Skip to content

g1t/apps/web/app/lib/project-list.test.ts

148 lines5,982 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Navigation: the workspace's own page with tabs, pins and recent in the sidebar1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import {
5 DEFAULT_QUERY,
6 type Listed,
7 PAGE_SIZE,
8 facetsOf,
9 filterProjects,
10 isFiltered,
11 nextRow,
12 pageOf,
13 projectQueryString,
14 readProjectQuery,
15} from "./project-list.ts";
16
17function project(slug: string, more: Partial<Listed> = {}): Listed {
18 return {
19 id: `prj_${slug}`,
20 slug,
21 name: slug,
22 description: null,
23 private: false,
24 archived: false,
25 kind: "app",
26 ecosystem: null,
27 updatedAt: "2026-10-01T00:00:00.000Z",
28 pushedAt: null,
29 activity: 0,
30 deploying: false,
31 ...more,
32 };
33}
34
35const q = (search: string) => readProjectQuery(new URLSearchParams(search));
36
37test("an empty address is the default list", () => {
38 assert.deepEqual(q(""), DEFAULT_QUERY);
39 assert.equal(projectQueryString(DEFAULT_QUERY), "");
40 assert.equal(isFiltered(DEFAULT_QUERY), false);
41});
42
43test("what the address says is read, and nonsense is the default", () => {
44 const query = q("q=%20api%20&visibility=private&kind=library&language=Rust&deployments=on&archived=only&sort=active&view=grid&page=3");
45 assert.deepEqual(query, {
46 q: "api",
47 visibility: "private",
48 kind: "library",
49 language: "Rust",
50 deployments: true,
51 archived: "only",
52 sort: "active",
53 view: "grid",
54 page: 3,
55 });
56 assert.deepEqual(q("visibility=secret&sort=random&page=-2&view=table"), DEFAULT_QUERY);
57});
58
59test("the address round-trips, and a change goes back to page one", () => {
60 const query = q("q=web&sort=name&page=4");
61 assert.equal(projectQueryString(query, { page: 4 }), "?q=web&sort=name&page=4");
62 assert.equal(projectQueryString(query, { kind: "library" }), "?q=web&kind=library&sort=name");
63 assert.deepEqual(q(projectQueryString(query, { page: 4 }).slice(1)), query);
64});
65
66test("archived projects are left out unless asked for", () => {
67 const list = [project("live"), project("old", { archived: true })];
68 assert.deepEqual(filterProjects(list, DEFAULT_QUERY).map((p) => p.slug), ["live"]);
69 assert.deepEqual(filterProjects(list, { ...DEFAULT_QUERY, archived: "only" }).map((p) => p.slug), ["old"]);
70 assert.equal(filterProjects(list, { ...DEFAULT_QUERY, archived: "include" }).length, 2);
71});
72
73test("filters narrow by visibility, kind, language and deployments", () => {
74 const list = [
75 project("site", { deploying: true, ecosystem: "npm" }),
76 project("lib", { kind: "library", ecosystem: "cargo", private: true }),
77 project("tool", { ecosystem: "go" }),
78 ];
79 const slugs = (change: object) => filterProjects(list, { ...DEFAULT_QUERY, ...change }).map((p) => p.slug).sort();
80 assert.deepEqual(slugs({ visibility: "private" }), ["lib"]);
81 assert.deepEqual(slugs({ visibility: "public" }), ["site", "tool"]);
82 assert.deepEqual(slugs({ kind: "library" }), ["lib"]);
83 assert.deepEqual(slugs({ language: "Rust" }), ["lib"]);
84 assert.deepEqual(slugs({ language: "JavaScript" }), ["site"]);
85 assert.deepEqual(slugs({ deployments: true }), ["site"]);
86});
87
88test("search matches every word, in the name, slug or description, names that start with it first", () => {
89 const list = [
90 project("docs-site", { name: "Docs site", description: "The API reference" }),
91 project("api", { name: "API" }),
92 project("billing", { description: "charges cards" }),
93 ];
94 assert.deepEqual(filterProjects(list, { ...DEFAULT_QUERY, q: "api" }).map((p) => p.slug), ["api", "docs-site"]);
95 assert.deepEqual(filterProjects(list, { ...DEFAULT_QUERY, q: "api reference" }).map((p) => p.slug), ["docs-site"]);
96 assert.deepEqual(filterProjects(list, { ...DEFAULT_QUERY, q: "CARDS" }).map((p) => p.slug), ["billing"]);
97});
98
99test("each sort orders as it says, ties by name", () => {
100 const list = [
101 project("b", { updatedAt: "2026-10-01T00:00:00Z", pushedAt: "2026-10-05T00:00:00Z", activity: 1 }),
102 project("a", { updatedAt: "2026-10-03T00:00:00Z", activity: 9 }),
103 project("c", { updatedAt: "2026-10-02T00:00:00Z", pushedAt: "2026-10-04T00:00:00Z", activity: 1 }),
104 ];
105 const order = (sort: string) => filterProjects(list, { ...DEFAULT_QUERY, sort: sort as never }).map((p) => p.slug);
106 assert.deepEqual(order("name"), ["a", "b", "c"]);
107 // Updated is the later of its own changes and its last push.
108 assert.deepEqual(order("updated"), ["b", "c", "a"]);
109 assert.deepEqual(order("pushed"), ["b", "c", "a"]);
110 assert.deepEqual(order("active"), ["a", "b", "c"]);
111});
112
113test("pages hold PAGE_SIZE, and a page past the end is the last", () => {
114 const list = Array.from({ length: 412 }, (_, i) => i);
115 const first = pageOf(list, 1);
116 assert.equal(first.items.length, PAGE_SIZE);
117 assert.equal(first.pages, 14);
118 assert.deepEqual([first.from, first.to], [1, 30]);
119 const last = pageOf(list, 99);
120 assert.equal(last.page, 14);
121 assert.deepEqual([last.from, last.to], [391, 412]);
122 assert.deepEqual(pageOf([], 1), { items: [], page: 1, pages: 1, from: 0, to: 0 });
123});
124
125test("facets count the whole workspace", () => {
126 const facets = facetsOf([
127 project("a", { ecosystem: "npm", deploying: true }),
128 project("b", { ecosystem: "npm", private: true, kind: "library" }),
129 project("c", { ecosystem: "go", archived: true }),
Merge main: Deployments panel in the About, project homepage, both sides' operations130 project("d", { kind: "tool" }),
Navigation: the workspace's own page with tabs, pins and recent in the sidebar131 ]);
Merge main: Deployments panel in the About, project homepage, both sides' operations132 assert.deepEqual(facets.visibility, { public: 3, private: 1 });
133 assert.deepEqual(facets.kind, { app: 2, library: 1, tool: 1, docs: 0, other: 0 });
Navigation: the workspace's own page with tabs, pins and recent in the sidebar134 assert.deepEqual(facets.languages, [{ name: "JavaScript", count: 2 }, { name: "Go", count: 1 }]);
135 assert.equal(facets.deploying, 1);
136 assert.equal(facets.archived, 1);
137});
138
139test("the keyboard moves through rows and stops at the ends", () => {
140 assert.equal(nextRow("ArrowDown", -1, 3), 0);
141 assert.equal(nextRow("j", 0, 3), 1);
142 assert.equal(nextRow("ArrowDown", 2, 3), 2);
143 assert.equal(nextRow("k", 0, 3), 0);
144 assert.equal(nextRow("End", 0, 3), 2);
145 assert.equal(nextRow("Home", 2, 3), 0);
146 assert.equal(nextRow("x", 0, 3), null);
147 assert.equal(nextRow("ArrowDown", 0, 0), null);
148});

This file's history is long; its oldest lines are credited to the oldest commit read.