timezone.service.spec.tsβ’7.41 kB
import { describe, it, expect, beforeEach } from 'vitest'
import { TimezoneService } from './timezone.service'
describe('TimezoneService', () => {
let service: TimezoneService
beforeEach(() => {
service = new TimezoneService()
})
describe('getAvailableTimezones', () => {
it('should return an array of timezones', () => {
const timezones = service.getAvailableTimezones()
expect(Array.isArray(timezones)).toBe(true)
expect(timezones.length).toBeGreaterThan(0)
})
it('should include common timezones', () => {
const timezones = service.getAvailableTimezones()
expect(timezones).toContain('America/New_York')
expect(timezones).toContain('Europe/London')
expect(timezones).toContain('Asia/Tokyo')
})
})
describe('getRegions', () => {
it('should return an array of regions', () => {
const regions = service.getRegions()
expect(Array.isArray(regions)).toBe(true)
expect(regions.length).toBeGreaterThan(0)
})
it('should include common regions', () => {
const regions = service.getRegions()
expect(regions).toContain('America')
expect(regions).toContain('Europe')
expect(regions).toContain('Asia')
})
it('should return sorted regions', () => {
const regions = service.getRegions()
const sorted = [...regions].sort()
expect(regions).toEqual(sorted)
})
it('should not have duplicates', () => {
const regions = service.getRegions()
const unique = [...new Set(regions)]
expect(regions.length).toBe(unique.length)
})
})
describe('getCitiesInRegion', () => {
it('should return cities for America region', () => {
const cities = service.getCitiesInRegion('America')
expect(Array.isArray(cities)).toBe(true)
expect(cities.length).toBeGreaterThan(0)
expect(cities).toContain('New_York')
expect(cities).toContain('Los_Angeles')
})
it('should return cities for Europe region', () => {
const cities = service.getCitiesInRegion('Europe')
expect(Array.isArray(cities)).toBe(true)
expect(cities.length).toBeGreaterThan(0)
expect(cities).toContain('London')
expect(cities).toContain('Paris')
})
it('should return sorted cities', () => {
const cities = service.getCitiesInRegion('America')
const sorted = [...cities].sort()
expect(cities).toEqual(sorted)
})
it('should throw error for invalid region', () => {
expect(() => {
service.getCitiesInRegion('InvalidRegion')
}).toThrow('Invalid region')
})
it('should handle multi-part city names', () => {
const cities = service.getCitiesInRegion('America')
// Should include cities like "Argentina/Buenos_Aires" as "Argentina/Buenos_Aires"
const multiPart = cities.find((city) => city.includes('/'))
expect(multiPart).toBeDefined()
})
})
describe('getTimeInTimezone', () => {
it('should return time with local, UTC, and timezone offset', () => {
const result = service.getTimeInTimezone('America/New_York')
expect(result).toHaveProperty('timezone', 'America/New_York')
expect(result).toHaveProperty('datetime_local')
expect(result).toHaveProperty('datetime_utc')
expect(result).toHaveProperty('timezone_offset')
expect(result).toHaveProperty('timestamp')
expect(typeof result.datetime_local).toBe('string')
expect(typeof result.datetime_utc).toBe('string')
expect(typeof result.timezone_offset).toBe('string')
expect(typeof result.timestamp).toBe('number')
})
it('should return valid timezone offset format', () => {
const result = service.getTimeInTimezone('America/New_York')
// Should match offset format: +HH:mm or -HH:mm
expect(result.timezone_offset).toMatch(/^[+-]\d{2}:\d{2}$/)
})
it('should return valid ISO format for datetime_local', () => {
const result = service.getTimeInTimezone('America/New_York')
// Should match ISO format with offset: YYYY-MM-DDTHH:mm:ss+HH:mm or YYYY-MM-DDTHH:mm:ss-HH:mm
expect(result.datetime_local).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}$/)
})
it('should return valid ISO format for datetime_utc', () => {
const result = service.getTimeInTimezone('America/New_York')
// Should match ISO format with Z: YYYY-MM-DDTHH:mm:ss.sssZ
expect(result.datetime_utc).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/)
})
it('should throw error for invalid timezone', () => {
expect(() => {
service.getTimeInTimezone('Invalid/Timezone')
}).toThrow('Invalid timezone')
})
it('should have same UTC time for different timezones', () => {
const nyTime = service.getTimeInTimezone('America/New_York')
const londonTime = service.getTimeInTimezone('Europe/London')
expect(nyTime.timezone).toBe('America/New_York')
expect(londonTime.timezone).toBe('Europe/London')
// Timestamps should be within 10ms of each other (essentially same moment in time)
expect(Math.abs(nyTime.timestamp - londonTime.timestamp)).toBeLessThan(10)
// Both should have valid UTC ISO format
expect(nyTime.datetime_utc).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/)
expect(londonTime.datetime_utc).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/)
})
it('should have different local times for different timezones', () => {
const nyTime = service.getTimeInTimezone('America/New_York')
const tokyoTime = service.getTimeInTimezone('Asia/Tokyo')
// Local times should be different for different timezones
expect(nyTime.datetime_local).not.toBe(tokyoTime.datetime_local)
})
it('should use fallback offset when timeZoneName is not available', () => {
// Spy on Intl.DateTimeFormat to simulate missing timeZoneName
const originalDateTimeFormat = Intl.DateTimeFormat
// Create a mock constructor that returns formatToParts without timeZoneName on second call
let callCount = 0
class MockDateTimeFormat {
constructor(locale?: string | string[], options?: Intl.DateTimeFormatOptions) {
callCount++
if (callCount === 2 && options?.timeZoneName === 'longOffset') {
// Second call (offset formatter) - return parts without timeZoneName
const mockFormatter: Partial<Intl.DateTimeFormat> = {
formatToParts: () => [
{ type: 'month', value: '10' },
{ type: 'literal', value: '/' },
{ type: 'day', value: '18' },
{ type: 'literal', value: '/' },
{ type: 'year', value: '2025' },
// No timeZoneName part
],
}
return mockFormatter as Intl.DateTimeFormat
}
// First call (local formatter) - use real implementation
return new originalDateTimeFormat(locale, options)
}
}
globalThis.Intl.DateTimeFormat = MockDateTimeFormat as typeof Intl.DateTimeFormat
const result = service.getTimeInTimezone('America/New_York')
// Should fall back to +00:00 when offsetPart is undefined
expect(result.timezone_offset).toBe('+00:00')
// Restore original
globalThis.Intl.DateTimeFormat = originalDateTimeFormat
})
})
})