mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 07:40:59 +00:00
a0554c2346
- 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
92 lines
3.1 KiB
TypeScript
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)
|
|
})
|
|
})
|