Remove every as any from the test suite and enforce it

ESLint turned `no-explicit-any` off for test files, and 219 casts had
accumulated across 12 of them. Two shapes, very different risks: most
were `(useWorkspace as any).mockReturnValue(...)`, mere laziness that
`vi.mocked()` does properly; the rest cast partial fixtures onto API
types, which erases the contract exactly where a test should enforce it.

That second kind matters here specifically. This project's recurring bug
is a field silently dropped between backend and frontend -- the
hand-written mapping in models/plan.py has done it twice, and apiFetch
mishandling structured errors was the same shape. A test that casts an
incomplete fixture to `any` keeps passing through precisely that change.

A typed fixture layer already existed at tests/fixtures/mockData.ts and
was imported by exactly zero tests: the right tool was there and
invisible, so everyone reached for a cast. It is now a set of
`make*(overrides: Partial<T>) => T` factories returning complete, valid
objects, split by domain with a barrel. When a type gains a field, one
factory fails to compile instead of thirty tests silently passing.

With the count at zero the ESLint exemption is deleted, so this cannot
regrow. Removing it immediately caught two `}: any` prop stubs that a
grep for "as any" had missed; those mocks now use the real components'
exported prop types.

`as unknown as T` survives in five places, each a test deliberately
feeding invalid input (an undefined breakdown, missing tierData, a bogus
leave type). CLAUDE.md now documents that as the only accepted escape,
and points at the factories.

