import test from "node:test"; import assert from "node:assert/strict"; import { callGet, callPost, holdPublishQueue, setupOpsCorpus } from "../_testCorpus"; // Run with: // pnpm -C editor exec tsx --test "app/api/ops/publish/route.test.ts" // // The publish route's refusals before any job, and its GET — the status. // Moved from e2e/ops-api.spec.ts (release 19, A2b); the runs each verb // enqueues are still asserted there, against the running server's queue. const corpus = await setupOpsCorpus("title-filter-channel"); await corpus.writeSite("pubsite", { cloudflareProject: "pubproj" }); const { POST, GET } = await import("./route"); await holdPublishQueue(); test.after(() => corpus.cleanup()); test("publish: refusals before any job — a never-built deploy, a preview that is not one, a key the verb does not take", async () => { const unbuilt = await callPost(POST, { verb: "deploy", siteId: "pubsite", preview: "r18" }); assert.equal(unbuilt.status, 400); assert.match(String(unbuilt.body.error), /^no build of pubsite in .* — archilyzer publish build pubsite$/); const main = await callPost(POST, { verb: "deploy", siteId: "pubsite", preview: "main" }); assert.equal(main.status, 400); assert.match(String(main.body.error), /production branch/); const verb = await callPost(POST, { verb: "launch" }); assert.equal(verb.status, 400); assert.match( String(verb.body.error), /"verb" must be one of index, build, deploy, hub, homepage, now, stale/, ); const extra = await callPost(POST, { verb: "index", siteId: "pubsite" }); assert.equal(extra.status, 400); assert.match(String(extra.body.error), /verb "index" takes no other keys/); const hubPreview = await callPost(POST, { verb: "hub", preview: "r18" }); assert.equal(hubPreview.status, 400); assert.match(String(hubPreview.body.error), /need "deploy": true/); assert.deepEqual(await corpus.listJobIds(), []); }); test("GET publish is the publish status: the index, the lane, a row per target", async () => { const res = await callGet(GET as unknown as Parameters[0]); assert.equal(res.status, 200); const status = res.body as unknown as { ok: boolean; index: { chip: { text: string } }; lane: { held: boolean; enabled: boolean }; sites: { target: string; chips: { built: { text: string } } }[]; hub: { target: string }; homepage: { target: string }; plan: { steps: { kind: string }[] }; }; assert.equal(status.ok, true); assert.equal(status.index.chip.text, "no index yet"); assert.equal(status.lane.held, false); assert.equal(status.lane.enabled, false); assert.deepEqual(status.sites.map((x) => x.target), ["pubsite"]); assert.equal(status.sites[0].chips.built.text, "update the index first"); assert.deepEqual([status.hub.target, status.homepage.target], ["_hub", "_homepage"]); assert.deepEqual(status.plan.steps.map((x) => x.kind), ["update-index"]); const anon = await callGet(GET as unknown as Parameters[0], undefined, {}, {}); assert.equal(anon.status, 401); }); test("build takes allowMissingMedia (a local build's), carried onto the queued stage", async () => { const docker = await callPost(POST, { verb: "build", runner: "docker", allowMissingMedia: true }); assert.equal(docker.status, 400); assert.match(String(docker.body.error), /"allowMissingMedia" is a local build's/); const notBool = await callPost(POST, { verb: "build", siteId: "pubsite", allowMissingMedia: "yes" }); assert.equal(notBool.status, 400); assert.match(String(notBool.body.error), /"allowMissingMedia" must be a boolean/); const deploy = await callPost(POST, { verb: "deploy", siteId: "pubsite", allowMissingMedia: true }); assert.equal(deploy.status, 400); assert.match(String(deploy.body.error), /verb "deploy" takes .* — not allowMissingMedia/); const before = new Set(await corpus.listJobIds()); const queued = await callPost(POST, { verb: "build", siteId: "pubsite", allowMissingMedia: true }); assert.equal(queued.status, 200, JSON.stringify(queued.body)); const jobs = queued.body.jobs as { kind: string; target: string; jobId: string }[]; const build = jobs.find((j) => j.target === "pubsite"); assert.ok(build, JSON.stringify(jobs)); const { readFile } = await import("node:fs/promises"); const path = await import("node:path"); const fresh = (await corpus.listJobIds()).filter((f) => !before.has(f)); const metas = await Promise.all( fresh.map((f) => readFile(path.join(corpus.transcripts, ".jobs", f), "utf8")), ); const mine = metas.find((m) => m.includes(build!.jobId)) ?? metas.join("\n"); assert.match(mine, /allowMissingMedia|allow-missing-media/, mine); });