Files
negotium/src/lib/dates.test.js
T
Aculix Technologies e81e7ef8e7 feat: add date-key module with local-time formatting
Switches task keys to ISO YYYY-MM-DD. They sort, so finding every day
before today is a string compare instead of re-parsing each key.

Two things worth knowing. fromKey builds from date parts rather than
parsing a bare ISO string, which gets read as UTC and lands on the wrong
day west of Greenwich. addDays goes through setDate, so it stays on the
same calendar day across a DST change instead of adding a flat 24 hours.
2026-08-15 23:49:29 +05:30

90 lines
2.4 KiB
JavaScript

import { describe, it, expect } from 'vitest'
import { toKey, fromKey, addDays, isKey, labelFor, formatLong } from './dates.js'
describe('toKey', () => {
it('formats a date as local YYYY-MM-DD', () => {
expect(toKey(new Date(2026, 7, 15))).toBe('2026-08-15')
})
it('zero-pads single-digit months and days', () => {
expect(toKey(new Date(2026, 0, 5))).toBe('2026-01-05')
})
it('uses local time, not UTC', () => {
// 23:30 local on the 15th must not roll forward to the 16th.
expect(toKey(new Date(2026, 7, 15, 23, 30))).toBe('2026-08-15')
})
})
describe('fromKey', () => {
it('returns local midnight for the key', () => {
const date = fromKey('2026-08-15')
expect(date.getFullYear()).toBe(2026)
expect(date.getMonth()).toBe(7)
expect(date.getDate()).toBe(15)
expect(date.getHours()).toBe(0)
})
it('round-trips with toKey', () => {
expect(toKey(fromKey('2026-08-15'))).toBe('2026-08-15')
})
})
describe('addDays', () => {
it('advances across a month boundary', () => {
expect(toKey(addDays(new Date(2026, 7, 31), 1))).toBe('2026-09-01')
})
it('advances across a year boundary', () => {
expect(toKey(addDays(new Date(2026, 11, 31), 1))).toBe('2027-01-01')
})
it('does not mutate its argument', () => {
const date = new Date(2026, 7, 15)
addDays(date, 5)
expect(toKey(date)).toBe('2026-08-15')
})
})
describe('isKey', () => {
it('accepts ISO date keys', () => {
expect(isKey('2026-08-15')).toBe(true)
})
it('rejects legacy toDateString keys', () => {
expect(isKey('Sat Aug 15 2026')).toBe(false)
})
it('rejects arbitrary strings', () => {
expect(isKey('not-a-date')).toBe(false)
})
})
describe('labelFor', () => {
it('labels today', () => {
expect(labelFor('2026-08-15', '2026-08-15')).toBe('Today')
})
it('labels tomorrow', () => {
expect(labelFor('2026-08-16', '2026-08-15')).toBe('Tomorrow')
})
it('labels tomorrow across a month boundary', () => {
expect(labelFor('2026-09-01', '2026-08-31')).toBe('Tomorrow')
})
it('labels tomorrow across a year boundary', () => {
expect(labelFor('2027-01-01', '2026-12-31')).toBe('Tomorrow')
})
it('falls back to a short date for other days', () => {
expect(labelFor('2026-08-20', '2026-08-15')).toBe('Aug 20')
})
})
describe('formatLong', () => {
it('renders the long-form date used in the header', () => {
expect(formatLong('2026-08-15')).toBe('Saturday, August 15, 2026')
})
})