139 lines
4.6 KiB
TypeScript
139 lines
4.6 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { DAY } from "../src/shared/time.ts";
|
|
import {
|
|
VERSION_DAYS,
|
|
VERSIONS,
|
|
versionCaption,
|
|
versionWindow,
|
|
type GameVersion,
|
|
} from "../src/shared/versions.ts";
|
|
|
|
/**
|
|
* Version timers: a hand-kept, cited table (spec 2026-10-22). A routine resets
|
|
* only at an end the table records; an estimate is shown and never acted on.
|
|
*/
|
|
|
|
const at = (iso: string) => Date.parse(iso);
|
|
|
|
describe("VERSIONS", () => {
|
|
test("each game's versions are in order and meet end to start", () => {
|
|
const games = new Set(VERSIONS.map((v) => v.game));
|
|
for (const game of games) {
|
|
const list = VERSIONS.filter((v) => v.game === game);
|
|
list.forEach((v, i) => {
|
|
expect(Number.isFinite(at(v.start))).toBe(true);
|
|
if (v.end !== undefined) expect(at(v.end)).toBeGreaterThan(at(v.start));
|
|
const next = list[i + 1];
|
|
if (next !== undefined) {
|
|
expect(at(next.start)).toBeGreaterThan(at(v.start));
|
|
if (v.end !== undefined) expect(at(v.end)).toBe(at(next.start));
|
|
else expect(v.end).toBeDefined(); // only the newest may be open
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
test("every one cites an https page and the day it was read", () => {
|
|
for (const v of VERSIONS) {
|
|
expect(v.source.startsWith("https://")).toBe(true);
|
|
expect(v.checked).toMatch(/^\d{4}-\d{2}-\d{2}$/);
|
|
if (v.note?.toLowerCase().includes("in game") === true)
|
|
expect(v.note).toMatch(/Confirmed in game, \d{4}-\d{2}-\d{2}\./);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("versionWindow", () => {
|
|
test("inside 3.7: its number, its key, its recorded end", () => {
|
|
expect(versionWindow("wuwa", at("2026-10-22T14:30:00Z"))).toEqual({
|
|
number: "3.7",
|
|
key: "2026-09-30",
|
|
start: at("2026-09-30T03:00:00Z"),
|
|
end: at("2026-11-11T10:30:00Z"),
|
|
estimate: undefined,
|
|
nextNumber: "3.8",
|
|
});
|
|
});
|
|
|
|
test("rolls at the recorded instant, not a minute before", () => {
|
|
expect(versionWindow("wuwa", at("2026-11-11T10:29:00Z"))?.number).toBe("3.7");
|
|
expect(versionWindow("wuwa", at("2026-11-11T10:30:00Z"))).toEqual({
|
|
number: "3.8",
|
|
key: "2026-11-11",
|
|
start: at("2026-11-11T10:30:00Z"),
|
|
end: undefined,
|
|
estimate: at("2026-11-11T10:30:00Z") + 42 * DAY,
|
|
nextNumber: undefined,
|
|
});
|
|
});
|
|
|
|
test("never rolls on an estimate: far past it, still 3.8 under the same key", () => {
|
|
const w = versionWindow("wuwa", at("2027-02-01T00:00:00Z"));
|
|
expect(w?.number).toBe("3.8");
|
|
expect(w?.key).toBe("2026-11-11");
|
|
});
|
|
|
|
const open: GameVersion = {
|
|
game: "wuwa",
|
|
number: "4.0",
|
|
start: "2026-12-23T03:00:00Z",
|
|
next: "4.1",
|
|
source: "https://example.org/",
|
|
checked: "2026-10-22",
|
|
};
|
|
|
|
test("a newest entry with no end is open, estimated from its own start", () => {
|
|
const w = versionWindow("wuwa", at("2026-12-30T00:00:00Z"), [open]);
|
|
expect(w).toEqual({
|
|
number: "4.0",
|
|
key: "2026-12-23",
|
|
start: at(open.start),
|
|
end: undefined,
|
|
estimate: at(open.start) + 42 * DAY,
|
|
nextNumber: "4.1",
|
|
});
|
|
});
|
|
|
|
test("no usual length, no estimate", () => {
|
|
expect(versionWindow("wuwa", at("2026-12-30T00:00:00Z"), [open], {})?.estimate).toBeUndefined();
|
|
});
|
|
|
|
test("a game with no versions has no window", () => {
|
|
expect(versionWindow("genshin", at("2026-10-22T00:00:00Z"))).toBeUndefined();
|
|
});
|
|
|
|
test("WuWa's usual length is six weeks", () => {
|
|
expect(VERSION_DAYS.wuwa).toBe(42);
|
|
});
|
|
});
|
|
|
|
describe("versionCaption", () => {
|
|
const base = { key: "2026-11-11", start: at("2026-11-11T10:30:00Z") };
|
|
const estimate = at("2026-12-23T10:30:00Z");
|
|
|
|
test("a recorded end names the next version and the day", () => {
|
|
const w = versionWindow("wuwa", at("2026-10-22T14:30:00Z"))!;
|
|
expect(versionCaption(w, at("2026-10-22T14:30:00Z"))).toBe("resets with 3.8 · 11 Nov");
|
|
});
|
|
|
|
test("no recorded end: the next version, if named, and the estimate", () => {
|
|
const now = at("2026-11-20T00:00:00Z");
|
|
expect(versionCaption({ ...base, number: "3.8", nextNumber: "3.9", estimate }, now)).toBe(
|
|
"resets with next version (3.9) · expected ~23 Dec",
|
|
);
|
|
expect(versionCaption({ ...base, number: "3.8", estimate }, now)).toBe(
|
|
"resets with next version · expected ~23 Dec",
|
|
);
|
|
});
|
|
|
|
test("past the estimate, it says the end is not yet confirmed", () => {
|
|
expect(versionCaption({ ...base, estimate }, at("2027-01-02T00:00:00Z"))).toBe(
|
|
"resets with next version · expected ~23 Dec, not yet confirmed",
|
|
);
|
|
});
|
|
|
|
test("no estimate at all", () => {
|
|
expect(versionCaption(base, at("2026-11-20T00:00:00Z"))).toBe("resets with next version");
|
|
});
|
|
});
|