1234import { afterAll, beforeAll, describe, expect, setSystemTime, test } from "bun:test";5import { Browser, type Instance, instance } from "./browser.ts";6import { makeRepos, writeRelease } from "./fixture.ts";78describe("download analytics (§24)", () => {9 let inst: Instance;10 let operator: Browser;11 const at = (iso: string) => setSystemTime(new Date(iso));12 const download = (repo: string, platform: string) =>13 inst.app.request(`/${repo}/releases/1.0.0/${platform}`);14 const page = async (query = "") => (await operator.get(`/admin/downloads${query}`)).text();1516 beforeAll(async () => {17 at("2026-09-30T12:00:00Z");18 const repos = await makeRepos(["app", "tools"]);19 for (const repo of ["app", "tools"]) {20 await writeRelease(repos.bucketDir, repo, {21 version: "1.0.0",22 save: repos.saves[repo] as string,23 files: [24 { platform: "linux-x86_64", name: repo, bytes: new Uint8Array([1]) },25 { platform: "macos-aarch64", name: repo, bytes: new Uint8Array([2]) },26 ],27 });28 }29 inst = await instance(repos.bucketDir);30 operator = new Browser(inst.app);31 await operator.signIn();32 for (const repo of ["app", "tools"])33 await operator.post(`/admin/repos/${repo}`, { public: "1" });34 at("2025-08-01T12:00:00Z");35 await download("app", "linux-x86_64");36 at("2026-09-28T23:59:00Z");37 await download("app", "linux-x86_64");38 await download("app", "macos-aarch64");39 at("2026-09-30T00:01:00Z");40 await download("app", "linux-x86_64");41 await download("tools", "linux-x86_64");42 });43 afterAll(() => setSystemTime());4445 test("each download counts toward its repo's UTC day, and days past 400 are dropped", () => {46 const days = inst.kepr47 .query("SELECT repo, day, count FROM download_days ORDER BY day, repo")48 .all();49 expect(days).toEqual([50 { repo: "app", day: "2026-09-28", count: 2 },51 { repo: "app", day: "2026-09-30", count: 1 },52 { repo: "tools", day: "2026-09-30", count: 1 },53 ]);54 });5556 test("the section shows 30 days, each repo's totals and the top files", async () => {57 const html = await page();58 expect(html).toContain('<meter min="0" max="2" value="2"');59 expect(html).toContain("2026-09-28");60 expect(html).not.toContain("2026-08-31");61 expect(html).toContain("2026-09-01");62 expect(html).toMatch(/app<\/a>\s*<span[^>]*>4 downloads · 3 in 30 days<\/span>/);63 expect(html.indexOf("app 1.0.0 linux-x86_64")).toBeLessThan(64 html.indexOf("tools 1.0.0 linux-x86_64"),65 );66 });6768 test("one repo narrows the days, and an unknown one narrows nothing", async () => {69 const tools = await page("?repo=tools");70 expect(tools).toContain('<meter min="0" max="1" value="1"');71 expect(tools).not.toContain('value="2"');72 expect(await page("?repo=nowhere")).toContain('<meter min="0" max="2" value="2"');73 });74});