test(notifications): voeg component-tests toe voor AnswerModal

Dekt: optieknoppen + textarea + Verstuur zichtbaar met opties,
submit via optieknop, submit via vrij tekstveld, disabled Verstuur
bij leeg veld, en demo-modus (textarea + Verstuur disabled).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scrum4Me Agent 2026-05-15 05:18:19 +02:00
parent a67ea73f2e
commit fa4b98f1f9

View file

@ -0,0 +1,104 @@
// @vitest-environment jsdom
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import React from 'react'
vi.mock('@/actions/questions', () => ({
answerQuestion: vi.fn(),
}))
vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }))
vi.mock('@/stores/notifications-store', () => ({
useNotificationsStore: {
getState: () => ({ remove: vi.fn() }),
},
}))
vi.mock('next/link', () => ({
default: ({ href, children }: { href: string; children: React.ReactNode }) => (
<a href={href}>{children}</a>
),
}))
import { AnswerModal } from '@/components/notifications/answer-modal'
import { answerQuestion } from '@/actions/questions'
import { toast } from 'sonner'
import type { NotificationQuestion } from '@/stores/notifications-store'
const mockAnswerQuestion = answerQuestion as ReturnType<typeof vi.fn>
const mockToast = toast as unknown as {
success: ReturnType<typeof vi.fn>
error: ReturnType<typeof vi.fn>
}
const QUESTION: NotificationQuestion = {
kind: 'idea',
id: 'q-1',
product_id: 'prod-1',
idea_id: 'idea-1',
idea_code: 'IDEA-42',
idea_title: 'Mijn Idee',
question: 'Wat denk jij?',
options: ['Optie A', 'Optie B'],
created_at: '2026-01-01T00:00:00Z',
expires_at: '2026-12-31T00:00:00Z',
}
beforeEach(() => {
vi.clearAllMocks()
})
describe('AnswerModal — met opties', () => {
it('toont optieknoppen, textarea en Verstuur-knop', () => {
render(<AnswerModal question={QUESTION} isDemo={false} onClose={vi.fn()} />)
expect(screen.getByRole('button', { name: 'Optie A' })).toBeTruthy()
expect(screen.getByRole('button', { name: 'Optie B' })).toBeTruthy()
expect(screen.getByLabelText(/Antwoord op Claude/)).toBeTruthy()
expect(screen.getByRole('button', { name: 'Verstuur' })).toBeTruthy()
})
it('roept answerQuestion aan met optiewaarde bij klik op optieknop', async () => {
mockAnswerQuestion.mockResolvedValue({ ok: true })
render(<AnswerModal question={QUESTION} isDemo={false} onClose={vi.fn()} />)
fireEvent.click(screen.getByRole('button', { name: 'Optie A' }))
await waitFor(() => {
expect(mockAnswerQuestion).toHaveBeenCalledWith('q-1', 'Optie A')
})
})
it('roept answerQuestion aan met getypte tekst bij klik op Verstuur', async () => {
mockAnswerQuestion.mockResolvedValue({ ok: true })
render(<AnswerModal question={QUESTION} isDemo={false} onClose={vi.fn()} />)
fireEvent.change(screen.getByLabelText(/Antwoord op Claude/), {
target: { value: 'Mijn eigen antwoord' },
})
fireEvent.click(screen.getByRole('button', { name: 'Verstuur' }))
await waitFor(() => {
expect(mockAnswerQuestion).toHaveBeenCalledWith('q-1', 'Mijn eigen antwoord')
})
})
it('Verstuur-knop is disabled zolang het tekstveld leeg is', () => {
render(<AnswerModal question={QUESTION} isDemo={false} onClose={vi.fn()} />)
expect(screen.getByRole('button', { name: 'Verstuur' })).toHaveProperty('disabled', true)
})
})
describe('AnswerModal — demo-modus', () => {
it('textarea is disabled en Verstuur is disabled bij isDemo=true', () => {
render(<AnswerModal question={QUESTION} isDemo={true} onClose={vi.fn()} />)
expect(screen.getByLabelText(/Antwoord op Claude/)).toHaveProperty('disabled', true)
expect(screen.getByRole('button', { name: 'Verstuur' })).toHaveProperty('disabled', true)
})
})
describe('AnswerModal — geen vraag', () => {
it('rendert niets wanneer question null is', () => {
const { container } = render(
<AnswerModal question={null} isDemo={false} onClose={vi.fn()} />,
)
expect(container.firstChild).toBeNull()
})
})