interface PollResponse in useScraperFetch.ts is exported so its shape can
be derived rather than duplicated -- pollScraperSession declares
Promise<unknown>, so there was no other honest way to type it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RXMhc9nT6sNz1SL4j8dznL
This commit is contained in:
2026-09-15 04:17:22 +02:00
parent da7ac84aca
commit fe120ee222
24 changed files with 1905 additions and 1137 deletions
+258 -285
View File
@@ -4,6 +4,14 @@ import { Calendar } from './Calendar'
import { useWorkspace } from '@/context'
import { usePlannedDays, useCalendarDays, useDayOverrides, useShowWeekNumbers, getLastLeaveType } from '@/hooks'
import { LanguageProvider } from '@/i18n'
import {
makeWorkspaceContextValue,
makePlannedDaysResult,
makeCalendarDaysResult,
makeDayOverridesResult,
makeShowWeekNumbersTuple,
} from '../../tests/fixtures'
import { makeCalendarDayEntry, makeCalendarWindow } from '../../tests/fixtures/calendar'
vi.mock('@/context', () => ({
useWorkspace: vi.fn(),
@@ -43,52 +51,33 @@ describe('Calendar', () => {
vi.clearAllMocks()
})
const mockWorkspace = {
isLoading: false,
const mockWorkspace = makeWorkspaceContextValue({
selectedChildId: 'child-1',
workspace: { id: 'ws-1' },
personalDataUuid: 'person-1',
}
})
const mockPlannedDays = {
data: [],
isLoading: false,
add: vi.fn(),
update: vi.fn(),
remove: vi.fn(),
}
const mockPlannedDays = makePlannedDaysResult()
const mockCalendarWindow = {
data: { startYear: 2026, endYear: 2026, minYear: 2026, maxYear: 2035, days: [] },
isLoading: false,
error: null,
refetch: vi.fn(),
}
const mockCalendarWindow = makeCalendarDaysResult()
const mockDayOverrides = {
data: [],
isLoading: false,
error: null,
upsert: vi.fn(),
remove: vi.fn(),
}
const mockDayOverrides = makeDayOverridesResult()
beforeEach(() => {
;(useCalendarDays as any).mockReturnValue(mockCalendarWindow)
;(useDayOverrides as any).mockReturnValue(mockDayOverrides)
vi.mocked(useCalendarDays).mockReturnValue(mockCalendarWindow)
vi.mocked(useDayOverrides).mockReturnValue(mockDayOverrides)
})
it('renders loading state while data is loading', () => {
;(useWorkspace as any).mockReturnValue({ ...mockWorkspace, isLoading: true })
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue({ ...mockWorkspace, isLoading: true })
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
expect(screen.getByText('Loading...')).toBeInTheDocument()
})
it('renders 7 weekday headers in Monday-first Swedish order', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
const weekdays = screen.getAllByText(/^(Mån|Tis|Ons|Tor|Fre|Lör|Sön)$/)
@@ -101,8 +90,8 @@ describe('Calendar', () => {
})
it('renders day cells for all weeks in a month', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -112,8 +101,8 @@ describe('Calendar', () => {
})
it('marks Sunday-starting month (March 2026) correctly with 7-column grid', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
const { rerender } = render(<Calendar />)
expect(screen.getByTestId('calendar')).toBeInTheDocument()
@@ -124,8 +113,8 @@ describe('Calendar', () => {
})
it('opens modal when clicking a current-month day', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -139,8 +128,8 @@ describe('Calendar', () => {
})
it('does not open modal when clicking disabled (non-current-month) day', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -154,8 +143,8 @@ describe('Calendar', () => {
})
it('displays current month title', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -164,8 +153,8 @@ describe('Calendar', () => {
})
it('handles next/prev month navigation', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -179,8 +168,8 @@ describe('Calendar', () => {
})
it('highlights date range live while dragging, before pointerup', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -207,8 +196,8 @@ describe('Calendar', () => {
})
it('jumps forward to any month via month dropdown', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -225,8 +214,8 @@ describe('Calendar', () => {
})
it('jumps backward to any month via month dropdown', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -242,8 +231,8 @@ describe('Calendar', () => {
})
it('jumps forward to any year via year dropdown', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -259,8 +248,8 @@ describe('Calendar', () => {
})
it('jumps backward to any year via year dropdown', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -276,8 +265,8 @@ describe('Calendar', () => {
})
it('year dropdown includes all supported years from 2026 to 2055', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -293,8 +282,8 @@ describe('Calendar', () => {
})
it('month and year selects have proper accessibility labels', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -318,29 +307,24 @@ describe('Calendar', () => {
describe('§3.4 red day / klämdag shading', () => {
it('shades a statutory red day and shows its name', () => {
const today = todayDateString()
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
;(useCalendarDays as any).mockReturnValue({
data: {
startYear: 2026,
endYear: 2026,
minYear: 2026,
maxYear: 2035,
days: [
{
date: today,
name: 'Påskdagen; Söndag',
dayType: 'red_day',
isOverride: false,
overrideIsWorkingDay: null,
isFree: true,
},
],
},
isLoading: false,
error: null,
refetch: vi.fn(),
})
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
vi.mocked(useCalendarDays).mockReturnValue(
makeCalendarDaysResult({
data: makeCalendarWindow({
days: [
makeCalendarDayEntry({
date: today,
name: 'Påskdagen; Söndag',
dayType: 'red_day',
isOverride: false,
overrideIsWorkingDay: null,
isFree: true,
}),
],
}),
})
)
render(<Calendar />)
@@ -353,29 +337,24 @@ describe('Calendar', () => {
it('marks an overridden day distinctly from a plain statutory day', () => {
const today = todayDateString()
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
;(useCalendarDays as any).mockReturnValue({
data: {
startYear: 2026,
endYear: 2026,
minYear: 2026,
maxYear: 2035,
days: [
{
date: today,
name: null,
dayType: 'working_day',
isOverride: true,
overrideIsWorkingDay: false,
isFree: true,
},
],
},
isLoading: false,
error: null,
refetch: vi.fn(),
})
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
vi.mocked(useCalendarDays).mockReturnValue(
makeCalendarDaysResult({
data: makeCalendarWindow({
days: [
makeCalendarDayEntry({
date: today,
name: null,
dayType: 'working_day',
isOverride: true,
overrideIsWorkingDay: false,
isFree: true,
}),
],
}),
})
)
render(<Calendar />)
@@ -387,8 +366,8 @@ describe('Calendar', () => {
describe('§3.6 click-to-override', () => {
it('shows an override-mode toggle button', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -396,8 +375,8 @@ describe('Calendar', () => {
})
it('clicking a day while override mode is active does not open the planning modal', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -412,8 +391,8 @@ describe('Calendar', () => {
})
it('toggling override mode off restores normal click-to-plan behaviour', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -432,30 +411,28 @@ describe('Calendar', () => {
const today = todayDateString()
const upsert = vi.fn().mockResolvedValue(undefined)
const refetchCalendarWindow = vi.fn().mockResolvedValue(undefined)
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
;(useCalendarDays as any).mockReturnValue({
data: {
startYear: 2026,
endYear: 2026,
minYear: 2026,
maxYear: 2035,
days: [
{
date: today,
name: null,
dayType: 'weekend',
isOverride: false,
overrideIsWorkingDay: null,
isFree: true,
},
],
},
isLoading: false,
error: null,
refetch: refetchCalendarWindow,
})
;(useDayOverrides as any).mockReturnValue({ data: [], isLoading: false, error: null, upsert, remove: vi.fn() })
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
vi.mocked(useCalendarDays).mockReturnValue(
makeCalendarDaysResult({
data: makeCalendarWindow({
days: [
makeCalendarDayEntry({
date: today,
name: null,
dayType: 'weekend',
isOverride: false,
overrideIsWorkingDay: null,
isFree: true,
}),
],
}),
refetch: refetchCalendarWindow,
})
)
vi.mocked(useDayOverrides).mockReturnValue(
makeDayOverridesResult({ data: [], upsert, remove: vi.fn() })
)
render(<Calendar />)
fireEvent.click(screen.getByTestId('calendar-override-toggle'))
@@ -483,36 +460,32 @@ describe('Calendar', () => {
const today = todayDateString()
const removeOverride = vi.fn().mockResolvedValue(undefined)
const refetchCalendarWindow = vi.fn().mockResolvedValue(undefined)
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
;(useCalendarDays as any).mockReturnValue({
data: {
startYear: 2026,
endYear: 2026,
minYear: 2026,
maxYear: 2035,
days: [
{
date: today,
name: null,
dayType: 'working_day',
isOverride: true,
overrideIsWorkingDay: false,
isFree: true,
},
],
},
isLoading: false,
error: null,
refetch: refetchCalendarWindow,
})
;(useDayOverrides as any).mockReturnValue({
data: [{ id: 'ov-1', workspaceId: 'ws-1', date: today, isWorkingDay: false, note: null }],
isLoading: false,
error: null,
upsert: vi.fn(),
remove: removeOverride,
})
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
vi.mocked(useCalendarDays).mockReturnValue(
makeCalendarDaysResult({
data: makeCalendarWindow({
days: [
makeCalendarDayEntry({
date: today,
name: null,
dayType: 'working_day',
isOverride: true,
overrideIsWorkingDay: false,
isFree: true,
}),
],
}),
refetch: refetchCalendarWindow,
})
)
vi.mocked(useDayOverrides).mockReturnValue(
makeDayOverridesResult({
data: [{ id: 'ov-1', workspaceId: 'ws-1', date: today, isWorkingDay: false, note: null, createdAt: '2026-01-01', updatedAt: '2026-01-01' }],
upsert: vi.fn(),
remove: removeOverride,
})
)
render(<Calendar />)
fireEvent.click(screen.getByTestId('calendar-override-toggle'))
@@ -530,12 +503,18 @@ describe('Calendar', () => {
describe('defensive fallbacks and additional branches', () => {
it('falls back to safe defaults when workspace/child/personalData are unavailable', () => {
const noWorkspace = { isLoading: false, selectedChildId: null, workspace: null, personalDataUuid: null }
;(useWorkspace as any).mockReturnValue(noWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
const noWorkspace = makeWorkspaceContextValue({
selectedChildId: null,
workspace: null,
personalDataUuid: null,
})
vi.mocked(useWorkspace).mockReturnValue(noWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
const upsert = vi.fn()
const removeOverride = vi.fn()
;(useDayOverrides as any).mockReturnValue({ data: [], isLoading: false, error: null, upsert, remove: removeOverride })
vi.mocked(useDayOverrides).mockReturnValue(
makeDayOverridesResult({ data: [], upsert: vi.fn(), remove: removeOverride })
)
render(<Calendar />)
@@ -557,14 +536,14 @@ describe('Calendar', () => {
})
it('treats a missing calendar window as having no days yet', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
;(useCalendarDays as any).mockReturnValue({
data: undefined,
isLoading: true,
error: null,
refetch: vi.fn(),
})
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
vi.mocked(useCalendarDays).mockReturnValue(
makeCalendarDaysResult({
data: null,
isLoading: true,
})
)
render(<Calendar />)
@@ -574,8 +553,8 @@ describe('Calendar', () => {
})
it('treats missing planned days as an empty list for lookups and bar rendering', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue({ ...mockPlannedDays, data: undefined })
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue({ ...mockPlannedDays, data: null })
render(<Calendar />)
@@ -589,8 +568,8 @@ describe('Calendar', () => {
})
it('renders the month/year header in English when the locale is English', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
Object.defineProperty(window.navigator, 'language', { value: 'en-US', configurable: true })
vi.stubGlobal('localStorage', {
@@ -616,9 +595,9 @@ describe('Calendar', () => {
})
it('shows the week-number column when the preference is enabled', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
;(useShowWeekNumbers as any).mockReturnValueOnce([true])
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
vi.mocked(useShowWeekNumbers).mockReturnValueOnce(makeShowWeekNumbersTuple(true))
render(<Calendar />)
@@ -627,9 +606,9 @@ describe('Calendar', () => {
})
it('defaults the new-day modal to "vacation" when there is no last-used leave type', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
;(getLastLeaveType as any).mockReturnValueOnce(null)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
vi.mocked(getLastLeaveType).mockReturnValueOnce(null)
render(<Calendar />)
@@ -641,8 +620,8 @@ describe('Calendar', () => {
})
it('ignores pointer-drag gestures entirely while override mode is active', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -666,39 +645,38 @@ describe('Calendar', () => {
const today = todayDateString()
const removeOverride = vi.fn()
const refetchCalendarWindow = vi.fn().mockResolvedValue(undefined)
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
;(useCalendarDays as any).mockReturnValue({
data: {
startYear: 2026,
endYear: 2026,
minYear: 2026,
maxYear: 2035,
days: [
{
date: today,
name: null,
dayType: 'working_day',
isOverride: true,
overrideIsWorkingDay: false,
isFree: true,
},
],
},
isLoading: false,
error: null,
refetch: refetchCalendarWindow,
})
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
vi.mocked(useCalendarDays).mockReturnValue(
makeCalendarDaysResult({
data: makeCalendarWindow({
days: [
makeCalendarDayEntry({
date: today,
name: null,
dayType: 'working_day',
isOverride: true,
overrideIsWorkingDay: false,
isFree: true,
}),
],
}),
refetch: refetchCalendarWindow,
})
)
// data is undefined here (e.g. before the overrides fetch resolves) —
// the (dayOverrides ?? []).find(...) fallback must kick in rather than
// throwing, and since nothing is found there is nothing to remove.
;(useDayOverrides as any).mockReturnValue({
data: undefined,
isLoading: true,
error: null,
upsert: vi.fn(),
remove: removeOverride,
})
vi.mocked(useDayOverrides).mockReturnValue(
{
...makeDayOverridesResult({
isLoading: true,
upsert: vi.fn(),
remove: removeOverride,
}),
data: undefined,
} as unknown as ReturnType<typeof useDayOverrides>
)
render(<Calendar />)
fireEvent.click(screen.getByTestId('calendar-override-toggle'))
@@ -715,30 +693,27 @@ describe('Calendar', () => {
it('shows the Error message directly when the override mutation rejects with an Error', async () => {
const today = todayDateString()
const upsert = vi.fn().mockRejectedValue(new Error('quota exceeded'))
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
;(useCalendarDays as any).mockReturnValue({
data: {
startYear: 2026,
endYear: 2026,
minYear: 2026,
maxYear: 2035,
days: [
{
date: today,
name: null,
dayType: 'weekend',
isOverride: false,
overrideIsWorkingDay: null,
isFree: true,
},
],
},
isLoading: false,
error: null,
refetch: vi.fn(),
})
;(useDayOverrides as any).mockReturnValue({ data: [], isLoading: false, error: null, upsert, remove: vi.fn() })
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
vi.mocked(useCalendarDays).mockReturnValue(
makeCalendarDaysResult({
data: makeCalendarWindow({
days: [
makeCalendarDayEntry({
date: today,
name: null,
dayType: 'weekend',
isOverride: false,
overrideIsWorkingDay: null,
isFree: true,
}),
],
}),
})
)
vi.mocked(useDayOverrides).mockReturnValue(
makeDayOverridesResult({ data: [], upsert, remove: vi.fn() })
)
render(<Calendar />)
fireEvent.click(screen.getByTestId('calendar-override-toggle'))
@@ -754,8 +729,8 @@ describe('Calendar', () => {
it('passes an empty personalDataUuid through to the planning modal when it is unavailable', () => {
const noPersonalData = { ...mockWorkspace, personalDataUuid: null }
;(useWorkspace as any).mockReturnValue(noPersonalData)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(noPersonalData)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -769,29 +744,30 @@ describe('Calendar', () => {
})
it('lets the modal offer deletion when the clicked date already has a planned day', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
render(<Calendar />)
const calendarDays = screen.getAllByTestId('calendar-day')
const currentMonthDay = calendarDays.find((el) => !el.classList.contains('calendar-day--disabled'))
const clickedDate = currentMonthDay!.getAttribute('aria-label')!
;(usePlannedDays as any).mockReturnValue({
...mockPlannedDays,
data: [
{
id: 'pd-1',
workspaceId: 'ws-1',
childId: 'child-1',
parentPersonalDataUuid: 'person-1',
date: clickedDate,
dayType: 'vacation',
isDubbeldag: false,
createdAt: '2026-01-01',
updatedAt: '2026-01-01',
},
],
})
vi.mocked(usePlannedDays).mockReturnValue(
makePlannedDaysResult({
data: [
{
id: 'pd-1',
workspaceId: 'ws-1',
childId: 'child-1',
parentPersonalDataUuid: 'person-1',
date: clickedDate,
dayType: 'vacation',
isDubbeldag: false,
createdAt: '2026-01-01',
updatedAt: '2026-01-01',
},
],
})
)
const { rerender } = render(<Calendar />)
rerender(<Calendar />)
@@ -804,8 +780,8 @@ describe('Calendar', () => {
})
it('forces existingDay to null while a multi-day range is being planned', () => {
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
render(<Calendar />)
@@ -826,30 +802,27 @@ describe('Calendar', () => {
it('shows a generic override error when the mutation rejects with a non-Error value', async () => {
const today = todayDateString()
const upsert = vi.fn().mockRejectedValue('network exploded')
;(useWorkspace as any).mockReturnValue(mockWorkspace)
;(usePlannedDays as any).mockReturnValue(mockPlannedDays)
;(useCalendarDays as any).mockReturnValue({
data: {
startYear: 2026,
endYear: 2026,
minYear: 2026,
maxYear: 2035,
days: [
{
date: today,
name: null,
dayType: 'weekend',
isOverride: false,
overrideIsWorkingDay: null,
isFree: true,
},
],
},
isLoading: false,
error: null,
refetch: vi.fn(),
})
;(useDayOverrides as any).mockReturnValue({ data: [], isLoading: false, error: null, upsert, remove: vi.fn() })
vi.mocked(useWorkspace).mockReturnValue(mockWorkspace)
vi.mocked(usePlannedDays).mockReturnValue(mockPlannedDays)
vi.mocked(useCalendarDays).mockReturnValue(
makeCalendarDaysResult({
data: makeCalendarWindow({
days: [
makeCalendarDayEntry({
date: today,
name: null,
dayType: 'weekend',
isOverride: false,
overrideIsWorkingDay: null,
isFree: true,
}),
],
}),
})
)
vi.mocked(useDayOverrides).mockReturnValue(
makeDayOverridesResult({ data: [], upsert, remove: vi.fn() })
)
render(<Calendar />)
fireEvent.click(screen.getByTestId('calendar-override-toggle'))