Bladeren bron

test: add tests for confirm dialog

satnaing 2 maanden geleden
bovenliggende
commit
91231766fd
1 gewijzigde bestanden met toevoegingen van 202 en 0 verwijderingen
  1. 202 0
      src/components/confirm-dialog.test.tsx

+ 202 - 0
src/components/confirm-dialog.test.tsx

@@ -0,0 +1,202 @@
+import type { SubmitEvent } from 'react'
+import { describe, expect, it, vi } from 'vitest'
+import { render } from 'vitest-browser-react'
+import { userEvent } from 'vitest/browser'
+import { ConfirmDialog } from './confirm-dialog'
+
+describe('ConfirmDialog', () => {
+  it('renders title, description, and default buttons', async () => {
+    const { getByRole, getByText } = await render(
+      <ConfirmDialog
+        open
+        onOpenChange={vi.fn()}
+        title='Delete item'
+        desc='This action cannot be undone.'
+        handleConfirm={vi.fn()}
+      />
+    )
+
+    expect(getByRole('heading', { name: 'Delete item' })).toBeInTheDocument()
+    expect(getByText('This action cannot be undone.')).toBeInTheDocument()
+    expect(getByRole('button', { name: 'Cancel' })).toBeInTheDocument()
+    expect(getByRole('button', { name: 'Continue' })).toBeInTheDocument()
+  })
+
+  it('calls handleConfirm when the confirm button is clicked', async () => {
+    const handleConfirm = vi.fn()
+    const { getByRole } = await render(
+      <ConfirmDialog
+        open
+        onOpenChange={vi.fn()}
+        title='Sign out'
+        desc='Are you sure?'
+        confirmText='Sign out'
+        handleConfirm={handleConfirm}
+      />
+    )
+
+    await userEvent.click(getByRole('button', { name: 'Sign out' }))
+    expect(handleConfirm).toHaveBeenCalledOnce()
+  })
+
+  it('disables confirm when disabled is true', async () => {
+    const handleConfirm = vi.fn()
+    const { getByRole } = await render(
+      <ConfirmDialog
+        open
+        onOpenChange={vi.fn()}
+        title='Danger'
+        desc='...'
+        disabled
+        handleConfirm={handleConfirm}
+      />
+    )
+
+    const confirm = getByRole('button', { name: 'Continue' })
+    expect(confirm).toBeDisabled()
+    expect(handleConfirm).not.toHaveBeenCalled()
+  })
+
+  it('when isLoading is true, disables cancel and confirm', async () => {
+    const handleConfirm = vi.fn()
+    const { getByRole } = await render(
+      <ConfirmDialog
+        open
+        onOpenChange={vi.fn()}
+        title='Loading'
+        desc='...'
+        isLoading
+        handleConfirm={handleConfirm}
+      />
+    )
+
+    expect(getByRole('button', { name: 'Cancel' })).toBeDisabled()
+    expect(getByRole('button', { name: 'Continue' })).toBeDisabled()
+  })
+
+  it('supports custom button texts', async () => {
+    const { getByRole } = await render(
+      <ConfirmDialog
+        open
+        onOpenChange={vi.fn()}
+        title='Delete'
+        desc='...'
+        cancelBtnText='No'
+        confirmText='Yes'
+        handleConfirm={vi.fn()}
+      />
+    )
+
+    expect(getByRole('button', { name: 'No' })).toBeInTheDocument()
+    expect(getByRole('button', { name: 'Yes' })).toBeInTheDocument()
+  })
+
+  it('renders confirm as submit button linked to desc form when `form` is set', async () => {
+    const { getByRole } = await render(
+      <ConfirmDialog
+        open
+        onOpenChange={vi.fn()}
+        title='Delete tasks'
+        form='tasks-multi-delete-form'
+        desc={
+          <form id='tasks-multi-delete-form' className='space-y-4'>
+            <p>Type DELETE to confirm.</p>
+          </form>
+        }
+        confirmText='Delete'
+        destructive
+      />
+    )
+
+    const deleteBtn = getByRole('button', { name: 'Delete' })
+    expect(deleteBtn).toHaveAttribute('type', 'submit')
+    expect(deleteBtn).toHaveAttribute('form', 'tasks-multi-delete-form')
+  })
+
+  it('submits the desc form when confirm is clicked (form prop, no handleConfirm)', async () => {
+    const handleFormSubmit = vi.fn((e: SubmitEvent<HTMLFormElement>) => {
+      e.preventDefault()
+    })
+
+    const { getByRole } = await render(
+      <ConfirmDialog
+        open
+        onOpenChange={vi.fn()}
+        title='Delete'
+        form='users-delete-form'
+        desc={
+          <form
+            id='users-delete-form'
+            onSubmit={handleFormSubmit}
+            className='space-y-4'
+          >
+            <p>Confirm deletion.</p>
+          </form>
+        }
+        confirmText='Delete'
+        destructive
+      />
+    )
+
+    await userEvent.click(getByRole('button', { name: 'Delete' }))
+
+    expect(handleFormSubmit).toHaveBeenCalledOnce()
+  })
+
+  it('submits the form when Enter key is pressed', async () => {
+    const handleFormSubmit = vi.fn((e: SubmitEvent<HTMLFormElement>) => {
+      e.preventDefault()
+    })
+
+    const { getByPlaceholder } = await render(
+      <ConfirmDialog
+        open
+        onOpenChange={vi.fn()}
+        title='Delete'
+        form='users-delete-form'
+        desc={
+          <form
+            id='users-delete-form'
+            onSubmit={handleFormSubmit}
+            className='space-y-4'
+          >
+            <input type='text' name='username' placeholder='username' />
+          </form>
+        }
+        confirmText='Delete'
+        destructive
+      />
+    )
+
+    await userEvent.fill(getByPlaceholder('username'), 'test')
+    await userEvent.keyboard('{Enter}')
+    expect(handleFormSubmit).toHaveBeenCalledOnce()
+  })
+
+  it('does not submit the form when confirm is disabled (typed confirmation mismatch)', async () => {
+    const handleFormSubmit = vi.fn((e: SubmitEvent<HTMLFormElement>) => {
+      e.preventDefault()
+    })
+
+    const { getByRole } = await render(
+      <ConfirmDialog
+        open
+        onOpenChange={vi.fn()}
+        title='Delete'
+        form='users-delete-form'
+        disabled
+        desc={
+          <form id='users-delete-form' onSubmit={handleFormSubmit}>
+            <p>Enter username to enable Delete.</p>
+          </form>
+        }
+        confirmText='Delete'
+        destructive
+      />
+    )
+
+    const deleteBtn = getByRole('button', { name: 'Delete' })
+    expect(deleteBtn).toBeDisabled()
+    expect(handleFormSubmit).not.toHaveBeenCalled()
+  })
+})