Ctrl K
ComunidadGuías…

lib/changelog.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { describe, expect, it } from "vitest";
import {
  CHANGELOG_LAST_MODIFIED,
  RECENT_CHANGELOG_DAYS,
  formatChangelogAge,
  hasRecentChangelog,
  mergeChangelogReleases,
} from "./changelog";
import type { Locale } from "@/i18n/config";
import type { ChangelogReleaseSummary } from "./changelog-types";

it("keeps historical anchors chronological and unique across successive older pages", () => {
  const release = (version: string, publishedAt: string): ChangelogReleaseSummary => ({
    version, publishedAt, title: version, summary: "", layout: "compact", features: [],
  });
  const latest = release("0.11.0", "2026-10-03T12:00:00Z");
  const anchor = release("0.9.5", "2026-07-01T12:00:00Z");
  const middle = release("0.10.0", "2026-09-01T12:00:00Z");
  const older = release("0.9.0", "2026-06-01T12:00:00Z");
  const initial = [latest];
  const anchored = mergeChangelogReleases(initial, [anchor]);
  const paginated = mergeChangelogReleases(anchored, [middle]);
  expect(paginated).toEqual([latest, middle, anchor]);
  expect(mergeChangelogReleases(paginated, [anchor, older])).toEqual([latest, middle, anchor, older]);
  expect(initial).toEqual([latest]);
  expect(anchored).toEqual([latest, anchor]);
});

/**
 * The blue dot in the account menu. The terminals are tested relative to
 * the last input: otherwise the test would turn off by itself as it ages.
 */
describe("changelog freshness", () => {
  const DAY = 24 * 60 * 60 * 1000;
  const latest = Date.parse(`${CHANGELOG_LAST_MODIFIED}T00:00:00Z`);

  it("lights up on release day, including before UTC midnight", () => {
    expect(hasRecentChangelog(latest)).toBe(true);
    // Paris, 1 a.m. on the day of release: again the day before in UTC.
    expect(hasRecentChangelog(latest - 2 * 60 * 60 * 1000)).toBe(true);
  });

  it("lasts five days, not six", () => {
    expect(hasRecentChangelog(latest + RECENT_CHANGELOG_DAYS * DAY - 1)).toBe(
      true,
    );
    expect(hasRecentChangelog(latest + RECENT_CHANGELOG_DAYS * DAY)).toBe(
      false,
    );
  });
});

/** The age displayed instead of the date, on the public page and in the modal. */
describe("changelog age", () => {
  const DAY = 24 * 60 * 60 * 1000;
  const published = Date.parse("2026-07-20T00:00:00Z");
  const age = (now: number, locale: Locale = "en") =>
    formatChangelogAge("2026-07-20", locale, now);

  it("counts in days in the served language", () => {
    expect(age(published)).toBe("today");
    expect(age(published + DAY)).toBe("yesterday");
    expect(age(published + 3 * DAY)).toBe("3 days ago");
    expect(age(published + 3 * DAY, "fr")).toBe("il y a 3 jours");
    expect(age(published + 3 * DAY, "de")).toBe("vor 3 Tagen");
    expect(age(published + 3 * DAY, "pt-BR")).toBe("há 3 dias");
    expect(age(published + 3 * DAY, "it")).toBe("3 giorni fa");
    expect(age(published + 3 * DAY, "es")).toBe("hace 3 días");
  });

  /**
   * Dates are written in UTC-midnight: a reader east of UTC opens the
   * page while today's delivery is still "in the future". Without
   * floor, the page would say "in 4 hours".
   */
  it("never describes a publication as being in the future", () => {
    expect(age(published - 4 * 60 * 60 * 1000)).toBe("today");
  });

  it("switches to months and then years instead of lining up days", () => {
    expect(age(published + 29 * DAY)).toBe("29 days ago");
    expect(age(published + 40 * DAY)).toBe("last month");
    expect(age(published + 200 * DAY)).toBe("6 months ago");
    expect(age(published + 400 * DAY)).toBe("last year");
  });
});