import type { Dayjs } from 'dayjs'; import dayjs from 'dayjs'; import { describe, expect, it } from 'vitest'; import { createDateRangeCodec } from '../../src/utils/date-range-codec'; interface SearchFormValues extends Record { createdAt?: [Dayjs, Dayjs]; keyword?: string; } const codec = createDateRangeCodec()({ endField: 'finishedAt', rangeField: 'createdAt', startField: 'startedAt', }); describe('date range codec', () => { it('only accepts optional date range fields', () => { interface RangeFieldCandidates extends Record { optionalRange?: [Dayjs, Dayjs]; optionalText?: string; requiredRange: [Dayjs, Dayjs]; } const createCodec = createDateRangeCodec(); const optionalRangeCodec = createCodec({ endField: 'end', rangeField: 'optionalRange', startField: 'start', }); expect(optionalRangeCodec).toEqual({ decode: expect.any(Function), encode: expect.any(Function), }); createCodec({ endField: 'end', // @ts-expect-error A required range cannot be omitted by decode. rangeField: 'requiredRange', startField: 'start', }); createCodec({ endField: 'end', // @ts-expect-error The range field must contain a DateRange. rangeField: 'optionalText', startField: 'start', }); }); it('encodes and decodes configurable date range fields', () => { const submitValues = codec.encode({ createdAt: [dayjs('2026-07-01'), dayjs('2026-07-23')], keyword: 'admin', }); expect(submitValues).toEqual({ finishedAt: '2026-07-23', keyword: 'admin', startedAt: '2026-07-01', }); const formValues = codec.decode(submitValues); expect(formValues.keyword).toBe('admin'); expect( formValues.createdAt?.map((value) => value.format('YYYY-MM-DD')), ).toEqual(['2026-07-01', '2026-07-23']); }); it('does not reconstruct a range with a missing bound', () => { expect( codec.decode({ finishedAt: undefined, keyword: 'admin', startedAt: '2026-07-01', }), ).toEqual({ keyword: 'admin' }); }); });