import { describe, expect, it } from 'vitest'; import { StatsPeriod } from './stats-period.vo.js'; import { InvalidStatsPeriodException } from '../exceptions/invalid-stats-period.exception.js'; describe('StatsPeriod', () => { const now = new Date('2026-10-07T22:30:00.000Z'); it('defaults to the last 30 days up to today in UTC', () => { const period = StatsPeriod.create({}, now); expect(period.from).toBe('2026-09-08'); expect(period.to).toBe('2026-10-07'); expect(period.timeZone).toBe('UTC'); expect(period.days).toHaveLength(30); }); it('takes "today" in the requested time zone', () => { // 22:30 UTC — в Москве уже 8 октября expect(StatsPeriod.create({ timeZone: 'Europe/Moscow' }, now).to).toBe('2026-10-08'); }); it('lists every day of an explicit period inclusively', () => { const period = StatsPeriod.create({ from: '2026-02-27', to: '2026-03-02' }, now); expect(period.days).toEqual(['2026-02-27', '2026-02-28', '2026-03-01', '2026-03-02']); }); it.each([ [{ from: '2026-10-05', to: '2026-10-01' }, 'from after to'], [{ from: '2026-02-30' }, 'non-existent date'], [{ to: '07.10.2026' }, 'wrong date format'], [{ from: '2025-01-01', to: '2026-10-07' }, 'period too long'], [{ timeZone: 'Mars/Olympus' }, 'unknown time zone'], [{ timeZone: '+03:00' }, 'offset instead of IANA name'], ] as const)('rejects %j (%s)', (params, _reason) => { expect(() => StatsPeriod.create(params, now)).toThrow(InvalidStatsPeriodException); }); it('accepts the maximum period length', () => { expect(StatsPeriod.create({ from: '2025-10-07', to: '2026-10-07' }, now).days).toHaveLength(StatsPeriod.MAX_DAYS); }); });