Files
diegosouzapw--omniroute/tests/unit/github-skills-route-validation.test.ts
2026-07-13 13:39:12 +08:00

39 lines
1.5 KiB
TypeScript

// t06 route-validation: POST /api/github-skills must validate its body with a
// Zod schema (Hard Rule #7) instead of blind request.json() destructuring.
import { test } from "node:test";
import assert from "node:assert/strict";
const { POST } = await import("../../src/app/api/github-skills/route.ts");
function post(body: unknown): Request {
return new Request("http://localhost/api/github-skills", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
});
}
test("POST github-skills: missing repoName → 400", async () => {
const res = await POST(post({ targets: ["hermes"] }) as never);
assert.equal(res.status, 400);
});
test("POST github-skills: non-array targets → 400 (was silently .map-crashing before Zod)", async () => {
const res = await POST(post({ repoName: "a/b", targets: "hermes" }) as never);
assert.equal(res.status, 400);
});
test("POST github-skills: valid body → 200 with per-target results and defaults applied", async () => {
const res = await POST(post({ repoName: "owner/skill-repo" }) as never);
assert.equal(res.status, 200);
const body = (await res.json()) as { skillName: string; results: { target: string }[] };
assert.equal(body.skillName, "skill-repo");
assert.equal(body.results[0].target, "hermes");
});
test("POST github-skills: 400 error body does not leak stack traces", async () => {
const res = await POST(post({}) as never);
const text = await res.text();
assert.ok(!text.includes("at /"), "stack trace leaked");
});