Files
TREK/client/src/utils/localDate.test.ts
T
Maurice a0554c2346 fix: four reported bugs that dev still had
- Dashboard: a browser that names no time zone (Chrome on Windows for a zone
  it cannot map) crashed the world clocks and the whole dashboard. One helper
  now reads the browser zone and every reader picks its fallback; a stored
  zone the browser does not know is left out instead of throwing (#2694).
- Phone: a leg of a multi-leg train or flight showed only its route, and its
  sheet showed the first leg's seat. The day plan subtitle is one helper for
  desktop and phone now, so a leg names its own train or flight, platform and
  seat, translated instead of the hardcoded "Gl."/"Sitz"; the sheet opened
  from a leg shows that leg's number, seat, platform and times (#2701). The
  PDF export translates platform and seat too.
- Journey list: the year badge named the year a journey was written, not the
  years of its trips; a trip over New Year shows both (#2685).
- A place's description and notes are markdown in the planner but printed as
  raw syntax in the PDF export and on a shared trip. Both render it now through
  the app's sanitized markdown pipeline, raw HTML stays text (#2692).

Closes #2694
Closes #2701
Closes #2685
Closes #2692
2026-10-24 10:39:35 +02:00

92 lines
3.1 KiB
TypeScript

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { browserTimeZone, isLocalToday, isValidTimeZone, localIsoDate, localMinutes } from './localDate'
/**
* "Today" must be the user's local calendar date. `toISOString()` is the UTC
* date — between local midnight and the UTC rollover it is YESTERDAY for any
* TZ ahead of UTC, which misclassified trips/journeys in that window. On a UTC
* machine local == UTC, so the distinction is vacuous there; these tests pin
* the clock at 00:30 local, where any positive offset separates the two.
*/
describe('localIsoDate', () => {
beforeEach(() => {
vi.useFakeTimers()
vi.setSystemTime(new Date(2026, 7, 25, 0, 30)) // local 2026-08-25 00:30
})
afterEach(() => {
vi.useRealTimers()
})
it('formats the local calendar date, zero-padded', () => {
expect(localIsoDate()).toBe('2026-08-25')
expect(localIsoDate(new Date(2026, 0, 3, 12))).toBe('2026-01-03')
})
it('defaults to now', () => {
expect(localIsoDate()).toBe(localIsoDate(new Date()))
})
})
describe('localMinutes', () => {
afterEach(() => {
vi.useRealTimers()
})
it('counts the minutes since local midnight', () => {
expect(localMinutes(new Date(2026, 7, 25, 0, 0))).toBe(0)
expect(localMinutes(new Date(2026, 7, 25, 13, 45, 59))).toBe(825)
expect(localMinutes(new Date(2026, 7, 25, 23, 59))).toBe(1439)
})
it('defaults to now', () => {
vi.useFakeTimers()
vi.setSystemTime(new Date(2026, 7, 25, 0, 30))
expect(localMinutes()).toBe(30)
})
})
describe('isLocalToday', () => {
beforeEach(() => {
vi.useFakeTimers()
vi.setSystemTime(new Date(2026, 7, 25, 0, 30)) // local 2026-08-25 00:30
})
afterEach(() => {
vi.useRealTimers()
})
it('matches the local calendar date, with or without a time part', () => {
expect(isLocalToday('2026-08-25')).toBe(true)
expect(isLocalToday('2026-08-25T00:00:00.000Z')).toBe(true)
})
it('is false for another date or no date at all', () => {
expect(isLocalToday('2026-08-24')).toBe(false)
expect(isLocalToday('')).toBe(false)
expect(isLocalToday(null)).toBe(false)
expect(isLocalToday(undefined)).toBe(false)
})
})
describe('browserTimeZone and isValidTimeZone (#2694)', () => {
it('names the browser zone, and nothing when the browser names none', () => {
expect(browserTimeZone()).toBe(Intl.DateTimeFormat().resolvedOptions().timeZone)
const original = Intl.DateTimeFormat.prototype.resolvedOptions
const spy = vi.spyOn(Intl.DateTimeFormat.prototype, 'resolvedOptions').mockImplementation(function (this: Intl.DateTimeFormat) {
return { ...original.call(this), timeZone: undefined as unknown as string }
})
try {
expect(browserTimeZone()).toBeUndefined()
} finally {
spy.mockRestore()
}
})
it('accepts the zones Intl knows and refuses the rest', () => {
expect(isValidTimeZone('Europe/Berlin')).toBe(true)
expect(isValidTimeZone('UTC')).toBe(true)
expect(isValidTimeZone('Mars/Olympus_Mons')).toBe(false)
expect(isValidTimeZone('')).toBe(false)
expect(isValidTimeZone(undefined)).toBe(false)
})
})