test/shared/build-tag.test.ts
Rama main · réplica de lectura del repositorio original.
/**
* Tests for the release-tag format shared between build-edge.ts (which
* writes .build-tag) and src/shared/update.ts (which parses tags from
* GitHub releases to decide whether a newer version is available).
*
* Any drift between these two halves silently breaks self-update, so the
* roundtrip tests here are the single source of truth for the tag format.
*/
import { expect } from "@std/expect";
import { describe, it as test } from "@std/testing/bdd";
import { isoToTag } from "#shared/build-tag.ts";
import {
isNewerVersion,
parseReleaseTag,
setBuildTimestampForTest,
} from "#shared/update.ts";
const RELEASE_TAG_FORMAT = /^v\d{4}-\d{2}-\d{2}-\d{6}$/;
describe("isoToTag", () => {
test("produces the vYYYY-MM-DD-HHMMSS format the release workflow expects", () => {
expect(isoToTag("2026-03-28T14:30:22.000Z")).toBe("v2026-03-28-143022");
});
test("matches the shape parsed by parseReleaseTag", () => {
const tag = isoToTag(new Date().toISOString());
expect(tag).toMatch(RELEASE_TAG_FORMAT);
});
test("uses UTC so local timezone does not shift the tag", () => {
const iso = "2026-06-15T23:59:59.000Z";
const tag = isoToTag(iso);
expect(tag).toBe("v2026-06-15-235959");
expect(tag).toBe(isoToTag(new Date(iso).toISOString()));
});
test("zero-pads single-digit month/day/hour/minute/second", () => {
expect(isoToTag("2026-01-02T03:04:05.000Z")).toBe("v2026-01-02-030405");
});
test("rounds down sub-second precision (releases are second-resolution)", () => {
expect(isoToTag("2026-03-28T14:30:22.999Z")).toBe("v2026-03-28-143022");
});
});
describe("isoToTag / parseReleaseTag roundtrip", () => {
test("parseReleaseTag recovers the original ISO timestamp (to the second)", () => {
const iso = "2026-03-28T14:30:22.000Z";
const parsed = parseReleaseTag(isoToTag(iso));
expect(parsed).not.toBeNull();
expect(parsed!.toISOString()).toBe(iso);
});
test("roundtrips a freshly built timestamp", () => {
const now = new Date();
now.setUTCMilliseconds(0);
const parsed = parseReleaseTag(isoToTag(now.toISOString()));
expect(parsed?.getTime()).toBe(now.getTime());
});
test("isNewerVersion treats a tag built from a later timestamp as newer", () => {
setBuildTimestampForTest("2026-01-01T00:00:00.000Z");
try {
const newerTag = isoToTag("2026-02-01T00:00:00.000Z");
expect(isNewerVersion(newerTag)).toBe(true);
} finally {
setBuildTimestampForTest(null);
}
});
test("isNewerVersion treats a tag built from the same timestamp as not newer", () => {
const iso = "2026-03-28T14:30:22.000Z";
setBuildTimestampForTest(iso);
try {
expect(isNewerVersion(isoToTag(iso))).toBe(false);
} finally {
setBuildTimestampForTest(null);
}
});
test("isNewerVersion treats an earlier tag as not newer", () => {
setBuildTimestampForTest("2026-03-01T00:00:00.000Z");
try {
const olderTag = isoToTag("2026-01-01T00:00:00.000Z");
expect(isNewerVersion(olderTag)).toBe(false);
} finally {
setBuildTimestampForTest(null);
}
});
test("isNewerVersion returns false (never throws) for an unparseable tag", () => {
// Guard must short-circuit before dereferencing the null parsed date, even
// when a real build timestamp is present.
setBuildTimestampForTest("2026-01-01T00:00:00.000Z");
try {
expect(isNewerVersion("not-a-release-tag")).toBe(false);
} finally {
setBuildTimestampForTest(null);
}
});
test("isNewerVersion returns false when the build timestamp is empty", () => {
// Development/source builds carry no timestamp; nothing is ever "newer".
setBuildTimestampForTest("");
try {
const tag = isoToTag("2026-02-01T00:00:00.000Z");
expect(isNewerVersion(tag)).toBe(false);
} finally {
setBuildTimestampForTest(null);
}
});
});