Phase 2: Build 9 presentational components with full test coverage
New components (all with .tsx + .test.tsx, 90%+ coverage): - CalendarDay: day cell with event badges - CalendarEvent: colored event chip with dismiss option - DaysBreakdown: table of days by type - ProgressChart: progress bar toward age-4 deadline - TipCard: optimization tip card with severity badges - VacationDaysInput: number input with min/max validation - ParentProfileInput: dual selects for salary type & employment status - PlanningGoalSelector: radio buttons for planning goal - BreakPeriodsInput: list manager with inline add/edit form All components follow existing patterns from Header/Footer: - Typed props interfaces (exported) - Semantic HTML with data-testid & ARIA attributes - No business logic, purely presentational - Comprehensive test coverage including edge cases npm test: 22 files, 167 tests passing npx tsc --noEmit: clean Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
import { render, fireEvent } from '@testing-library/react'
|
||||
import { CalendarDay } from './CalendarDay'
|
||||
|
||||
describe('CalendarDay', () => {
|
||||
it('renders day number', () => {
|
||||
const { getByTestId } = render(<CalendarDay date="2026-06-15" />)
|
||||
const day = getByTestId('calendar-day')
|
||||
expect(day).toBeInTheDocument()
|
||||
expect(day.textContent).toContain('15')
|
||||
})
|
||||
|
||||
it('renders as disabled when isCurrentMonth is false', () => {
|
||||
const { getByTestId } = render(
|
||||
<CalendarDay date="2026-06-15" isCurrentMonth={false} />
|
||||
)
|
||||
const day = getByTestId('calendar-day')
|
||||
expect(day).toHaveClass('calendar-day--disabled')
|
||||
})
|
||||
|
||||
it('renders events when provided', () => {
|
||||
const { getByTestId } = render(
|
||||
<CalendarDay
|
||||
date="2026-06-15"
|
||||
events={[
|
||||
{ type: 'vacation', color: '#FF5733', title: 'Vacation' },
|
||||
{ type: 'sick', color: '#FFD700', title: 'Sick leave' },
|
||||
]}
|
||||
/>
|
||||
)
|
||||
const events = getByTestId('calendar-day-events')
|
||||
expect(events).toBeInTheDocument()
|
||||
expect(events.children).toHaveLength(2)
|
||||
})
|
||||
|
||||
it('applies has-events class when events exist', () => {
|
||||
const { getByTestId } = render(
|
||||
<CalendarDay
|
||||
date="2026-06-15"
|
||||
events={[{ type: 'vacation', color: '#FF5733' }]}
|
||||
/>
|
||||
)
|
||||
const day = getByTestId('calendar-day')
|
||||
expect(day).toHaveClass('calendar-day--has-events')
|
||||
})
|
||||
|
||||
it('calls onClick when clicked', () => {
|
||||
const onClick = vi.fn()
|
||||
const { getByTestId } = render(
|
||||
<CalendarDay date="2026-06-15" onClick={onClick} />
|
||||
)
|
||||
const day = getByTestId('calendar-day')
|
||||
fireEvent.click(day)
|
||||
expect(onClick).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('calls onClick on Enter key', () => {
|
||||
const onClick = vi.fn()
|
||||
const { getByTestId } = render(
|
||||
<CalendarDay date="2026-06-15" onClick={onClick} />
|
||||
)
|
||||
const day = getByTestId('calendar-day')
|
||||
fireEvent.keyDown(day, { key: 'Enter' })
|
||||
expect(onClick).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('calls onClick on Space key', () => {
|
||||
const onClick = vi.fn()
|
||||
const { getByTestId } = render(
|
||||
<CalendarDay date="2026-06-15" onClick={onClick} />
|
||||
)
|
||||
const day = getByTestId('calendar-day')
|
||||
fireEvent.keyDown(day, { key: ' ' })
|
||||
expect(onClick).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('provides accessibility label with event count', () => {
|
||||
const { getByTestId } = render(
|
||||
<CalendarDay
|
||||
date="2026-06-15"
|
||||
events={[
|
||||
{ type: 'vacation', color: '#FF5733' },
|
||||
{ type: 'sick', color: '#FFD700' },
|
||||
]}
|
||||
/>
|
||||
)
|
||||
const day = getByTestId('calendar-day')
|
||||
expect(day).toHaveAttribute('aria-label', '2026-06-15 with 2 event(s)')
|
||||
})
|
||||
|
||||
it('renders without events by default', () => {
|
||||
const { queryByTestId } = render(<CalendarDay date="2026-06-15" />)
|
||||
const events = queryByTestId('calendar-day-events')
|
||||
expect(events).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user