Files
TREK/client/tests/unit/utils/startDestination.test.ts
T
Maurice e7851e79ff fix(client): honour the start page on a device that never mirrored it
The mirror answered "dashboard" for a browser that had simply never been
told, and RootRedirect took that as the user's choice - so the setting was
ignored on every device except the one that set it, and on that one too
after a logout cleared the mirror. The setting itself was stored correctly
the whole time, which is what made it look like nothing happened.

readStartDestination now says "unknown" rather than guessing, and a device
in that state waits for the real settings instead. That costs one wait,
once per device; afterwards the mirror answers and the launch is as fast
as before. Bounded by a timeout, because loadSettings deliberately leaves
isLoaded false on a failed request so it can retry - without the floor, a
launch with no backend would sit on the spinner forever.
2026-08-08 23:01:40 +02:00

97 lines
3.9 KiB
TypeScript

// FE-UTIL-START-001 to FE-UTIL-START-009
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'
import {
readStartDestination,
rememberStartDestination,
forgetStartDestination,
tripStartPath,
DEFAULT_START_PAGE,
DEFAULT_START_TRIP_TAB,
} from '../../../src/utils/startDestination'
beforeEach(() => {
localStorage.clear()
})
afterEach(() => {
vi.restoreAllMocks()
})
describe('readStartDestination', () => {
// Not the dashboard: the preference lives on the server, so a device that has
// never seen it has to say "I don't know" and let the caller wait for the
// settings. Answering 'dashboard' here ignored the setting on every device
// that hadn't set it — including any browser that had logged out since.
it('FE-UTIL-START-001: reports "unknown" when nothing was ever mirrored', () => {
expect(readStartDestination()).toBeNull()
})
it('FE-UTIL-START-002: returns what was mirrored', () => {
rememberStartDestination({ start_page: 'active_trip', start_trip_tab: 'finanzplan' })
expect(readStartDestination()).toEqual({ page: 'active_trip', tab: 'finanzplan' })
})
it('FE-UTIL-START-002b: an explicitly mirrored dashboard is an answer, not "unknown"', () => {
rememberStartDestination({ start_page: 'dashboard' })
expect(readStartDestination()).toEqual({ page: DEFAULT_START_PAGE, tab: DEFAULT_START_TRIP_TAB })
})
// A value a user (or an older/newer build) could have written by hand must not
// become a route we then navigate to.
it('FE-UTIL-START-003: ignores values that are not a known page or tab', () => {
localStorage.setItem('trek_start_page', 'somewhere_else')
expect(readStartDestination()).toBeNull()
localStorage.setItem('trek_start_page', 'active_trip')
localStorage.setItem('trek_start_trip_tab', '../../etc/passwd')
expect(readStartDestination()).toEqual({ page: 'active_trip', tab: DEFAULT_START_TRIP_TAB })
})
it('FE-UTIL-START-004: survives a browser that refuses storage access', () => {
vi.spyOn(Storage.prototype, 'getItem').mockImplementation(() => {
throw new Error('SecurityError')
})
expect(readStartDestination()).toBeNull()
})
})
describe('rememberStartDestination', () => {
it('FE-UTIL-START-005: only touches the keys present in the patch', () => {
rememberStartDestination({ start_page: 'active_trip', start_trip_tab: 'dateien' })
rememberStartDestination({ start_trip_tab: 'buchungen' })
expect(readStartDestination()).toEqual({ page: 'active_trip', tab: 'buchungen' })
})
it('FE-UTIL-START-006: clears a key that comes back invalid instead of keeping a stale one', () => {
rememberStartDestination({ start_page: 'active_trip' })
rememberStartDestination({ start_page: undefined })
expect(localStorage.getItem('trek_start_page')).toBeNull()
})
it('FE-UTIL-START-007: swallows a quota error rather than failing the settings save', () => {
vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => {
throw new Error('QuotaExceededError')
})
expect(() => rememberStartDestination({ start_page: 'active_trip' })).not.toThrow()
})
})
describe('forgetStartDestination', () => {
it('FE-UTIL-START-008: leaves the next account on this browser knowing nothing', () => {
rememberStartDestination({ start_page: 'active_trip', start_trip_tab: 'finanzplan' })
forgetStartDestination()
// "unknown", so the next login waits for its own settings instead of
// inheriting the previous account's preference.
expect(readStartDestination()).toBeNull()
})
})
describe('tripStartPath', () => {
it('FE-UTIL-START-009: always spells the tab out, and never a tab that does not exist', () => {
// Explicit even for 'plan', or the last session's tab would decide instead.
expect(tripStartPath(7, 'plan')).toBe('/trips/7?tab=plan')
expect(tripStartPath(7, 'finanzplan')).toBe('/trips/7?tab=finanzplan')
expect(tripStartPath(7, 'nonsense')).toBe('/trips/7?tab=plan')
})
})