|
|
@@ -0,0 +1,171 @@
|
|
|
+import { useState } from 'react'
|
|
|
+import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
+import { render } from 'vitest-browser-react'
|
|
|
+import { userEvent } from 'vitest/browser'
|
|
|
+import { showSubmittedData } from '@/lib/show-submitted-data'
|
|
|
+import { type Task } from '../data/schema'
|
|
|
+import { TasksMutateDrawer } from './tasks-mutate-drawer'
|
|
|
+
|
|
|
+vi.mock('@/lib/show-submitted-data', () => ({ showSubmittedData: vi.fn() }))
|
|
|
+
|
|
|
+const MOCK_TASK = {
|
|
|
+ id: 'task-1',
|
|
|
+ title: 'Existing task',
|
|
|
+ status: 'in progress',
|
|
|
+ label: 'feature',
|
|
|
+ priority: 'medium',
|
|
|
+} as const satisfies Task
|
|
|
+
|
|
|
+describe('TasksMutateDrawer', () => {
|
|
|
+ beforeEach(() => vi.clearAllMocks())
|
|
|
+
|
|
|
+ it('renders create title and description', async () => {
|
|
|
+ const { getByRole, getByText } = await render(
|
|
|
+ <TasksMutateDrawer open onOpenChange={vi.fn()} />
|
|
|
+ )
|
|
|
+
|
|
|
+ const title = getByRole('heading', {
|
|
|
+ level: 2,
|
|
|
+ name: /Create Task/i,
|
|
|
+ })
|
|
|
+ const desc = getByText(/Add a new task/i)
|
|
|
+
|
|
|
+ expect(title).toBeInTheDocument()
|
|
|
+ expect(desc).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('renders edit title, description, and prefilled title', async () => {
|
|
|
+ const { getByRole, getByText } = await render(
|
|
|
+ <TasksMutateDrawer open onOpenChange={vi.fn()} currentRow={MOCK_TASK} />
|
|
|
+ )
|
|
|
+
|
|
|
+ const title = getByRole('heading', {
|
|
|
+ level: 2,
|
|
|
+ name: /Update Task/i,
|
|
|
+ })
|
|
|
+ const desc = getByText(/Update the task/i)
|
|
|
+
|
|
|
+ const titleInput = getByRole('textbox', { name: /Title/i })
|
|
|
+ const statusSelect = getByRole('combobox', { name: /Status/i })
|
|
|
+ const labelRadio = getByRole('radio', { name: MOCK_TASK.label })
|
|
|
+ const priorityRadio = getByRole('radio', { name: MOCK_TASK.priority })
|
|
|
+
|
|
|
+ expect(title).toBeInTheDocument()
|
|
|
+ expect(desc).toBeInTheDocument()
|
|
|
+ expect(titleInput).toHaveValue(MOCK_TASK.title)
|
|
|
+ expect(statusSelect).toHaveTextContent(new RegExp(MOCK_TASK.status, 'i'))
|
|
|
+ expect(labelRadio).toBeChecked()
|
|
|
+ expect(priorityRadio).toBeChecked()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('shows validation messages when submitting an empty form', async () => {
|
|
|
+ const { getByRole, getByText } = await render(
|
|
|
+ <TasksMutateDrawer open onOpenChange={vi.fn()} />
|
|
|
+ )
|
|
|
+
|
|
|
+ const saveButton = getByRole('button', { name: /Save changes/i })
|
|
|
+ await userEvent.click(saveButton)
|
|
|
+
|
|
|
+ expect(getByText(/Title is required.$/i)).toBeInTheDocument()
|
|
|
+ expect(getByText(/Please select a status.$/i)).toBeInTheDocument()
|
|
|
+ expect(getByText(/Please select a label.$/i)).toBeInTheDocument()
|
|
|
+ expect(getByText(/Please choose a priority.$/i)).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('submits create form and shows submitted data', async () => {
|
|
|
+ const onOpenChange = vi.fn()
|
|
|
+ const { getByRole } = await render(
|
|
|
+ <TasksMutateDrawer open onOpenChange={onOpenChange} />
|
|
|
+ )
|
|
|
+
|
|
|
+ const titleInput = getByRole('textbox', { name: /Title/i })
|
|
|
+ await userEvent.fill(titleInput, 'New task title')
|
|
|
+
|
|
|
+ const statusSelect = getByRole('combobox', { name: /Status/i })
|
|
|
+ await userEvent.click(statusSelect)
|
|
|
+ await userEvent.click(getByRole('option', { name: /Todo/i }))
|
|
|
+
|
|
|
+ await userEvent.click(getByRole('radio', { name: /^Bug$/i }))
|
|
|
+ await userEvent.click(getByRole('radio', { name: /^Low$/i }))
|
|
|
+
|
|
|
+ const saveButton = getByRole('button', { name: /Save changes/i })
|
|
|
+ await userEvent.click(saveButton)
|
|
|
+
|
|
|
+ expect(onOpenChange).toHaveBeenCalledOnce()
|
|
|
+ expect(onOpenChange).toHaveBeenCalledWith(false)
|
|
|
+
|
|
|
+ expect(showSubmittedData).toHaveBeenCalledOnce()
|
|
|
+ expect(showSubmittedData).toHaveBeenCalledWith({
|
|
|
+ title: 'New task title',
|
|
|
+ status: 'todo',
|
|
|
+ label: 'bug',
|
|
|
+ priority: 'low',
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('closes when Close is clicked', async () => {
|
|
|
+ const onOpenChange = vi.fn()
|
|
|
+ const { getByRole } = await render(
|
|
|
+ <TasksMutateDrawer open onOpenChange={onOpenChange} />
|
|
|
+ )
|
|
|
+
|
|
|
+ const closeButtons = getByRole('dialog')
|
|
|
+ .getByRole('button', {
|
|
|
+ name: /Close/i,
|
|
|
+ })
|
|
|
+ .all()
|
|
|
+ expect(closeButtons).toHaveLength(2)
|
|
|
+ await userEvent.click(closeButtons[1])
|
|
|
+
|
|
|
+ expect(onOpenChange).toHaveBeenCalledOnce()
|
|
|
+ expect(onOpenChange).toHaveBeenCalledWith(false)
|
|
|
+ })
|
|
|
+
|
|
|
+ it('resets entered values when the sheet is closed and reopened', async () => {
|
|
|
+ function Harness() {
|
|
|
+ const [open, setOpen] = useState(true)
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <button type='button' onClick={() => setOpen(true)}>
|
|
|
+ Reopen
|
|
|
+ </button>
|
|
|
+ <TasksMutateDrawer open={open} onOpenChange={setOpen} />
|
|
|
+ </>
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ const { getByRole } = await render(<Harness />)
|
|
|
+
|
|
|
+ const titleInput = getByRole('textbox', { name: /Title/i })
|
|
|
+ await userEvent.fill(titleInput, 'Draft title')
|
|
|
+ expect(titleInput).toHaveValue('Draft title')
|
|
|
+
|
|
|
+ const statusSelect = getByRole('combobox', { name: /Status/i })
|
|
|
+ await userEvent.click(statusSelect)
|
|
|
+ await userEvent.click(getByRole('option', { name: /Todo/i }))
|
|
|
+ expect(statusSelect).toHaveTextContent(/Todo/i)
|
|
|
+
|
|
|
+ const labelRadio = getByRole('radio', { name: /^Documentation$/i })
|
|
|
+ await userEvent.click(labelRadio)
|
|
|
+ expect(labelRadio).toBeChecked()
|
|
|
+
|
|
|
+ const priorityRadio = getByRole('radio', { name: /^High$/i })
|
|
|
+ await userEvent.click(priorityRadio)
|
|
|
+ expect(priorityRadio).toBeChecked()
|
|
|
+
|
|
|
+ const closeButtons = getByRole('dialog')
|
|
|
+ .getByRole('button', {
|
|
|
+ name: /Close/i,
|
|
|
+ })
|
|
|
+ .all()
|
|
|
+ await userEvent.click(closeButtons[0])
|
|
|
+
|
|
|
+ const reopenButton = getByRole('button', { name: /Reopen/i })
|
|
|
+ await userEvent.click(reopenButton)
|
|
|
+
|
|
|
+ expect(titleInput).toHaveValue('')
|
|
|
+ expect(statusSelect).not.toHaveTextContent(/Todo/i)
|
|
|
+ expect(labelRadio).not.toBeChecked()
|
|
|
+ expect(priorityRadio).not.toBeChecked()
|
|
|
+ })
|
|
|
+})
|