import assert from "node:assert/strict"; import test from "node:test"; import { DEEPSEEK, GLM } from "../src/schedules.ts"; import { fmtWhen, reportLines, resolveTimezone, summarize, tzOffsetMinutes, widgetSegments, } from "../src/render.ts"; test("resolveTimezone", async (t) => { await t.test("auto resolves to a non-empty IANA zone", () => { const tz = resolveTimezone("auto"); assert.ok(tz.length > 0 && tz !== "auto"); }); await t.test("UTC passes through in any case", () => { assert.equal(resolveTimezone("UTC"), "UTC"); assert.equal(resolveTimezone("utc"), "UTC"); }); await t.test("valid IANA zone passes through", () => { assert.equal(resolveTimezone("Asia/Yekaterinburg"), "Asia/Yekaterinburg"); }); await t.test("invalid zone falls back to auto", () => { assert.equal(resolveTimezone("Mars/Olympus"), resolveTimezone("auto")); }); }); test("tzOffsetMinutes", async (t) => { await t.test("Asia/Yekaterinburg is UTC+5", () => { assert.equal(tzOffsetMinutes(new Date("2026-08-28T04:00:00Z"), "Asia/Yekaterinburg"), 300); }); await t.test("UTC is 0", () => { assert.equal(tzOffsetMinutes(new Date("2026-08-28T04:00:00Z"), "UTC"), 0); }); }); test("fmtWhen", async (t) => { await t.test("same local day → clock only", () => { const now = new Date("2026-08-28T04:00:00Z"); assert.equal(fmtWhen(new Date("2026-08-28T04:00:00Z"), now, "Asia/Yekaterinburg"), "09:00"); }); await t.test("other local day → weekday and clock", () => { const now = new Date("2026-08-28T10:30:00Z"); // Fri assert.equal(fmtWhen(new Date("2026-08-31T01:00:00Z"), now, "Asia/Yekaterinburg"), "Mon 06:00"); }); }); test("widgetSegments", async (t) => { const now = new Date("2026-08-28T00:30:00Z"); // Fri 05:30 in +05 = 08:30 Beijing: nobody in peak const tz = "Asia/Yekaterinburg"; await t.test("hidden when show=peak and nobody is in peak", () => { const statuses = summarize([DEEPSEEK, GLM], now); assert.equal(widgetSegments(statuses, now, tz, "peak"), null); }); await t.test("show=always lists off-peak providers dimmed", () => { const statuses = summarize([DEEPSEEK, GLM], now); const segments = widgetSegments(statuses, now, tz, "always"); assert.ok(segments); assert.ok(segments.every((s) => s.tone === "dim")); assert.ok(segments.some((s) => s.text.includes("DS"))); }); await t.test("peak providers carry a warning tone and an until-clause", () => { const statuses = summarize([DEEPSEEK], new Date("2026-08-24T02:00:00Z")); // Mon 07:00 +05 → DS peak const segments = widgetSegments(statuses, now, tz, "peak"); assert.ok(segments); const peak = segments.find((s) => s.tone === "warning"); assert.ok(peak); assert.match(peak.text, /^⚡ DS until /); }); }); test("reportLines", () => { const now = new Date("2026-08-28T04:00:00Z"); const lines = reportLines(summarize([DEEPSEEK, GLM], now), now, "Asia/Yekaterinburg"); assert.ok(lines[0].includes("Asia/Yekaterinburg")); assert.ok(lines.some((l) => l.includes("DS") || l.includes("DeepSeek"))); // DS windows 09:00-12:00, 14:00-18:00 UTC+8 → 06:00-09:00, 11:00-15:00 in +05 assert.ok(lines.some((l) => l.includes("06:00-09:00, 11:00-15:00"))); assert.ok(lines.some((l) => l.includes("api-docs.deepseek.com"))); assert.ok(lines.some((l) => l.includes("docs.z.ai"))); });