| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | |
| 4 | import { |
| 5 | type ChecklistFacts, |
| 6 | agentWasAssigned, |
| 7 | dismiss, |
| 8 | dismissKey, |
| 9 | hasInstructions, |
| 10 | isDismissed, |
| 11 | productionChecklist, |
| 12 | progress, |
| 13 | } from "./checklist.ts"; |
| 14 | |
| 15 | const fresh: ChecklistFacts = { |
| 16 | base: "/acme/web", |
| 17 | hasCode: false, |
| 18 | deploysEnabled: false, |
| 19 | productionDeployed: false, |
| 20 | domains: 0, |
| 21 | previewOpened: false, |
| 22 | instructions: false, |
| 23 | agentAssigned: false, |
| 24 | }; |
| 25 | |
| 26 | test("a new project has everything to do, in order", () => { |
| 27 | const items = productionChecklist(fresh); |
| 28 | assert.deepEqual( |
| 29 | items.map((item) => item.key), |
| 30 | ["code", "deploy", "domain", "preview", "instructions", "agent"], |
| 31 | ); |
| 32 | assert.deepEqual(progress(items), { done: 0, total: 6, complete: false }); |
| 33 | }); |
| 34 | |
| 35 | test("each step is done from its own fact", () => { |
| 36 | const items = productionChecklist({ ...fresh, hasCode: true, productionDeployed: true, domains: 2 }); |
| 37 | assert.deepEqual(progress(items), { done: 3, total: 6, complete: false }); |
| 38 | const all = productionChecklist({ |
| 39 | ...fresh, |
| 40 | hasCode: true, |
| 41 | productionDeployed: true, |
| 42 | domains: 1, |
| 43 | previewOpened: true, |
| 44 | instructions: true, |
| 45 | agentAssigned: true, |
| 46 | }); |
| 47 | assert.equal(progress(all).complete, true); |
| 48 | }); |
| 49 | |
| 50 | test("unknown facts count as not done", () => { |
| 51 | const items = productionChecklist({ ...fresh, domains: null, instructions: null }); |
| 52 | assert.equal(items.find((item) => item.key === "domain")?.done, false); |
| 53 | assert.equal(items.find((item) => item.key === "instructions")?.done, false); |
| 54 | }); |
| 55 | |
| 56 | test("each step links to where it is done", () => { |
| 57 | const off = productionChecklist(fresh); |
| 58 | assert.equal(off.find((item) => item.key === "deploy")?.to, "/acme/web/settings/deployments"); |
| 59 | const on = productionChecklist({ ...fresh, deploysEnabled: true }); |
| 60 | assert.equal(on.find((item) => item.key === "deploy")?.to, "/acme/web/deployments"); |
| 61 | assert.equal(on.find((item) => item.key === "domain")?.to, "/acme/web/settings/domains"); |
| 62 | assert.equal(on.find((item) => item.key === "agent")?.to, "/acme/web/issues/new"); |
| 63 | }); |
| 64 | |
| 65 | test("instructions are AGENTS.md or CLAUDE.md at the root", () => { |
| 66 | assert.equal(hasInstructions(["README.md", "AGENTS.md"]), true); |
| 67 | assert.equal(hasInstructions(["claude.md"]), true); |
| 68 | assert.equal(hasInstructions(["README.md", "AGENTS.mdx", "docs"]), false); |
| 69 | }); |
| 70 | |
| 71 | test("g1t-agent counts as assigned from a run, a pull request or an issue", () => { |
| 72 | const none = { runAgents: ["g1t"], pullAgents: ["claude-code"], issues: [{ assignees: ["ana"], agent: null }] }; |
| 73 | assert.equal(agentWasAssigned(none), false); |
| 74 | assert.equal(agentWasAssigned({ ...none, runAgents: ["g1t-agent"] }), true); |
| 75 | assert.equal(agentWasAssigned({ ...none, pullAgents: ["g1t-agent"] }), true); |
| 76 | assert.equal(agentWasAssigned({ ...none, issues: [{ assignees: ["G1T-Agent"], agent: null }] }), true); |
| 77 | assert.equal(agentWasAssigned({ ...none, issues: [{ assignees: [], agent: "g1t-agent" }] }), true); |
| 78 | }); |
| 79 | |
| 80 | test("dismissing is remembered per project, and storage that throws is ignored", () => { |
| 81 | const map = new Map<string, string>(); |
| 82 | const store = { getItem: (key: string) => map.get(key) ?? null, setItem: (key: string, value: string) => void map.set(key, value) }; |
| 83 | assert.equal(isDismissed(() => store, "/acme/web"), false); |
| 84 | assert.equal(dismiss(() => store, "/Acme/Web"), true); |
| 85 | assert.equal(isDismissed(() => store, "/acme/web"), true); |
| 86 | assert.equal(isDismissed(() => store, "/acme/api"), false); |
| 87 | assert.equal(dismissKey("/Acme/Web"), "g1t:checklist-dismissed:/acme/web"); |
| 88 | const blocked = { |
| 89 | getItem: () => { |
| 90 | throw new Error("blocked"); |
| 91 | }, |
| 92 | setItem: () => { |
| 93 | throw new Error("blocked"); |
| 94 | }, |
| 95 | }; |
| 96 | assert.equal(isDismissed(() => blocked, "/acme/web"), false); |
| 97 | assert.equal(dismiss(() => blocked, "/acme/web"), false); |
| 98 | }); |