|
|
@@ -0,0 +1,171 @@
|
|
|
+import { useState } from 'react'
|
|
|
+import { type Table } from '@tanstack/react-table'
|
|
|
+import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
+import { render } from 'vitest-browser-react'
|
|
|
+import { userEvent } from 'vitest/browser'
|
|
|
+import { UsersMultiDeleteDialog } from './users-multi-delete-dialog'
|
|
|
+
|
|
|
+vi.mock('@/lib/utils', async (orig) => ({
|
|
|
+ ...(await orig()),
|
|
|
+ sleep: vi.fn(() => Promise.resolve()),
|
|
|
+}))
|
|
|
+
|
|
|
+function createTableMock(rowCount = 2) {
|
|
|
+ const rows = Array.from({ length: rowCount }, () => ({}))
|
|
|
+ const resetRowSelection = vi.fn()
|
|
|
+ const table = {
|
|
|
+ getFilteredSelectedRowModel: () => ({ rows }),
|
|
|
+ resetRowSelection,
|
|
|
+ } as unknown as Table<Record<string, unknown>>
|
|
|
+ return { table, resetRowSelection }
|
|
|
+}
|
|
|
+
|
|
|
+describe('UsersMultiDeleteDialog', () => {
|
|
|
+ beforeEach(() => vi.clearAllMocks())
|
|
|
+
|
|
|
+ it('renders the dialog with the correct title, description, input and buttons', async () => {
|
|
|
+ const { table } = createTableMock()
|
|
|
+
|
|
|
+ const { getByRole, getByText } = await render(
|
|
|
+ <UsersMultiDeleteDialog open onOpenChange={vi.fn()} table={table} />
|
|
|
+ )
|
|
|
+
|
|
|
+ const title = getByRole('heading', {
|
|
|
+ level: 2,
|
|
|
+ name: /Delete 2 users/i,
|
|
|
+ })
|
|
|
+ const desc = getByText(
|
|
|
+ new RegExp(`Are you sure you want to delete the selected users?`, 'i')
|
|
|
+ )
|
|
|
+ const confirmDeleteInput = getByRole('textbox', {
|
|
|
+ name: /Confirm by typing "DELETE"/i,
|
|
|
+ })
|
|
|
+ const deleteButton = getByRole('button', { name: /Delete/i })
|
|
|
+
|
|
|
+ expect(title).toBeInTheDocument()
|
|
|
+ expect(desc).toBeInTheDocument()
|
|
|
+ expect(confirmDeleteInput).toBeInTheDocument()
|
|
|
+ expect(deleteButton).toBeInTheDocument()
|
|
|
+ expect(deleteButton).toBeDisabled()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('keeps the delete button disabled until the confirm delete input is filled correctly', async () => {
|
|
|
+ const { table } = createTableMock()
|
|
|
+ const { getByRole } = await render(
|
|
|
+ <UsersMultiDeleteDialog open onOpenChange={vi.fn()} table={table} />
|
|
|
+ )
|
|
|
+
|
|
|
+ const confirmDeleteInput = getByRole('textbox', {
|
|
|
+ name: /Confirm by typing "DELETE"/i,
|
|
|
+ })
|
|
|
+ const deleteButton = getByRole('button', { name: /Delete/i })
|
|
|
+
|
|
|
+ expect(deleteButton).toBeDisabled()
|
|
|
+
|
|
|
+ await userEvent.fill(confirmDeleteInput, 'wrong-input')
|
|
|
+ expect(deleteButton).toBeDisabled()
|
|
|
+
|
|
|
+ await userEvent.fill(confirmDeleteInput, 'DELETE')
|
|
|
+ expect(deleteButton).toBeEnabled()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('closes the dialog when the cancel button is clicked', async () => {
|
|
|
+ const { table } = createTableMock()
|
|
|
+ const onOpenChange = vi.fn()
|
|
|
+ const { getByRole } = await render(
|
|
|
+ <UsersMultiDeleteDialog open onOpenChange={onOpenChange} table={table} />
|
|
|
+ )
|
|
|
+
|
|
|
+ const cancelButton = getByRole('button', { name: /Cancel/i })
|
|
|
+ await userEvent.click(cancelButton)
|
|
|
+
|
|
|
+ expect(onOpenChange).toHaveBeenCalledOnce()
|
|
|
+ expect(onOpenChange).toHaveBeenCalledWith(false)
|
|
|
+ })
|
|
|
+
|
|
|
+ it('resets the confirm delete input when the dialog is closed and reopened', async () => {
|
|
|
+ const { table } = createTableMock()
|
|
|
+
|
|
|
+ function Harness() {
|
|
|
+ const [open, setOpen] = useState(true)
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <button type='button' onClick={() => setOpen(true)}>
|
|
|
+ Reopen
|
|
|
+ </button>
|
|
|
+ {open ? (
|
|
|
+ <UsersMultiDeleteDialog
|
|
|
+ open={open}
|
|
|
+ onOpenChange={setOpen}
|
|
|
+ table={table}
|
|
|
+ />
|
|
|
+ ) : null}
|
|
|
+ </>
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ const { getByRole } = await render(<Harness />)
|
|
|
+
|
|
|
+ const confirmDeleteInput = getByRole('textbox', {
|
|
|
+ name: /Confirm by typing "DELETE"/i,
|
|
|
+ })
|
|
|
+ await userEvent.fill(confirmDeleteInput, 'DELETE')
|
|
|
+ expect(confirmDeleteInput).toHaveValue('DELETE')
|
|
|
+
|
|
|
+ const cancelButton = getByRole('button', { name: /Cancel/i })
|
|
|
+ await userEvent.click(cancelButton)
|
|
|
+
|
|
|
+ const reopenButton = getByRole('button', { name: /Reopen/i })
|
|
|
+ await userEvent.click(reopenButton)
|
|
|
+ expect(confirmDeleteInput).toHaveValue('')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('shows the submitted data when deleted successfully', async () => {
|
|
|
+ const { table, resetRowSelection } = createTableMock()
|
|
|
+ const onOpenChange = vi.fn()
|
|
|
+ const { getByRole } = await render(
|
|
|
+ <UsersMultiDeleteDialog open onOpenChange={onOpenChange} table={table} />
|
|
|
+ )
|
|
|
+
|
|
|
+ const confirmDeleteInput = getByRole('textbox', {
|
|
|
+ name: /Confirm by typing "DELETE"/i,
|
|
|
+ })
|
|
|
+ const deleteButton = getByRole('button', { name: /Delete/i })
|
|
|
+
|
|
|
+ expect(deleteButton).toBeDisabled()
|
|
|
+
|
|
|
+ await userEvent.fill(confirmDeleteInput, 'DELETE')
|
|
|
+ expect(deleteButton).toBeEnabled()
|
|
|
+
|
|
|
+ await userEvent.click(deleteButton)
|
|
|
+
|
|
|
+ expect(onOpenChange).toHaveBeenCalledOnce()
|
|
|
+ expect(onOpenChange).toHaveBeenCalledWith(false)
|
|
|
+
|
|
|
+ await vi.waitFor(() => expect(resetRowSelection).toHaveBeenCalledOnce())
|
|
|
+ })
|
|
|
+
|
|
|
+ it('deletes successfully when press Enter key on the confirm delete input', async () => {
|
|
|
+ const { table, resetRowSelection } = createTableMock()
|
|
|
+ const onOpenChange = vi.fn()
|
|
|
+ const { getByRole } = await render(
|
|
|
+ <UsersMultiDeleteDialog open onOpenChange={onOpenChange} table={table} />
|
|
|
+ )
|
|
|
+
|
|
|
+ const confirmDeleteInput = getByRole('textbox', {
|
|
|
+ name: /Confirm by typing "DELETE"/i,
|
|
|
+ })
|
|
|
+ const deleteButton = getByRole('button', { name: /Delete/i })
|
|
|
+
|
|
|
+ expect(deleteButton).toBeDisabled()
|
|
|
+
|
|
|
+ await userEvent.fill(confirmDeleteInput, 'DELETE')
|
|
|
+ expect(deleteButton).toBeEnabled()
|
|
|
+
|
|
|
+ await userEvent.keyboard('{Enter}')
|
|
|
+ expect(onOpenChange).toHaveBeenCalledOnce()
|
|
|
+ expect(onOpenChange).toHaveBeenCalledWith(false)
|
|
|
+
|
|
|
+ await vi.waitFor(() => expect(resetRowSelection).toHaveBeenCalledOnce())
|
|
|
+ })
|
|
|
+})
|