| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | |
| 4 | import { |
| 5 | KIND_CHOICES, |
| 6 | KIND_CHOICE_SETS, |
| 7 | bare, |
| 8 | choiceOf, |
| 9 | hasRelease, |
| 10 | kindLabel, |
| 11 | latestTag, |
| 12 | libraryPackages, |
| 13 | neverDeploys, |
| 14 | primaryLink, |
| 15 | projectChanges, |
| 16 | linksFromForm, |
| 17 | linksToShow, |
| 18 | packageLine, |
| 19 | packagePath, |
| 20 | publishGuide, |
| 21 | } from "./project-kind.ts"; |
| 22 | |
| 23 | const pkg = (over: Record<string, unknown>) => ({ |
| 24 | ecosystem: "composer" as const, |
| 25 | name: "psr/log", |
| 26 | workspace: "flagon-io", |
| 27 | latest: "3.0.2", |
| 28 | versions: 3, |
| 29 | updated_at: "2026-10-01T00:00:00Z", |
| 30 | ...over, |
| 31 | }); |
| 32 | |
| 33 | test("a package reads as its registry, its name and its latest version", () => { |
| 34 | assert.equal(packageLine(pkg({})), "Composer · psr/log 3.0.2"); |
| 35 | assert.equal(packageLine(pkg({ ecosystem: "npm", name: "ui", latest: null })), "npm · @flagon-io/ui"); |
| 36 | assert.equal(packagePath(pkg({})), "/flagon-io/-/packages/composer/psr/log"); |
| 37 | }); |
| 38 | |
| 39 | test("what a library publishes comes before an image, released ones first", () => { |
| 40 | const list = [ |
| 41 | pkg({ ecosystem: "container", name: "img", updated_at: "2026-10-05T00:00:00Z" }), |
| 42 | pkg({ name: "empty", versions: 0, updated_at: "2026-10-04T00:00:00Z" }), |
| 43 | pkg({}), |
| 44 | ]; |
| 45 | assert.deepEqual(libraryPackages(list).map((p) => p.name), ["psr/log", "empty", "img"]); |
| 46 | assert.equal(hasRelease(list), true); |
| 47 | assert.equal(hasRelease([pkg({ versions: 0 })]), false); |
| 48 | assert.equal(hasRelease([]), false); |
| 49 | }); |
| 50 | |
| 51 | test("each ecosystem links to how it publishes", () => { |
| 52 | assert.equal(publishGuide("composer")?.guide, "https://docs.g1t.sh/guides/composer/"); |
| 53 | assert.equal(publishGuide("composer")?.start, "git tag v1.0.0 && git push --tags"); |
| 54 | assert.equal(publishGuide("npm")?.start, "npm publish"); |
| 55 | assert.equal(publishGuide("go")?.guide, "https://docs.g1t.sh/guides/go/"); |
| 56 | assert.equal(publishGuide("python")?.guide, "https://docs.g1t.sh/guides/packages/"); |
| 57 | assert.equal(publishGuide(null), null); |
| 58 | }); |
| 59 | |
| 60 | test("each choice sets a kind and where it runs, and reads back", () => { |
| 61 | for (const choice of KIND_CHOICES) { |
| 62 | const set = KIND_CHOICE_SETS[choice.value]; |
| 63 | const setting = { kind: set.kind === "auto" ? null : set.kind, runs: set.runs === "auto" ? null : set.runs }; |
| 64 | assert.equal(choiceOf(setting), choice.value); |
| 65 | } |
| 66 | // Set through the API to an app, with where it runs left open: no choice says that. |
| 67 | assert.equal(choiceOf({ kind: "app", runs: null }), null); |
| 68 | }); |
| 69 | |
| 70 | test("a project's badge says what it is and where it runs", () => { |
| 71 | assert.equal(kindLabel({ kind: "app", runs: "elsewhere" }), "App, deployed elsewhere"); |
| 72 | assert.equal(kindLabel({ kind: "app", runs: "g1t" }), "App on g1t"); |
| 73 | assert.equal(kindLabel({ kind: "app", runs: null }), "App"); |
| 74 | assert.equal(kindLabel({ kind: "tool", runs: null }), "Tool"); |
| 75 | assert.equal(kindLabel({ kind: "other", runs: null }), "Project"); |
| 76 | }); |
| 77 | |
| 78 | test("links show homepage, docs, then the rest, never twice", () => { |
| 79 | const links = { |
| 80 | homepage: "https://g1t.sh/", |
| 81 | homepageInherited: false, |
| 82 | docs: "https://docs.g1t.sh", |
| 83 | custom: [ |
| 84 | { label: "Status", url: "https://status.g1t.sh" }, |
| 85 | { label: "Docs again", url: "http://docs.g1t.sh/" }, |
| 86 | ], |
| 87 | }; |
| 88 | assert.deepEqual( |
| 89 | linksToShow(links).map((link) => [link.type, link.label]), |
| 90 | [ |
| 91 | ["homepage", "g1t.sh"], |
| 92 | ["docs", "Docs"], |
| 93 | ["custom", "Status"], |
| 94 | ], |
| 95 | ); |
| 96 | // Production's address already shows on the page: the homepage pointing there is left out. |
| 97 | assert.deepEqual(linksToShow(links, ["https://g1t.sh"]).map((link) => link.type), ["docs", "custom"]); |
| 98 | assert.equal(bare("https://g1t.sh/docs/"), "g1t.sh/docs"); |
| 99 | }); |
| 100 | |
| 101 | test("an overview form changes only what it carries", () => { |
| 102 | const kind = new FormData(); |
| 103 | kind.set("choice", "elsewhere"); |
| 104 | kind.set("productionUrl", "g1t.sh"); |
| 105 | assert.deepEqual(projectChanges(kind), { kind: "app", runs: "elsewhere", productionUrl: "g1t.sh" }); |
| 106 | const about = new FormData(); |
| 107 | about.set("description", ""); |
| 108 | about.set("homepage", "https://g1t.sh"); |
| 109 | about.set("links", "rows"); |
| 110 | // Every row removed: the list is cleared, not left as it was. |
| 111 | assert.deepEqual(projectChanges(about), { description: "", homepage: "https://g1t.sh", links: [] }); |
| 112 | const bogus = new FormData(); |
| 113 | bogus.set("choice", "sometimes"); |
| 114 | assert.deepEqual(projectChanges(bogus), {}); |
| 115 | }); |
| 116 | |
| 117 | test("the latest release is the newest tag by its commit", () => { |
| 118 | assert.deepEqual( |
| 119 | latestTag([ |
| 120 | { name: "v1.0.0", commit: { authoredAt: "2026-09-01T00:00:00Z" } }, |
| 121 | { name: "v1.1.0", commit: { authoredAt: "2026-10-01T00:00:00Z" } }, |
| 122 | { name: "nightly", commit: null }, |
| 123 | ]), |
| 124 | { name: "v1.1.0", at: "2026-10-01T00:00:00Z" }, |
| 125 | ); |
| 126 | assert.equal(latestTag([]), null); |
| 127 | }); |
| 128 | |
| 129 | test("cards show production, else the homepage or docs", () => { |
| 130 | const links = { homepage: "https://acme.dev", homepageInherited: false, docs: "https://docs.acme.dev", custom: [] }; |
| 131 | assert.equal(primaryLink({ runs: "g1t", productionUrl: null, links }, "https://web-acme.g1t.page"), "https://web-acme.g1t.page"); |
| 132 | assert.equal(primaryLink({ runs: "elsewhere", productionUrl: "https://app.acme.dev", links }, null), "https://app.acme.dev"); |
| 133 | assert.equal(primaryLink({ runs: null, productionUrl: null, links }, null), "https://acme.dev"); |
| 134 | assert.equal(primaryLink({ runs: null, productionUrl: null, links: { ...links, homepage: null } }, null), "https://docs.acme.dev"); |
| 135 | assert.equal(neverDeploys({ setting: { kind: "tool", runs: null } }), true); |
| 136 | assert.equal(neverDeploys({ setting: { kind: "docs", runs: null } }), false); |
| 137 | }); |
| 138 | |
| 139 | test("custom links are read from a form's rows, blank rows left out", () => { |
| 140 | const form = new FormData(); |
| 141 | for (const [label, url] of [["Status", "status.g1t.sh"], ["", ""], ["", "npmjs.com/x"]]) { |
| 142 | form.append("linkLabel", label!); |
| 143 | form.append("linkUrl", url!); |
| 144 | } |
| 145 | assert.deepEqual(linksFromForm(form), [ |
| 146 | { label: "Status", url: "status.g1t.sh" }, |
| 147 | { label: "", url: "npmjs.com/x" }, |
| 148 | ]); |
| 149 | }); |