Skip to content

g1t/apps/web/app/lib/labels.test.ts

70 lines3,246 bytesCodeBlame
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import {
5 chipStyle,
6 colorsOf,
7 dayInWords,
8 dueInWords,
9 isOverdue,
10 listFilters,
11 matchLabels,
12 percentDone,
13 tidyColor,
14 tidyLabelName,
15 withFilter,
16} from "./labels.ts";
17
18test("colors are six hex digits however they were written", () => {
19 assert.equal(tidyColor("#D73A4A"), "d73a4a");
20 assert.equal(tidyColor("fc0"), "ffcc00");
21 assert.equal(tidyColor("red"), null);
22 assert.equal(tidyColor(undefined), null);
23});
24
25test("a chip is tinted with its label's color, and neutral without one", () => {
26 const style = chipStyle("d73a4a");
27 assert.match(style.backgroundColor!, /#d73a4a/);
28 assert.match(style.color!, /var\(--color-fg\)/);
29 assert.deepEqual(chipStyle("nope"), {});
30 assert.deepEqual(colorsOf([{ name: "bug", color: "d73a4a" }]), { bug: "d73a4a" });
31});
32
33test("labels are found by name or description", () => {
34 const labels = [
35 { name: "bug", description: "Something isn't working" },
36 { name: "good first issue", description: "Good for newcomers" },
37 ];
38 assert.deepEqual(matchLabels(labels, "first").map((l) => l.name), ["good first issue"]);
39 assert.deepEqual(matchLabels(labels, "working").map((l) => l.name), ["bug"]);
40 assert.equal(matchLabels(labels, " ").length, 2);
41 assert.equal(tidyLabelName(" Good First Issue "), "good first issue");
42});
43
44test("a milestone's progress and due date read as words", () => {
45 assert.equal(percentDone({ openItems: 3, closedItems: 1 }), 25);
46 assert.equal(percentDone({ openItems: 0, closedItems: 0 }), 0);
47 assert.equal(dayInWords("2026-10-14"), "October 14, 2026");
48 const today = new Date("2026-10-07T12:00:00Z");
49 assert.equal(dueInWords({ dueOn: "2026-10-14", state: "open" }, today), "Due by October 14, 2026");
50 assert.equal(dueInWords({ dueOn: "2026-10-05", state: "open" }, today), "Past due by 2 days");
51 assert.equal(dueInWords({ dueOn: "2026-10-05", state: "closed" }, today), "Due by October 5, 2026");
52 assert.equal(dueInWords({ dueOn: null, state: "open" }, today), null);
53 assert.equal(isOverdue({ dueOn: "2026-10-05", state: "open" }, today), true);
54 assert.equal(isOverdue({ dueOn: "2026-10-07", state: "open" }, today), false);
55});
56
57test("filters come from the address, and q wins", () => {
58 const plain = listFilters(new URLSearchParams("label=Bug&milestone=3&state=closed"));
59 assert.deepEqual(plain, { label: "bug", milestone: 3, state: "closed", base: "" });
60 const typed = listFilters(new URLSearchParams({ q: 'label:"good first issue" milestone:2 is:open base:release' }));
61 assert.deepEqual(typed, { label: "good first issue", milestone: 2, state: "open", base: "release" });
62 assert.deepEqual(listFilters(new URLSearchParams()), { label: "", milestone: null, state: "open", base: "" });
63});
64
65test("changing one filter keeps the others", () => {
66 const current = new URLSearchParams("state=closed&label=bug");
67 assert.equal(withFilter("/a/b/issues", current, "milestone", "3"), "/a/b/issues?state=closed&label=bug&milestone=3");
68 assert.equal(withFilter("/a/b/issues", current, "label", null), "/a/b/issues?state=closed");
69 assert.equal(withFilter("/a/b/issues", new URLSearchParams("label=bug"), "label", ""), "/a/b/issues");
70});