Spaces:
Sleeping
Sleeping
File size: 6,608 Bytes
cd99321 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | import { afterEach, describe, expect, it, vi } from 'vitest'
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { render } from '../../../tests/helpers/render'
import { resetAllStores } from '../../../tests/helpers/store'
import VacayMonthCard from './VacayMonthCard'
const baseProps = {
year: 2025,
month: 0, // January 2025
holidays: {},
companyHolidaySet: new Set<string>(),
companyHolidaysEnabled: true,
entryMap: {},
onCellClick: vi.fn(),
companyMode: false,
blockWeekends: true,
weekendDays: [0, 6],
}
afterEach(() => {
resetAllStores()
vi.clearAllMocks()
})
describe('VacayMonthCard', () => {
it('FE-COMP-VACAYMONTHCARD-001: Renders the month name', () => {
render(<VacayMonthCard {...baseProps} />)
// January in en-US locale via Intl.DateTimeFormat
expect(screen.getByText(/january/i)).toBeInTheDocument()
})
it('FE-COMP-VACAYMONTHCARD-002: Renders correct number of day cells for January 2025', () => {
render(<VacayMonthCard {...baseProps} />)
// January 2025 has 31 days
for (let d = 1; d <= 31; d++) {
expect(screen.getByText(String(d))).toBeInTheDocument()
}
})
it('FE-COMP-VACAYMONTHCARD-003: Calls onCellClick with the correct ISO date string', async () => {
const user = userEvent.setup()
render(<VacayMonthCard {...baseProps} />)
// January 15, 2025 is a Wednesday (not blocked)
await user.click(screen.getByText('15'))
expect(baseProps.onCellClick).toHaveBeenCalledWith('2025-01-15')
})
it('FE-COMP-VACAYMONTHCARD-004: Holiday cell has tooltip with localName', () => {
const props = {
...baseProps,
holidays: { '2025-01-01': { name: 'Neujahr', localName: 'Neujahr', label: null, color: '#ef4444' } },
}
render(<VacayMonthCard {...props} />)
// Jan 1 is a Wednesday — there may be multiple "1" text nodes, find the one with a title
const cell = screen.getByTitle('Neujahr')
expect(cell).toBeInTheDocument()
})
it('FE-COMP-VACAYMONTHCARD-005: Holiday cell with label shows combined tooltip', () => {
const props = {
...baseProps,
holidays: { '2025-01-01': { name: 'New Year', localName: 'New Year', label: 'DE', color: '#ef4444' } },
}
render(<VacayMonthCard {...props} />)
const cell = screen.getByTitle('DE: New Year')
expect(cell).toBeInTheDocument()
})
it('FE-COMP-VACAYMONTHCARD-006: Weekend cell has default cursor (blocked)', () => {
render(<VacayMonthCard {...baseProps} />)
// January 5, 2025 is a Sunday (getDay() === 0), which is in weekendDays [0, 6]
// isBlocked = weekend && blockWeekends = true
const daySpan = screen.getByText('5')
const cell = daySpan.closest('div') as HTMLElement
expect(cell.style.cursor).toBe('default')
})
it('FE-COMP-VACAYMONTHCARD-007: Company holiday overlay renders', () => {
const props = {
...baseProps,
companyHolidaySet: new Set(['2025-01-10']),
companyHolidaysEnabled: true,
}
render(<VacayMonthCard {...props} />)
// January 10, 2025 is a Friday (not a weekend)
const daySpan = screen.getByText('10')
const cell = daySpan.closest('div') as HTMLElement
// Company overlay is a direct child div with amber background
const overlayDivs = Array.from(cell.querySelectorAll(':scope > div')) as HTMLElement[]
const companyOverlay = overlayDivs.find(el => el.className.includes('bg-[rgba(245,158,11'))
expect(companyOverlay).toBeTruthy()
})
it('FE-COMP-VACAYMONTHCARD-008: Single vacation entry renders colored overlay', () => {
const props = {
...baseProps,
entryMap: { '2025-01-15': [{ date: '2025-01-15', user_id: 1, person_color: '#6366f1' }] },
}
render(<VacayMonthCard {...props} />)
const daySpan = screen.getByText('15')
const cell = daySpan.closest('div') as HTMLElement
// The overlay div should have opacity: 0.4 and a backgroundColor set
const overlayDivs = Array.from(cell.querySelectorAll(':scope > div')) as HTMLElement[]
const colorOverlay = overlayDivs.find(
el => el.style.opacity === '0.4' && el.style.backgroundColor !== '',
)
expect(colorOverlay).toBeTruthy()
})
it('FE-COMP-VACAYMONTHCARD-009: Day number font-weight is bold when entries exist', () => {
const props = {
...baseProps,
entryMap: { '2025-01-20': [{ date: '2025-01-15', user_id: 1, person_color: '#6366f1' }] },
}
render(<VacayMonthCard {...props} />)
const daySpan = screen.getByText('20')
expect(daySpan.style.fontWeight).toBe('700')
})
it('FE-COMP-VACAYMONTHCARD-010: Renders 7 weekday header labels', () => {
render(<VacayMonthCard {...baseProps} />)
// Weekday labels from translations: Mon, Tue, Wed, Thu, Fri, Sat, Sun
const weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
for (const wd of weekdays) {
expect(screen.getByText(wd)).toBeInTheDocument()
}
})
it('FE-COMP-VACAYMONTHCARD-011: Two vacation entries render gradient overlay', () => {
const props = {
...baseProps,
entryMap: {
'2025-01-15': [{ date: '2025-01-15', user_id: 1, person_color: '#6366f1' }, { date: '2025-01-15', user_id: 1, person_color: '#f43f5e' }],
},
}
render(<VacayMonthCard {...props} />)
const daySpan = screen.getByText('15')
const cell = daySpan.closest('div') as HTMLElement
const overlayDivs = Array.from(cell.querySelectorAll(':scope > div')) as HTMLElement[]
const gradientOverlay = overlayDivs.find(
el => el.style.opacity === '0.4' && el.style.background.includes('linear-gradient'),
)
expect(gradientOverlay).toBeTruthy()
})
it('FE-COMP-VACAYMONTHCARD-012: Four vacation entries render quadrant overlay', () => {
const props = {
...baseProps,
entryMap: {
'2025-01-15': [
{ date: '2025-01-15', user_id: 1, person_color: '#6366f1' },
{ date: '2025-01-15', user_id: 1, person_color: '#f43f5e' },
{ date: '2025-01-15', user_id: 1, person_color: '#22c55e' },
{ date: '2025-01-15', user_id: 1, person_color: '#f59e0b' },
],
},
}
render(<VacayMonthCard {...props} />)
const daySpan = screen.getByText('15')
const cell = daySpan.closest('div') as HTMLElement
// Quadrant overlay wrapper div (4 entries) has 4 sub-divs
const wrapperDiv = cell.querySelector(':scope > div') as HTMLElement
expect(wrapperDiv).toBeTruthy()
const quadrants = wrapperDiv.querySelectorAll(':scope > div')
expect(quadrants).toHaveLength(4)
})
})
|