mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
92 lines
3.3 KiB
TypeScript
92 lines
3.3 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
formatCustom,
|
|
formatDate,
|
|
formatIso,
|
|
formatSmart,
|
|
type DateFormatMode,
|
|
} from './date-format';
|
|
|
|
/** A fixed local reference "now" for relative-date tests. */
|
|
const NOW = new Date(2026, 5, 7, 12, 0, 0); // 2026-06-07 12:00 local
|
|
const at = (y: number, mo: number, d: number, h = 9, mi = 0, s = 0) => new Date(y, mo, d, h, mi, s);
|
|
|
|
describe('formatSmart', () => {
|
|
it('renders the same calendar day as Today', () => {
|
|
expect(formatSmart(at(2026, 5, 7, 0, 1), NOW)).toBe('Today');
|
|
expect(formatSmart(at(2026, 5, 7, 23, 59), NOW)).toBe('Today');
|
|
});
|
|
|
|
it('renders the previous calendar day as Yesterday', () => {
|
|
expect(formatSmart(at(2026, 5, 6), NOW)).toBe('Yesterday');
|
|
});
|
|
|
|
it('renders under a week as Nd ago', () => {
|
|
expect(formatSmart(at(2026, 5, 4), NOW)).toBe('3d ago');
|
|
expect(formatSmart(at(2026, 5, 1), NOW)).toBe('6d ago');
|
|
});
|
|
|
|
it('falls back to a full locale date at a week or older', () => {
|
|
const old = at(2026, 4, 1);
|
|
expect(formatSmart(old, NOW)).toBe(old.toLocaleDateString());
|
|
});
|
|
|
|
it('does not flip to Yesterday on the hour within the same day', () => {
|
|
// 1 minute ago but same calendar day → still Today.
|
|
expect(formatSmart(at(2026, 5, 7, 11, 59), NOW)).toBe('Today');
|
|
});
|
|
});
|
|
|
|
describe('formatIso', () => {
|
|
it('returns a full ISO 8601 timestamp', () => {
|
|
const d = new Date('2026-06-07T10:30:00.000Z');
|
|
expect(formatIso(d)).toBe('2026-06-07T10:30:00.000Z');
|
|
});
|
|
});
|
|
|
|
describe('formatCustom', () => {
|
|
it('formats the placeholder pattern yyyy-MM-dd HH:mm', () => {
|
|
expect(formatCustom(at(2026, 0, 5, 8, 4), 'yyyy-MM-dd HH:mm')).toBe('2026-01-05 08:04');
|
|
});
|
|
|
|
it('supports month names and short year', () => {
|
|
expect(formatCustom(at(2026, 11, 25), 'd MMMM yy')).toBe('25 December 26');
|
|
expect(formatCustom(at(2026, 2, 9), 'MMM d, yyyy')).toBe('Mar 9, 2026');
|
|
});
|
|
|
|
it('supports 12-hour clock with meridiem', () => {
|
|
expect(formatCustom(at(2026, 5, 7, 0, 5), 'h:mm a')).toBe('12:05 AM');
|
|
expect(formatCustom(at(2026, 5, 7, 13, 5), 'h:mm a')).toBe('1:05 PM');
|
|
expect(formatCustom(at(2026, 5, 7, 12, 0), 'hh:mm a')).toBe('12:00 PM');
|
|
});
|
|
|
|
it('preserves non-token literals verbatim', () => {
|
|
expect(formatCustom(at(2026, 0, 1), 'yyyy/MM/dd')).toBe('2026/01/01');
|
|
});
|
|
});
|
|
|
|
describe('formatDate', () => {
|
|
it('dispatches by mode', () => {
|
|
const iso = at(2026, 5, 6, 9, 0).toISOString();
|
|
expect(formatDate(iso, 'smart', '', NOW)).toBe('Yesterday');
|
|
expect(formatDate(iso, 'iso')).toBe(new Date(iso).toISOString());
|
|
expect(formatDate(iso, 'custom', 'yyyy-MM-dd', NOW)).toBe('2026-06-06');
|
|
});
|
|
|
|
it('falls back to ISO when a custom pattern is blank', () => {
|
|
const iso = '2026-06-07T10:30:00.000Z';
|
|
expect(formatDate(iso, 'custom', ' ')).toBe(new Date(iso).toISOString());
|
|
expect(formatDate(iso, 'custom', '')).toBe(new Date(iso).toISOString());
|
|
});
|
|
|
|
it('returns an unparseable timestamp verbatim rather than "Invalid Date"', () => {
|
|
expect(formatDate('not-a-date', 'iso')).toBe('not-a-date');
|
|
expect(formatDate('not-a-date', 'smart', '', NOW)).toBe('not-a-date');
|
|
});
|
|
|
|
it('defaults unknown modes to smart', () => {
|
|
const iso = at(2026, 5, 7).toISOString();
|
|
expect(formatDate(iso, 'bogus' as DateFormatMode, '', NOW)).toBe('Today');
|
|
});
|
|
});
|