Skip to content

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

133 lines5,322 bytesCodeBlame
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import type { ReviewAssignment } from "@g1t/contracts";
5
6import {
7 filterTeams,
8 newTeamFromForm,
9 parentChoices,
10 reviewAssignmentFromForm,
11 splitTeams,
12 teamChangesFromForm,
13 teamCounts,
14 teamPath,
15} from "./teams.ts";
16
17const team = (slug: string, extra: Record<string, unknown> = {}) => ({
18 slug,
19 name: slug[0].toUpperCase() + slug.slice(1),
20 description: null as string | null,
21 visibility: "visible" as "visible" | "secret",
22 parent: null as { slug: string; name: string } | null,
23 viewer_role: null as "member" | "maintainer" | null,
24 ...extra,
25});
26
27const form = (fields: Record<string, string | string[]>) => {
28 const data = new FormData();
29 for (const [key, value] of Object.entries(fields)) {
30 for (const one of Array.isArray(value) ? value : [value]) data.append(key, one);
31 }
32 return data;
33};
34
35const DEFAULTS: ReviewAssignment = {
36 enabled: false,
37 algorithm: "round_robin",
38 count: 1,
39 skip_busy: false,
40 busy_at: 5,
41 include_child_teams: false,
42 excluded: [],
43 notify_team: false,
44};
45
46test("team pages live under the workspace's teams", () => {
47 assert.equal(teamPath("acme", "backend"), "/acme/-/teams/backend");
48 assert.equal(teamPath("acme", "backend", "settings"), "/acme/-/teams/backend/settings");
49});
50
51test("teams are found by every word of the search", () => {
52 const teams = [team("backend", { description: "APIs and data" }), team("web"), team("platform", { description: "Shared backend tools" })];
53 assert.deepEqual(filterTeams(teams, "").map((t) => t.slug), ["backend", "web", "platform"]);
54 assert.deepEqual(filterTeams(teams, "BACKEND").map((t) => t.slug), ["backend", "platform"]);
55 assert.deepEqual(filterTeams(teams, "backend tools").map((t) => t.slug), ["platform"]);
56 assert.deepEqual(filterTeams(teams, "nothing"), []);
57});
58
59test("your teams come first", () => {
60 const { mine, others } = splitTeams([team("a"), team("b", { viewer_role: "member" }), team("c", { viewer_role: "maintainer" })]);
61 assert.deepEqual(mine.map((t) => t.slug), ["b", "c"]);
62 assert.deepEqual(others.map((t) => t.slug), ["a"]);
63});
64
65test("a team can go under any visible team but itself and those below it", () => {
66 const teams = [
67 team("eng"),
68 team("backend", { parent: { slug: "eng", name: "Eng" } }),
69 team("api", { parent: { slug: "backend", name: "Backend" } }),
70 team("web", { parent: { slug: "eng", name: "Eng" } }),
71 team("secret", { visibility: "secret" }),
72 ];
73 assert.deepEqual(parentChoices(teams, "backend").map((t) => t.slug), ["eng", "web"]);
74 assert.deepEqual(parentChoices(teams, "eng").map((t) => t.slug), []);
75 assert.deepEqual(parentChoices(teams, null).map((t) => t.slug), ["eng", "backend", "api", "web"]);
76});
77
78test("a new team reads its form", () => {
79 assert.deepEqual(newTeamFromForm(form({ name: " Backend ", slug: "", description: "", visibility: "secret", parent: "", members: "@ana, bo cy" })), {
80 name: "Backend",
81 slug: null,
82 description: null,
83 visibility: "secret",
84 parent: null,
85 members: ["ana", "bo", "cy"],
86 });
87 assert.equal(newTeamFromForm(form({ name: "x", visibility: "weird" })).visibility, "visible");
88});
89
90test("settings change only what their form has", () => {
91 assert.deepEqual(teamChangesFromForm(form({ name: "Web", description: " UI " })), { name: "Web", description: "UI" });
92 assert.deepEqual(teamChangesFromForm(form({ parent: "" })), { parent: "" });
93 assert.deepEqual(teamChangesFromForm(form({ "notify-shown": "1" })), { notify: false });
94 assert.deepEqual(teamChangesFromForm(form({ "notify-shown": "1", notify: "on" })), { notify: true });
95 assert.deepEqual(teamChangesFromForm(form({ visibility: "secret" })), { visibility: "secret" });
96});
97
98test("review assignment is read within bounds", () => {
99 const read = reviewAssignmentFromForm(
100 form({ enabled: "on", algorithm: "load_balance", count: "40", skip_busy: "on", busy_at: "0", excluded: "@Ana, bo ana" }),
101 DEFAULTS,
102 );
103 assert.deepEqual(read, {
104 enabled: true,
105 algorithm: "load_balance",
106 count: 10,
107 skip_busy: true,
108 busy_at: 1,
109 include_child_teams: false,
110 excluded: ["ana", "bo"],
111 notify_team: false,
112 });
113 // Off, and nonsense kept as it was.
114 const off = reviewAssignmentFromForm(form({ algorithm: "random", count: "many" }), { ...DEFAULTS, count: 3 });
115 assert.equal(off.enabled, false);
116 assert.equal(off.algorithm, "round_robin");
117 assert.equal(off.count, 3);
118});
119
120test("counts leave out what is none", () => {
121 assert.equal(teamCounts({ members_count: 1, repos_count: 0, child_teams_count: 2 }), "1 member · 2 child teams");
122 assert.equal(teamCounts({ members_count: 0, repos_count: 0, child_teams_count: 0 }), "No members yet");
123});
124
125test("who may create teams follows the workspace's setting", async () => {
126 // From the contracts' source: the Teams page and the + menu decide with it.
127 const { mayCreateTeams } = await import("../../../../packages/contracts/src/teams.ts");
128 assert.equal(mayCreateTeams(undefined, "member"), true);
129 assert.equal(mayCreateTeams("members", "member"), true);
130 assert.equal(mayCreateTeams("owners", "member"), false);
131 assert.equal(mayCreateTeams("owners", "owner"), true);
132 assert.equal(mayCreateTeams("members", null), false);
133});