97 lines
4.3 KiB
TypeScript
97 lines
4.3 KiB
TypeScript
import { describe, it } from 'node:test';
|
|||
|
|
import assert from 'node:assert/strict';
|
||
|
|
import {
|
||
|
|
formatDayDivider,
|
||
|
|
formatRelativeAge,
|
||
|
|
formatShortAge,
|
||
|
|
formatTimestamp,
|
||
|
|
} from './formatTimestamp';
|
||
|
|
|
||
|
|
// Fri 18 Sep 2026 14:05 local.
|
||
|
|
const now = new Date(2026, 8, 18, 14, 5).getTime();
|
||
|
|
const at = (y: number, m: number, d: number, h = 21, min = 14) =>
|
||
|
|
new Date(y, m - 1, d, h, min).getTime();
|
||
|
|
const p12 = { hour24Clock: false, dateFormatString: 'D MMM YYYY' };
|
||
|
|
const p24 = { hour24Clock: true, dateFormatString: 'YYYY-MM-DD' };
|
||
|
|
|
||
|
|
describe('formatTimestamp', () => {
|
||
|
|
it('today → time only', () => {
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 18, 9, 3), p12, 'auto', now), '09:03 AM');
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 18, 9, 3), p24, 'auto', now), '09:03');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('yesterday / tomorrow → day word + time', () => {
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 17), p24, 'auto', now), 'Yesterday 21:14');
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 19), p24, 'auto', now), 'Tomorrow 21:14');
|
||
|
|
// Just before midnight yesterday is still yesterday, not "hours ago".
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 17, 23, 59), p24, 'auto', now), 'Yesterday 23:59');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('within the last week → weekday + time', () => {
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 14), p24, 'auto', now), 'Mon 21:14');
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 12), p24, 'auto', now), 'Sat 21:14');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('a week or more → date + time in the user format', () => {
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 11), p24, 'auto', now), '2026-09-11 21:14');
|
||
|
|
assert.equal(formatTimestamp(at(2025, 1, 2), p12, 'auto', now), '2 Jan 2025 09:14 PM');
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 25), p12, 'auto', now), '25 Sep 2026 09:14 PM');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('autoDate never shows the time', () => {
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 18), p12, 'autoDate', now), 'Today');
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 17), p12, 'autoDate', now), 'Yesterday');
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 15), p12, 'autoDate', now), 'Tue');
|
||
|
|
assert.equal(formatTimestamp(at(2026, 1, 15), p12, 'autoDate', now), '15 Jan 2026');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('fixed styles ignore the relative day', () => {
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 18), p12, 'time', now), '09:14 PM');
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 18), p12, 'date', now), '18 Sep 2026');
|
||
|
|
assert.equal(formatTimestamp(at(2026, 9, 18), p24, 'dateTime', now), '2026-09-18 21:14');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('falls back to a default date format when the preference is empty', () => {
|
||
|
|
assert.equal(
|
||
|
|
formatTimestamp(at(2026, 1, 15), { hour24Clock: true, dateFormatString: '' }, 'date', now),
|
||
|
|
'15 Jan 2026',
|
||
|
|
);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('formatShortAge', () => {
|
||
|
|
it('minutes and hours today', () => {
|
||
|
|
assert.equal(formatShortAge(now - 20_000, p12, now), 'now');
|
||
|
|
assert.equal(formatShortAge(now - 5 * 60_000, p12, now), '5m');
|
||
|
|
assert.equal(formatShortAge(now - 3 * 3_600_000, p12, now), '3h');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('day words, then a short date (year dropped when current)', () => {
|
||
|
|
assert.equal(formatShortAge(at(2026, 9, 17, 23, 0), p12, now), 'Yesterday');
|
||
|
|
assert.equal(formatShortAge(at(2026, 9, 14), p12, now), 'Mon');
|
||
|
|
assert.equal(formatShortAge(at(2026, 3, 2), p12, now), '2 Mar');
|
||
|
|
assert.equal(formatShortAge(at(2026, 3, 2), p24, now), '03-02');
|
||
|
|
assert.equal(formatShortAge(at(2025, 3, 2), p12, now), '2 Mar 2025');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('formatRelativeAge', () => {
|
||
|
|
it('steps through minutes, hours, days, then the date', () => {
|
||
|
|
assert.equal(formatRelativeAge(now - 10_000, p12, now), 'just now');
|
||
|
|
assert.equal(formatRelativeAge(now - 7 * 60_000, p12, now), '7m ago');
|
||
|
|
assert.equal(formatRelativeAge(now - 5 * 3_600_000, p12, now), '5h ago');
|
||
|
|
assert.equal(formatRelativeAge(at(2026, 9, 17, 8), p12, now), 'yesterday');
|
||
|
|
assert.equal(formatRelativeAge(at(2026, 9, 15, 8), p12, now), '3d ago');
|
||
|
|
assert.equal(formatRelativeAge(at(2026, 9, 1, 8), p24, now), '2026-09-01');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('formatDayDivider', () => {
|
||
|
|
it('uses the full weekday inside the last week', () => {
|
||
|
|
assert.equal(formatDayDivider(at(2026, 9, 18), p12, now), 'Today');
|
||
|
|
assert.equal(formatDayDivider(at(2026, 9, 17), p12, now), 'Yesterday');
|
||
|
|
assert.equal(formatDayDivider(at(2026, 9, 14), p12, now), 'Monday');
|
||
|
|
assert.equal(formatDayDivider(at(2026, 9, 11), p12, now), '11 Sep 2026');
|
||
|
|
});
|
||
|
|
});
|