| 1 | import { test } from "node:test"; |
| 2 | import assert from "node:assert/strict"; |
| 3 | |
| 4 | import { cleanCard } from "./cards.ts"; |
| 5 | |
| 6 | test("a card needs a kind and a title", () => { |
| 7 | assert.equal(cleanCard(null), null); |
| 8 | assert.equal(cleanCard("card"), null); |
| 9 | assert.equal(cleanCard({ kind: "session" }), null); |
| 10 | assert.equal(cleanCard({ title: "Fix the login" }), null); |
| 11 | assert.deepEqual(cleanCard({ kind: " session ", title: " Fix the login " }), { |
| 12 | kind: "session", |
| 13 | title: "Fix the login", |
| 14 | detail: null, |
| 15 | state: null, |
| 16 | href: null, |
| 17 | }); |
| 18 | }); |
| 19 | |
| 20 | test("links stay on the site", () => { |
| 21 | assert.equal(cleanCard({ kind: "pull", title: "x", href: "/acme/web/pull/1" })?.href, "/acme/web/pull/1"); |
| 22 | assert.equal(cleanCard({ kind: "pull", title: "x", href: "https://evil.example" })?.href, null); |
| 23 | assert.equal(cleanCard({ kind: "pull", title: "x", href: "//evil.example" })?.href, null); |
| 24 | }); |
| 25 | |
| 26 | test("fields keep labelled values and drop the rest", () => { |
| 27 | const card = cleanCard({ |
| 28 | kind: "draft_issue", |
| 29 | title: "x", |
| 30 | fields: [{ label: "Repository", value: "acme/web" }, { label: "Labels" }, { value: "orphan" }, "nope", null, { label: " ", value: "x" }], |
| 31 | }); |
| 32 | assert.deepEqual(card?.fields, [{ label: "Repository", value: "acme/web" }]); |
| 33 | assert.equal(cleanCard({ kind: "x", title: "x", fields: [] })?.fields, undefined); |
| 34 | const many = Array.from({ length: 12 }, (_, i) => ({ label: `L${i}`, value: "v" })); |
| 35 | assert.equal(cleanCard({ kind: "x", title: "x", fields: many })?.fields?.length, 8); |
| 36 | }); |
| 37 | |
| 38 | test("actions keep valid ones, normalised, and drop invalid ones and outside links", () => { |
| 39 | const card = cleanCard({ |
| 40 | kind: "session", |
| 41 | title: "x", |
| 42 | owner: "agents", |
| 43 | ref: "ses_1", |
| 44 | actions: [ |
| 45 | { id: "approve", label: "Approve more", style: "primary", input: { kind: "money", label: "Amount", initial: "2.00" } }, |
| 46 | { id: "stop", label: "Stop", style: "danger", confirm: "Stop this session?" }, |
| 47 | { id: "message", label: "Message", style: "loud", input: { kind: "voice", label: "x" } }, |
| 48 | { id: "Bad Id", label: "x" }, |
| 49 | { id: "nolabel" }, |
| 50 | { id: "open", label: "Open", href: "https://elsewhere.example" }, |
| 51 | "nope", |
| 52 | ], |
| 53 | }); |
| 54 | assert.equal(card?.owner, "agents"); |
| 55 | assert.equal(card?.ref, "ses_1"); |
| 56 | assert.deepEqual(card?.actions, [ |
| 57 | { id: "approve", label: "Approve more", style: "primary", confirm: null, input: { kind: "money", label: "Amount", placeholder: null, initial: "2.00" }, href: null }, |
| 58 | { id: "stop", label: "Stop", style: "danger", confirm: "Stop this session?", input: null, href: null }, |
| 59 | { id: "message", label: "Message", style: "default", confirm: null, input: null, href: null }, |
| 60 | ]); |
| 61 | }); |
| 62 | |
| 63 | test("without an owner only link actions are kept", () => { |
| 64 | const card = cleanCard({ |
| 65 | kind: "pull", |
| 66 | title: "x", |
| 67 | owner: "github", |
| 68 | actions: [ |
| 69 | { id: "merge", label: "Merge", style: "primary" }, |
| 70 | { id: "open", label: "Open", href: "/acme/web/pull/1" }, |
| 71 | ], |
| 72 | }); |
| 73 | assert.equal(card?.owner, undefined); |
| 74 | assert.equal(card?.ref, undefined); |
| 75 | assert.deepEqual(card?.actions, [{ id: "open", label: "Open", style: "default", confirm: null, input: null, href: "/acme/web/pull/1" }]); |
| 76 | }); |
| 77 | |
| 78 | test("a card offers at most five actions", () => { |
| 79 | const actions = Array.from({ length: 9 }, (_, i) => ({ id: `a${i}`, label: `A${i}` })); |
| 80 | assert.equal(cleanCard({ kind: "x", title: "x", owner: "agents", actions })?.actions?.length, 5); |
| 81 | }); |