Skip to content

g1t/services/projects/src/links.test.ts

59 lines3,183 bytesCodeBlame
1import { test } from "node:test";
2import assert from "node:assert/strict";
3
4import { cleanLinks, cleanUrl, projectLinks, storedLinks } from "./links.ts";
5
6test("an address is http or https, with https added when none is given", () => {
7 assert.deepEqual(cleanUrl(" g1t.sh "), { ok: true, value: "https://g1t.sh" });
8 assert.deepEqual(cleanUrl("HTTP://docs.example.com/guide?x=1#a"), { ok: true, value: "http://docs.example.com/guide?x=1#a" });
9 assert.deepEqual(cleanUrl("example.com:8080/app"), { ok: true, value: "https://example.com:8080/app" });
10 assert.deepEqual(cleanUrl(""), { ok: true, value: null });
11 assert.deepEqual(cleanUrl(null), { ok: true, value: null });
12});
13
14test("anything else is refused, naming what it is", () => {
15 for (const bad of ["javascript:alert(1)", "mailto:a@example.com", "ftp://example.com", "localhost:3000", "https://", "https://exa mple.com", "https://user@example.com", "https://.com"]) {
16 assert.equal(cleanUrl(bad).ok, false, bad);
17 }
18 assert.deepEqual(cleanUrl("ftp://x.io", "The homepage"), { ok: false, message: "The homepage is an http or https address." });
19 assert.equal(cleanUrl(`https://example.com/${"a".repeat(260)}`).ok, false);
20});
21
22test("links: blank rows dropped, labels from the host, at most ten", () => {
23 assert.deepEqual(
24 cleanLinks([
25 { label: " Status ", url: "status.example.com" },
26 { label: "", url: "" },
27 { label: "", url: "https://npmjs.com/package/x" },
28 ]),
29 {
30 ok: true,
31 value: [
32 { label: "Status", url: "https://status.example.com" },
33 { label: "npmjs.com", url: "https://npmjs.com/package/x" },
34 ],
35 },
36 );
37 assert.deepEqual(cleanLinks([{ label: "Chat", url: "" }]), { ok: false, message: "Give Chat an address." });
38 assert.deepEqual(cleanLinks([{ label: "Chat", url: "irc://x.io" }]), { ok: false, message: "The address for Chat is an http or https address." });
39 assert.equal(cleanLinks([{ label: "x".repeat(41), url: "x.io" }]).ok, false);
40 const eleven = Array.from({ length: 11 }, (_, i) => ({ label: `L${i}`, url: `l${i}.io` }));
41 assert.equal(cleanLinks(eleven).ok, false);
42 assert.equal(cleanLinks(eleven.slice(0, 10)).ok, true);
43 assert.equal(cleanLinks("nope").ok, false);
44});
45
46test("stored links that cannot be read are none", () => {
47 assert.deepEqual(storedLinks('[{"label":"A","url":"https://a.io"},{"label":1}]'), [{ label: "A", url: "https://a.io" }]);
48 assert.deepEqual(storedLinks("not json"), []);
49 assert.deepEqual(storedLinks(null), []);
50});
51
52test("a repository's own project follows its website until it has a homepage of its own", () => {
53 const row = { is_primary: 1, homepage: null, repo_website: "https://example.com", docs_url: null, links: null };
54 assert.deepEqual(projectLinks(row), { homepage: "https://example.com", homepageInherited: true, docs: null, custom: [] });
55 assert.equal(projectLinks({ ...row, homepage: "https://g1t.sh" }).homepage, "https://g1t.sh");
56 assert.equal(projectLinks({ ...row, homepage: "https://g1t.sh" }).homepageInherited, false);
57 // Another project in the same repository does not.
58 assert.deepEqual(projectLinks({ ...row, is_primary: 0 }).homepage, null);
59});