import { describe, it, expect, afterEach } from 'vitest' import { DEFAULT_TIMEZONE, COMMON_TIMEZONES, detectTimezone, listTimezones, isValidTimezone, } from '../src/lib/timezone.js' import { createEvent } from '../src/lib/event-factory.js' describe('DEFAULT_TIMEZONE', () => { it('is Australia/Melbourne per requirement', () => { expect(DEFAULT_TIMEZONE).toBe('Australia/Melbourne') }) }) describe('isValidTimezone', () => { it('accepts valid IANA zone ids', () => { expect(isValidTimezone('Australia/Melbourne')).toBe(true) expect(isValidTimezone('Asia/Shanghai')).toBe(true) expect(isValidTimezone('America/New_York')).toBe(true) expect(isValidTimezone('Europe/London')).toBe(true) }) it('rejects empty / non-string / malformed', () => { expect(isValidTimezone('')).toBe(false) expect(isValidTimezone(null)).toBe(false) expect(isValidTimezone(undefined)).toBe(false) expect(isValidTimezone(123)).toBe(false) expect(isValidTimezone('UTC')).toBe(false) // 单段, 本应用要求至少一段 '/' expect(isValidTimezone('Not A Zone')).toBe(false) expect(isValidTimezone('Bogus/Zone/With Space')).toBe(false) }) }) describe('detectTimezone', () => { // 保存原始 Intl 引用以便恢复 const origDateTimeFormat = Intl.DateTimeFormat afterEach(() => { Intl.DateTimeFormat = origDateTimeFormat }) it('returns a valid IANA zone in a normal environment', () => { // Node 环境总能解析出系统时区 const tz = detectTimezone() expect(isValidTimezone(tz)).toBe(true) }) it('falls back to Melbourne when Intl.DateTimeFormat throws', () => { Intl.DateTimeFormat = function () { throw new Error('unsupported') } expect(detectTimezone()).toBe(DEFAULT_TIMEZONE) }) it('falls back to Melbourne when resolved timeZone is empty', () => { Intl.DateTimeFormat = function () { return { resolvedOptions: () => ({ timeZone: '' }) } } expect(detectTimezone()).toBe(DEFAULT_TIMEZONE) }) it('falls back to Melbourne when resolved timeZone is malformed', () => { Intl.DateTimeFormat = function () { return { resolvedOptions: () => ({ timeZone: 'Not A Zone' }) } } expect(detectTimezone()).toBe(DEFAULT_TIMEZONE) }) it('returns the detected zone when it is valid', () => { Intl.DateTimeFormat = function () { return { resolvedOptions: () => ({ timeZone: 'Asia/Shanghai' }) } } expect(detectTimezone()).toBe('Asia/Shanghai') }) }) describe('listTimezones', () => { it('always includes Melbourne, Shanghai, UTC', () => { const list = listTimezones() expect(list).toContain('Australia/Melbourne') expect(list).toContain('Asia/Shanghai') expect(list).toContain('UTC') }) it('has no duplicates', () => { const list = listTimezones() expect(new Set(list).size).toBe(list.length) }) it('places UTC first, rest sorted', () => { const list = listTimezones() expect(list[0]).toBe('UTC') const rest = list.slice(1) const sorted = [...rest].sort((a, b) => a.localeCompare(b)) expect(rest).toEqual(sorted) }) it('every entry is a valid IANA zone (UTC excepted)', () => { const list = listTimezones() for (const tz of list) { if (tz === 'UTC') continue expect(isValidTimezone(tz)).toBe(true) } }) it('includes all COMMON_TIMEZONES entries', () => { const list = listTimezones() for (const tz of COMMON_TIMEZONES) { expect(list).toContain(tz) } }) }) describe('createEvent timezone override', () => { // 确认 useCalendar.addEvent 依赖的覆盖路径:传入 { tzid } 后新建事件的 // tzid 即为该值(而非 event-factory 的独立默认 'UTC')。 it('honors the tzid passed via overrides', () => { const ev = createEvent({ tzid: 'Asia/Shanghai' }) expect(ev.tzid).toBe('Asia/Shanghai') }) it('falls back to UTC when no tzid override is given (standalone default)', () => { const ev = createEvent() expect(ev.tzid).toBe('UTC') }) })