Skip to content
71 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { APPS, MAX_APP_PINS, appPinFromForm, appsFor, dockCookie, isPinnable, pinsFrom, pinsIn, pinsToShow, readDock, sidebarClosed, sidebarCookie, withPin, writeDock } from "./apps.ts";
5
6test("built-in apps are never pinned; the rest are", () => {
7 for (const app of APPS) assert.equal(isPinnable(app.key), !app.builtin, app.key);
8 assert.equal(isPinnable("nonsense"), false);
9});
10
11test("Code's apps are only for members with Code access", () => {
12 const without = appsFor(false).map((app) => app.key);
13 for (const key of ["code", "projects", "packages", "security", "context", "memory"]) assert.ok(!without.includes(key as never), key);
14 for (const key of ["today", "chat", "notifications", "agents", "artifacts", "people", "workspace", "teams", "usage"]) assert.ok(without.includes(key as never), key);
15 assert.equal(appsFor(true).length, APPS.length);
16});
17
18test("pins are kept per workspace, in the order they were pinned", () => {
19 const value = writeDock(writeDock(null, "acme", ["projects", "usage"]), "Beta", ["teams"]);
20 assert.equal(value, "beta:teams,acme:projects.usage");
21 assert.deepEqual(pinsIn(value, "acme"), ["projects", "usage"]);
22 assert.deepEqual(pinsIn(value, "BETA"), ["teams"]);
23 assert.deepEqual(pinsIn(value, "other"), []);
24 // Unpinning everything keeps the workspace, with no pins.
25 assert.deepEqual(pinsIn(writeDock(value, "acme", []), "acme"), []);
26});
27
28test("a cookie someone wrote by hand reads as far as it makes sense", () => {
29 assert.deepEqual(readDock("acme:projects.today.nonsense.projects,BAD SLUG:usage,beta"), { acme: ["projects"] });
30 assert.deepEqual(readDock(""), {});
31 const many = Array.from({ length: 30 }, () => "usage").join(".");
32 assert.ok(pinsIn(`acme:${many}`, "acme").length <= MAX_APP_PINS);
33});
34
35test("pins kept with the account keep their order and only real apps", () => {
36 assert.deepEqual(pinsFrom(["usage", "projects", "today", "retired-app", "usage", "teams"]), ["usage", "projects", "teams"]);
37 assert.deepEqual(pinsFrom([]), []);
38 assert.ok(pinsFrom(Array.from({ length: 30 }, (_, n) => APPS[8 + (n % 10)]!.key)).length <= MAX_APP_PINS);
39});
40
41test("the account's pins win over the cookie, which is the fallback", () => {
42 const cookie = writeDock(null, "acme", ["projects", "usage"]);
43 // Saved with the account, even with nothing pinned: the account's.
44 assert.deepEqual(pinsToShow(["teams", "audit"], cookie, "acme"), ["teams", "audit"]);
45 assert.deepEqual(pinsToShow([], cookie, "acme"), []);
46 // Never saved, or identity could not be asked: this device's cookie.
47 assert.deepEqual(pinsToShow(null, cookie, "acme"), ["projects", "usage"]);
48 assert.deepEqual(pinsToShow(undefined, null, "acme"), []);
49});
50
51test("a pin form pins or unpins one app", () => {
52 const form = (fields: Record<string, string>) => {
53 const data = new FormData();
54 for (const [name, value] of Object.entries(fields)) data.set(name, value);
55 return data;
56 };
57 assert.deepEqual(appPinFromForm(form({ intent: "pin", app: "teams" })), { app: "teams", pinned: true });
58 assert.deepEqual(appPinFromForm(form({ intent: "unpin", app: "teams" })), { app: "teams", pinned: false });
59 assert.equal(appPinFromForm(form({ intent: "pin", app: "chat" })), null);
60 assert.equal(appPinFromForm(form({ intent: "drop", app: "teams" })), null);
61 assert.deepEqual(withPin(["projects", "teams"], "projects", true), ["teams", "projects"]);
62 assert.deepEqual(withPin(["projects", "teams"], "projects", false), ["teams"]);
63});
64
65test("the cookies last a year and are secure when the site is", () => {
66 assert.match(dockCookie("acme:teams", true), /^g1t_dock=acme%3Ateams; Path=\/; Max-Age=31536000; SameSite=Lax; Secure$/);
67 assert.equal(sidebarCookie(true, false), "g1t_sidebar=closed; Path=/; Max-Age=31536000; SameSite=Lax");
68 assert.equal(sidebarClosed("closed"), true);
69 assert.equal(sidebarClosed("open"), false);
70 assert.equal(sidebarClosed(null), false);
71});