format-relative-date.test.ts2.9 KBView on GitHub
/**
 * formatRelativeDate, west of UTC.
 *
 * The sibling suite covers the same function in UTC and passes on the broken code, because
 * the bug is a DISAGREEMENT between two calendar readings and in UTC there is nothing to
 * disagree about: the sub-24h branch asked date-fns `isToday` (the LOCAL calendar) while the
 * day branch read UTC components. Every CI runner is UTC, so nothing in the suite could see
 * it, and it reached users instead — a US rep opening a deal just after 8pm saw a touch from
 * this afternoon labelled "Today" rather than "3h ago".
 *
 * 04:37Z on the 31st is 00:37 on the 31st in New York; a touch 3h41m earlier is 20:55 on the
 * 30th locally but still the 31st in UTC. That is the window where the two readings differ,
 * and it is most of the evening for every timezone west of UTC.
 *
 * Run by `pnpm --filter @zero/mail test:tz`, which sets TZ before the process starts — the
 * only point at which it can be set, since V8 caches the zone on first use.
 */
import { formatRelativeDate, parseAsUTC } from '@/modules/crm/utils/time';

afterEach(() => {
  jest.useRealTimers();
});

function freezeAt(iso: string) {
  jest.useFakeTimers({ doNotFake: ['performance'] }).setSystemTime(new Date(iso));
}

describe('formatRelativeDate west of UTC', () => {
  it('runs in the timezone this file asked for', () => {
    // Guards the harness itself: if the custom environment ever stops applying, these tests
    // would silently become duplicates of the UTC suite and pass on the broken code again.
    expect(new Date('2026-07-31T00:55:49Z').getDate()).toBe(30);
  });

  it('says how many hours ago, not "Today"', () => {
    freezeAt('2026-07-31T04:37:36Z');

    const lastTouch = parseAsUTC('2026-07-31 00:55:49')!.toISOString();

    expect(formatRelativeDate(lastTouch)).toBe('3h ago');
  });

  it('reads the calendar day the same way in both branches', () => {
    // The hour branch and the day branch must never disagree about which day the target is
    // on; a timestamp falling between them is what produced the wrong label.
    freezeAt('2026-07-31T04:37:36Z');

    const lastTouch = parseAsUTC('2026-07-31 00:55:49')!.toISOString();

    expect(formatRelativeDate(lastTouch, { dayGranularityOnly: true })).toBe('Today');
  });

  it('never labels a past timestamp as a future one', () => {
    freezeAt('2026-07-31T04:37:36Z');

    const lastTouch = parseAsUTC('2026-07-31 00:55:49')!.toISOString();

    expect(formatRelativeDate(lastTouch)).not.toBe('Tomorrow');
    expect(formatRelativeDate(lastTouch, { dayGranularityOnly: true })).not.toBe('Tomorrow');
  });

  it('keeps a midnight-UTC calendar date on its own day', () => {
    // The case the UTC day components exist for, asserted where it actually bites: a date-only
    // value stored at midnight UTC is "yesterday" locally for every US viewer.
    freezeAt('2026-03-06T04:00:00Z');

    expect(formatRelativeDate('2026-03-06T00:00:00Z', { dayGranularityOnly: true })).toBe('Today');
  });
});