Cover the mappers and labels nothing was watching
The day-override mapper was the only one in the client with no test feeding it the shape the server actually sends, which is how a feature once shipped rendering blank cards to everyone while the suite stayed green. The apply response's collision fields were mapped but only ever exercised with an empty list, and the leave band's accessible label, composed from translated text and two dates, was asserted nowhere. All three were correct; none was guarded. The day-override hook's fixtures now go through the typed factory rather than hand-written objects.
This commit is contained in:
@@ -432,6 +432,74 @@ describe('API response mappers (snake_case → camelCase)', () => {
|
||||
expect(result.createdAt).toBe('2026-06-14T17:09:47')
|
||||
})
|
||||
})
|
||||
|
||||
describe('listDayOverridesByWorkspace', () => {
|
||||
it('maps snake_case day overrides to camelCase', async () => {
|
||||
// Regression test: toDayOverride was the only mapper in this file with
|
||||
// no snake_case→camelCase test — this is the exact shape of bug that
|
||||
// shipped for getTips (see the getTips test below): a missing/wrong
|
||||
// mapping surfaces only at runtime, never in a suite that mocks the
|
||||
// module and hand-rolls already-camelCase fixtures.
|
||||
const rawResponse = [
|
||||
{
|
||||
id: 'do-1',
|
||||
workspace_id: 'ws1',
|
||||
date: '2026-12-24',
|
||||
is_working_day: true,
|
||||
note: 'Jobbade på juldagen',
|
||||
created_at: '2026-01-01T00:00:00',
|
||||
updated_at: '2026-01-02T00:00:00',
|
||||
},
|
||||
]
|
||||
|
||||
fetchMock.mockResolvedValue({
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => rawResponse,
|
||||
})
|
||||
|
||||
const result = await api.listDayOverridesByWorkspace('ws1')
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
id: 'do-1',
|
||||
workspaceId: 'ws1',
|
||||
date: '2026-12-24',
|
||||
isWorkingDay: true,
|
||||
note: 'Jobbade på juldagen',
|
||||
createdAt: '2026-01-01T00:00:00',
|
||||
updatedAt: '2026-01-02T00:00:00',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('maps a null note/created_at/updated_at through unchanged', async () => {
|
||||
const rawResponse = [
|
||||
{
|
||||
id: 'do-2',
|
||||
workspace_id: 'ws1',
|
||||
date: '2026-06-20',
|
||||
is_working_day: false,
|
||||
note: null,
|
||||
created_at: null,
|
||||
updated_at: null,
|
||||
},
|
||||
]
|
||||
|
||||
fetchMock.mockResolvedValue({
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => rawResponse,
|
||||
})
|
||||
|
||||
const result = await api.listDayOverridesByWorkspace('ws1')
|
||||
|
||||
expect(result[0]!.note).toBeNull()
|
||||
expect(result[0]!.createdAt).toBeNull()
|
||||
expect(result[0]!.updatedAt).toBeNull()
|
||||
expect(result[0]!.isWorkingDay).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('apiFetch (shared request/response handling)', () => {
|
||||
@@ -1334,6 +1402,46 @@ describe('endpoint functions (representative coverage)', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('applyPlan maps a populated collisions array to camelCase (§3.5)', async () => {
|
||||
// The only other applyPlan mapping test passes collisions: [], so
|
||||
// existing_day_type/proposed_day_type were never checked against real
|
||||
// data — this exercises the actual field renames.
|
||||
fetchMock.mockResolvedValue({
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => ({
|
||||
accepted: false,
|
||||
created_count: 0,
|
||||
skipped_identical_count: 0,
|
||||
skipped_free_count: 0,
|
||||
replaced_count: 0,
|
||||
collisions: [
|
||||
{
|
||||
date: '2026-06-15',
|
||||
parent_personal_data_uuid: 'pd1',
|
||||
child_id: 'child1',
|
||||
existing_day_type: 'vacation',
|
||||
proposed_day_type: 'sjukpenning',
|
||||
},
|
||||
],
|
||||
rejections: [],
|
||||
created_days: [],
|
||||
}),
|
||||
})
|
||||
|
||||
const result = await api.applyPlan('ws1', [], false)
|
||||
|
||||
expect(result.collisions).toEqual([
|
||||
{
|
||||
date: '2026-06-15',
|
||||
parentPersonalDataUuid: 'pd1',
|
||||
childId: 'child1',
|
||||
existingDayType: 'vacation',
|
||||
proposedDayType: 'sjukpenning',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('syncPlan posts the workspace id and maps the nested proposal/applyResult/changes', async () => {
|
||||
fetchMock.mockResolvedValue({
|
||||
ok: true,
|
||||
|
||||
Reference in New Issue
Block a user