Group settings into four panels and give balances one home
Settings becomes Barn & familj, Saldon, Kalender & språk and Undantag & röda dagar, each saving on its own. A BalanceFlow component owns fetching from Försäkringskassan and manual entry for every parent, used by the Saldon panel and by the onboarding wizard, which now runs without the app chrome. The red-days list and the day-override form merge into one exceptions view, the vacation table becomes wrapping rows that fit a phone, and the BankID modal speaks translated status lines instead of emoji. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XBRLomdLK9jF7wU7a8AA6H
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
||||
import { render, screen, fireEvent, waitFor, act } from '@testing-library/react'
|
||||
import { Settings } from './Settings'
|
||||
import * as hooks from '@/hooks'
|
||||
import { useWorkspace } from '@/context'
|
||||
import * as api from '@/services/api'
|
||||
import { ApiRequestError } from '@/services/errors'
|
||||
import { LanguageProvider } from '@/i18n'
|
||||
import type { BalanceFlowProps } from '@/components/balance/BalanceFlow'
|
||||
import type { CalendarExceptionsProps } from '@/components/calendar/CalendarExceptions'
|
||||
import {
|
||||
makeWorkspaceContextValue,
|
||||
makeWorkspaceMembersResult,
|
||||
@@ -14,8 +16,6 @@ import {
|
||||
makeChildSettingsResult,
|
||||
makeDayOverridesResult,
|
||||
makeCalendarDaysResult,
|
||||
makeParentalLeaveFetch,
|
||||
makeTierData,
|
||||
} from '../../tests/fixtures'
|
||||
|
||||
vi.mock('@/hooks')
|
||||
@@ -29,6 +29,26 @@ vi.mock('@/components/layout/Layout', () => ({
|
||||
Layout: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
|
||||
}))
|
||||
|
||||
// `BalanceFlow` and `CalendarExceptions` each own an extensive test suite of
|
||||
// their own (BalanceFlow.test.tsx, CalendarExceptions.test.tsx) — Settings
|
||||
// only needs to prove it wires the right props through to each, not
|
||||
// re-exercise their internals.
|
||||
let lastBalanceFlowProps: BalanceFlowProps | null = null
|
||||
vi.mock('@/components/balance/BalanceFlow', () => ({
|
||||
BalanceFlow: (props: BalanceFlowProps) => {
|
||||
lastBalanceFlowProps = props
|
||||
return <div data-testid="balance-flow-stub" />
|
||||
},
|
||||
}))
|
||||
|
||||
let lastCalendarExceptionsProps: CalendarExceptionsProps | null = null
|
||||
vi.mock('@/components/calendar/CalendarExceptions', () => ({
|
||||
CalendarExceptions: (props: CalendarExceptionsProps) => {
|
||||
lastCalendarExceptionsProps = props
|
||||
return <div data-testid="calendar-exceptions-stub" />
|
||||
},
|
||||
}))
|
||||
|
||||
function renderSettings() {
|
||||
return render(<Settings />)
|
||||
}
|
||||
@@ -50,7 +70,6 @@ const CURRENT_YEAR = new Date().getFullYear()
|
||||
const CHILD_BIRTH_DATE = `${CURRENT_YEAR - 1}-01-01`
|
||||
|
||||
describe('Settings', () => {
|
||||
|
||||
const mockVacationDays = [
|
||||
{
|
||||
id: 'vd-1',
|
||||
@@ -108,6 +127,8 @@ describe('Settings', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
lastBalanceFlowProps = null
|
||||
lastCalendarExceptionsProps = null
|
||||
mockUpsertVacationDays = vi.fn().mockResolvedValue(undefined)
|
||||
mockUpdateChildDetails = vi.fn().mockResolvedValue(undefined)
|
||||
mockUpsertDayOverride = vi.fn().mockResolvedValue(undefined)
|
||||
@@ -175,11 +196,6 @@ describe('Settings', () => {
|
||||
})
|
||||
vi.mocked(api.renameWorkspaceParent).mockResolvedValue(partnerMember)
|
||||
vi.mocked(api.removeWorkspaceParent).mockResolvedValue(undefined)
|
||||
// Default: nothing saved yet for whoever's balance form gets opened —
|
||||
// `useLatestBalance` (a real hook, imported directly by Settings.tsx to
|
||||
// bypass the `vi.mock('@/hooks')` above) falls back to the form's
|
||||
// preset. Tests that care about a saved balance override this.
|
||||
vi.mocked(api.getParentalLeave).mockResolvedValue(null)
|
||||
})
|
||||
|
||||
it('renders loading spinner while workspace loads', () => {
|
||||
@@ -202,28 +218,18 @@ describe('Settings', () => {
|
||||
expect(screen.getByTestId('page-skeleton')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders consistently Swedish section headings', () => {
|
||||
it('renders the four panels as h2 headings, in order, with the family panel\'s h3 subsections', () => {
|
||||
renderSettings()
|
||||
expect(screen.getByRole('heading', { name: 'Barn' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('heading', { name: 'Din profil' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('heading', { name: 'Partner' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('heading', { name: 'Semesterdagar' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('heading', { name: 'Kalender' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('heading', { name: 'Undantag i kalendern' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('heading', { name: 'Röda dagar' })).toBeInTheDocument()
|
||||
const h2s = screen.getAllByRole('heading', { level: 2 }).map((h) => h.textContent)
|
||||
expect(h2s).toEqual(['Barn & familj', 'Saldon', 'Kalender & språk', 'Undantag & röda dagar'])
|
||||
|
||||
const h3s = screen.getAllByRole('heading', { level: 3 }).map((h) => h.textContent)
|
||||
expect(h3s).toEqual(['Din profil', 'Partner'])
|
||||
})
|
||||
|
||||
it('renders the partner section where the removed planning-mode selector used to be, right after the profile section, and never renders a planning-mode selector', () => {
|
||||
it('keeps the settings-page root testid', () => {
|
||||
renderSettings()
|
||||
const headings = screen.getAllByRole('heading', { level: 2 }).map((h) => h.textContent)
|
||||
const profileIndex = headings.indexOf('Din profil')
|
||||
const partnerIndex = headings.indexOf('Partner')
|
||||
const vacationIndex = headings.indexOf('Semesterdagar')
|
||||
expect(profileIndex).toBeGreaterThanOrEqual(0)
|
||||
expect(partnerIndex).toBe(profileIndex + 1)
|
||||
expect(vacationIndex).toBe(partnerIndex + 1)
|
||||
expect(screen.queryByTestId('planning-mode-selector')).not.toBeInTheDocument()
|
||||
expect(screen.queryByRole('heading', { name: 'Planering' })).not.toBeInTheDocument()
|
||||
expect(screen.getByTestId('settings-page')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
describe('vacation days table', () => {
|
||||
@@ -267,25 +273,17 @@ describe('Settings', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('saves saved-days-in alongside total days', async () => {
|
||||
it('does not disable the vacation table while the family panel is saving', async () => {
|
||||
renderSettings()
|
||||
const savedInput = screen.getByTestId(`vacation-saved-days-${CURRENT_YEAR}`)
|
||||
fireEvent.change(savedInput, { target: { value: '7' } })
|
||||
fireEvent.click(screen.getByTestId(`vacation-save-${CURRENT_YEAR}`))
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockUpsertVacationDays).toHaveBeenCalledWith({
|
||||
personalDataUuid: 'pd-1',
|
||||
workspaceId: 'ws-1',
|
||||
year: CURRENT_YEAR,
|
||||
totalDays: 10,
|
||||
savedDaysIn: 7,
|
||||
}),
|
||||
)
|
||||
fireEvent.click(screen.getByTestId('save-family-button'))
|
||||
// The vacation save button must stay enabled — it has its own
|
||||
// `isSavingVacation` flag, independent of the family panel's.
|
||||
expect(screen.getByTestId(`vacation-save-${CURRENT_YEAR}`)).not.toBeDisabled()
|
||||
await waitFor(() => expect(screen.getByTestId('save-family-button')).not.toBeDisabled())
|
||||
})
|
||||
})
|
||||
|
||||
describe('child settings', () => {
|
||||
describe('family panel — child + profile (one combined Save)', () => {
|
||||
it('prefills birth date and preschool planning days from the child', () => {
|
||||
renderSettings()
|
||||
const birthInput = screen.getByTestId('birth-date-input') as HTMLInputElement
|
||||
@@ -294,11 +292,13 @@ describe('Settings', () => {
|
||||
expect(preschoolInput.value).toBe('6')
|
||||
})
|
||||
|
||||
it('saves birth date and preschool planning days together', async () => {
|
||||
it('saves child details and the parent profile together with one Save button', async () => {
|
||||
renderSettings()
|
||||
const preschoolInput = screen.getByTestId('vacation-days-field')
|
||||
fireEvent.change(preschoolInput, { target: { value: '10' } })
|
||||
fireEvent.click(screen.getByTestId('save-child-button'))
|
||||
fireEvent.change(screen.getByTestId('salary-type'), { target: { value: 'monthly' } })
|
||||
fireEvent.change(screen.getByTestId('employment-status'), { target: { value: 'employed' } })
|
||||
fireEvent.click(screen.getByTestId('save-family-button'))
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockUpdateChildDetails).toHaveBeenCalledWith({
|
||||
@@ -306,21 +306,20 @@ describe('Settings', () => {
|
||||
preschoolPlanningDaysPerYear: 10,
|
||||
}),
|
||||
)
|
||||
await waitFor(() =>
|
||||
expect(api.updateParentSettings).toHaveBeenCalledWith('pd-1', {
|
||||
salary_type: 'monthly',
|
||||
employment_status: 'employed',
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('saves parent profile fields', async () => {
|
||||
renderSettings()
|
||||
fireEvent.change(screen.getByTestId('salary-type'), { target: { value: 'monthly' } })
|
||||
fireEvent.change(screen.getByTestId('employment-status'), { target: { value: 'employed' } })
|
||||
fireEvent.click(screen.getByTestId('save-parent-button'))
|
||||
|
||||
await waitFor(() =>
|
||||
expect(api.updateParentSettings).toHaveBeenCalledWith('pd-1', {
|
||||
salary_type: 'monthly',
|
||||
employment_status: 'employed',
|
||||
}),
|
||||
)
|
||||
it('shows an error when the combined family save fails', async () => {
|
||||
vi.mocked(api.updateParentSettings).mockRejectedValue(new Error('save failed'))
|
||||
renderSettings()
|
||||
fireEvent.click(screen.getByTestId('save-family-button'))
|
||||
expect(await screen.findByTestId('save-message')).toHaveTextContent('save failed')
|
||||
})
|
||||
})
|
||||
|
||||
it('adds a partner', async () => {
|
||||
@@ -348,104 +347,6 @@ describe('Settings', () => {
|
||||
expect(message).toHaveTextContent('Partnerns namn är ogiltigt.')
|
||||
})
|
||||
|
||||
describe('parent balance ("Dagar kvar")', () => {
|
||||
it('opens the balance form for a solo workspace with a 480-day total', async () => {
|
||||
renderSettings()
|
||||
fireEvent.click(screen.getByTestId('settings-balance-pd-1'))
|
||||
expect(await screen.findByText('Dina dagar kvar')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('prefills the form with the parent\'s saved balance instead of the preset', async () => {
|
||||
vi.mocked(api.getParentalLeave).mockResolvedValue(
|
||||
makeParentalLeaveFetch({
|
||||
personalDataUuid: 'pd-1',
|
||||
childId: 'c-1',
|
||||
dubbeldagarLeft: 12,
|
||||
reservedDaysLeft: 34,
|
||||
tierData: makeTierData({ sjukpenningLeft: 111, lagstaNivaLeft: 22 }),
|
||||
}),
|
||||
)
|
||||
renderSettings()
|
||||
|
||||
fireEvent.click(screen.getByTestId('settings-balance-pd-1'))
|
||||
|
||||
expect(await screen.findByText('Dina dagar kvar')).toBeInTheDocument()
|
||||
expect((screen.getByLabelText(/Sjukpenningnivå/) as HTMLInputElement).value).toBe('111')
|
||||
expect((screen.getByLabelText(/Lägstanivå/) as HTMLInputElement).value).toBe('22')
|
||||
expect((screen.getByLabelText(/Dubbeldagar/) as HTMLInputElement).value).toBe('12')
|
||||
})
|
||||
|
||||
it('falls back to the preset when the parent has no saved balance yet', async () => {
|
||||
vi.mocked(api.getParentalLeave).mockResolvedValue(null)
|
||||
renderSettings()
|
||||
|
||||
fireEvent.click(screen.getByTestId('settings-balance-pd-1'))
|
||||
|
||||
expect(await screen.findByText('Dina dagar kvar')).toBeInTheDocument()
|
||||
// Solo workspace -> 480-day preset, split 390:90.
|
||||
expect((screen.getByLabelText(/Sjukpenningnivå/) as HTMLInputElement).value).toBe('390')
|
||||
expect((screen.getByLabelText(/Lägstanivå/) as HTMLInputElement).value).toBe('90')
|
||||
})
|
||||
|
||||
it("falls back to the workspace's first child when no child is selected yet", async () => {
|
||||
vi.mocked(useWorkspace).mockReturnValue(
|
||||
makeWorkspaceContextValue({
|
||||
workspace: { id: 'ws-1', name: 'Test Workspace', createdAt: '2026-01-01' },
|
||||
workspaceId: 'ws-1',
|
||||
children: [{ id: 'c-9', name: 'Child 9', birth_date: CHILD_BIRTH_DATE }],
|
||||
selectedChildId: null,
|
||||
personalDataUuid: 'pd-1',
|
||||
parentName: 'Test Parent',
|
||||
})
|
||||
)
|
||||
renderSettings()
|
||||
|
||||
fireEvent.click(screen.getByTestId('settings-balance-pd-1'))
|
||||
await screen.findByText('Dina dagar kvar')
|
||||
const saveButtons = screen.getAllByRole('button', { name: 'Spara' })
|
||||
fireEvent.click(saveButtons[saveButtons.length - 1]!)
|
||||
|
||||
await waitFor(() =>
|
||||
expect(api.saveManualFetch).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ personalDataUuid: 'pd-1', workspaceId: 'ws-1', childId: 'c-9', source: 'manual' })
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
it('does nothing when there is no child to attach the balance to', async () => {
|
||||
vi.mocked(useWorkspace).mockReturnValue(
|
||||
makeWorkspaceContextValue({
|
||||
workspace: { id: 'ws-1', name: 'Test Workspace', createdAt: '2026-01-01' },
|
||||
workspaceId: 'ws-1',
|
||||
children: [],
|
||||
selectedChildId: null,
|
||||
personalDataUuid: 'pd-1',
|
||||
parentName: 'Test Parent',
|
||||
})
|
||||
)
|
||||
renderSettings()
|
||||
|
||||
fireEvent.click(screen.getByTestId('settings-balance-pd-1'))
|
||||
await screen.findByText('Dina dagar kvar')
|
||||
const saveButtons = screen.getAllByRole('button', { name: 'Spara' })
|
||||
fireEvent.click(saveButtons[saveButtons.length - 1]!)
|
||||
|
||||
expect(api.saveManualFetch).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('shows an error when saving a balance fails', async () => {
|
||||
vi.mocked(api.saveManualFetch).mockRejectedValue(new Error('balance save failed'))
|
||||
renderSettings()
|
||||
|
||||
fireEvent.click(screen.getByTestId('settings-balance-pd-1'))
|
||||
await screen.findByText('Dina dagar kvar')
|
||||
const saveButtons = screen.getAllByRole('button', { name: 'Spara' })
|
||||
fireEvent.click(saveButtons[saveButtons.length - 1]!)
|
||||
|
||||
expect(await screen.findByText('balance save failed')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('workspace members', () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(hooks.useWorkspaceMembers).mockReturnValue(
|
||||
@@ -587,55 +488,51 @@ describe('Settings', () => {
|
||||
const message = await screen.findByTestId('member-action-error-pd-2')
|
||||
expect(message).not.toHaveTextContent('workspace.parents.remove.self')
|
||||
})
|
||||
})
|
||||
|
||||
it('opens the balance form for the clicked member and saves with that member\'s uuid', async () => {
|
||||
vi.mocked(api.saveManualFetch).mockResolvedValue({
|
||||
id: 'plf-1',
|
||||
personalDataUuid: 'pd-2',
|
||||
workspaceId: 'ws-1',
|
||||
childId: 'c-1',
|
||||
source: 'manual',
|
||||
fetchedAt: '2026-01-01',
|
||||
totalDays: 240,
|
||||
daysUsed: 0,
|
||||
daysLeft: 240,
|
||||
reservedDaysTotal: 45,
|
||||
reservedDaysLeft: 45,
|
||||
transferableDaysLeft: 0,
|
||||
dubbeldagarLeft: 60,
|
||||
tierData: {
|
||||
sjukpenningTotal: 195,
|
||||
sjukpenningUsed: 0,
|
||||
sjukpenningLeft: 195,
|
||||
lagstaNivaTotal: 45,
|
||||
lagstaNivaUsed: 0,
|
||||
lagstaNivaLeft: 45,
|
||||
},
|
||||
createdAt: '2026-01-01',
|
||||
updatedAt: '2026-01-01',
|
||||
})
|
||||
describe('Saldon panel — BalanceFlow wiring', () => {
|
||||
it('renders BalanceFlow in panel mode with the workspace members and selected child', () => {
|
||||
renderSettings()
|
||||
|
||||
fireEvent.click(screen.getByTestId('settings-balance-pd-2'))
|
||||
expect(await screen.findByText('Sams dagar kvar')).toBeInTheDocument()
|
||||
// The vacation-days table above also has per-year "Spara" buttons —
|
||||
// the balance form's is the last one rendered (it's mounted at the
|
||||
// very end of the page).
|
||||
const saveButtons = screen.getAllByRole('button', { name: 'Spara' })
|
||||
fireEvent.click(saveButtons[saveButtons.length - 1]!)
|
||||
|
||||
await waitFor(() =>
|
||||
expect(api.saveManualFetch).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ personalDataUuid: 'pd-2', workspaceId: 'ws-1', childId: 'c-1', source: 'manual' })
|
||||
)
|
||||
)
|
||||
expect(screen.getByTestId('balance-flow-stub')).toBeInTheDocument()
|
||||
expect(lastBalanceFlowProps).toMatchObject({
|
||||
mode: 'panel',
|
||||
personalDataUuid: 'pd-1',
|
||||
workspaceId: 'ws-1',
|
||||
selectedChildId: 'c-1',
|
||||
})
|
||||
expect(lastBalanceFlowProps?.members).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('opens the balance form for the logged-in user\'s own row too', async () => {
|
||||
it("falls back to the workspace's first child when no child is selected yet", () => {
|
||||
vi.mocked(useWorkspace).mockReturnValue(
|
||||
makeWorkspaceContextValue({
|
||||
workspace: { id: 'ws-1', name: 'Test Workspace', createdAt: '2026-01-01' },
|
||||
workspaceId: 'ws-1',
|
||||
children: [{ id: 'c-9', name: 'Child 9', birth_date: CHILD_BIRTH_DATE }],
|
||||
selectedChildId: null,
|
||||
personalDataUuid: 'pd-1',
|
||||
parentName: 'Test Parent',
|
||||
})
|
||||
)
|
||||
renderSettings()
|
||||
expect(lastBalanceFlowProps?.selectedChildId).toBe('c-9')
|
||||
})
|
||||
|
||||
fireEvent.click(screen.getByTestId('settings-balance-pd-1'))
|
||||
expect(await screen.findByText('Dina dagar kvar')).toBeInTheDocument()
|
||||
it('refreshes members when BalanceFlow reports a save', () => {
|
||||
renderSettings()
|
||||
lastBalanceFlowProps?.onSaved?.()
|
||||
expect(mockRefreshMembers).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('shows a loading message instead of BalanceFlow while members are loading', () => {
|
||||
vi.mocked(hooks.useWorkspaceMembers).mockReturnValue(
|
||||
makeWorkspaceMembersResult({ data: [], isLoading: true, refresh: mockRefreshMembers })
|
||||
)
|
||||
renderSettings()
|
||||
// Both the partner list (family panel) and the Saldon panel gate on
|
||||
// the same `membersLoading` flag, so the message appears twice.
|
||||
expect(screen.getAllByText('Laddar medlemmar…')).toHaveLength(2)
|
||||
expect(screen.queryByTestId('balance-flow-stub')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -747,7 +644,6 @@ describe('Settings', () => {
|
||||
|
||||
it('is labelled understandably regardless of the active language', () => {
|
||||
renderSettingsWithLanguageProvider()
|
||||
expect(screen.getByText('Språk / Language')).toBeInTheDocument()
|
||||
expect(screen.getByText('Välj språk / Select language')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
@@ -788,89 +684,29 @@ describe('Settings', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('red days list (§3.8)', () => {
|
||||
it('passes the fetched calendar window through to the list, four years at a time', () => {
|
||||
vi.mocked(hooks.useCalendarDays).mockReturnValue(
|
||||
makeCalendarDaysResult({
|
||||
data: {
|
||||
startYear: CURRENT_YEAR,
|
||||
endYear: CURRENT_YEAR + 3,
|
||||
minYear: 2026,
|
||||
maxYear: 2035,
|
||||
days: [
|
||||
{
|
||||
date: `${CURRENT_YEAR}-01-01`,
|
||||
name: 'Nyårsdagen',
|
||||
dayType: 'red_day',
|
||||
isOverride: false,
|
||||
overrideIsWorkingDay: null,
|
||||
isFree: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
describe('Undantag & röda dagar panel — CalendarExceptions wiring', () => {
|
||||
it('passes the fetched calendar window and override handlers through', () => {
|
||||
renderSettings()
|
||||
|
||||
expect(screen.getByTestId('red-days-range')).toHaveTextContent(`${CURRENT_YEAR}–${CURRENT_YEAR + 3}`)
|
||||
expect(screen.getByTestId(`red-days-item-${CURRENT_YEAR}-01-01`)).toHaveTextContent('Nyårsdagen')
|
||||
expect(screen.getByTestId('calendar-exceptions-stub')).toBeInTheDocument()
|
||||
expect(lastCalendarExceptionsProps).toMatchObject({
|
||||
startYear: CURRENT_YEAR,
|
||||
years: 4,
|
||||
workspaceId: 'ws-1',
|
||||
})
|
||||
expect(lastCalendarExceptionsProps?.onUpsertOverride).toBe(mockUpsertDayOverride)
|
||||
expect(lastCalendarExceptionsProps?.onRemoveOverride).toBe(mockRemoveDayOverride)
|
||||
})
|
||||
|
||||
it('requests the next 4-year window when paginating forward', () => {
|
||||
renderSettings()
|
||||
|
||||
fireEvent.click(screen.getByTestId('red-days-next'))
|
||||
|
||||
act(() => lastCalendarExceptionsProps?.onNextWindow())
|
||||
expect(hooks.useCalendarDays).toHaveBeenLastCalledWith('ws-1', CURRENT_YEAR + 4, 4)
|
||||
})
|
||||
|
||||
it('requests the previous 4-year window when paginating backward', () => {
|
||||
// minYear well below the current window so the "previous" button isn't disabled.
|
||||
vi.mocked(hooks.useCalendarDays).mockReturnValue(
|
||||
makeCalendarDaysResult({
|
||||
data: { ...mockCalendarWindow, minYear: 2000 },
|
||||
})
|
||||
)
|
||||
|
||||
renderSettings()
|
||||
|
||||
fireEvent.click(screen.getByTestId('red-days-prev'))
|
||||
|
||||
act(() => lastCalendarExceptionsProps?.onPrevWindow())
|
||||
expect(hooks.useCalendarDays).toHaveBeenLastCalledWith('ws-1', CURRENT_YEAR - 4, 4)
|
||||
})
|
||||
|
||||
it('wires the toggle button through to the shared day-overrides hook', async () => {
|
||||
vi.mocked(hooks.useCalendarDays).mockReturnValue(
|
||||
makeCalendarDaysResult({
|
||||
data: {
|
||||
...mockCalendarWindow,
|
||||
days: [
|
||||
{
|
||||
date: `${CURRENT_YEAR}-01-01`,
|
||||
name: 'Nyårsdagen',
|
||||
dayType: 'red_day',
|
||||
isOverride: false,
|
||||
overrideIsWorkingDay: null,
|
||||
isFree: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
renderSettings()
|
||||
|
||||
fireEvent.click(screen.getByTestId(`red-days-toggle-${CURRENT_YEAR}-01-01`))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockUpsertDayOverride).toHaveBeenCalledWith({
|
||||
workspaceId: 'ws-1',
|
||||
date: `${CURRENT_YEAR}-01-01`,
|
||||
isWorkingDay: true,
|
||||
note: null,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user