| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | |
| 4 | import { linkPathOf, refContext, refRoute, refSitePath, routeFor, sessionRoute, sitePathOf, targetRoute } from "./links.ts"; |
| 5 | |
| 6 | test("a g1t:// link names a site path, as on the desktop", () => { |
| 7 | assert.equal(sitePathOf("g1t://acme/-/chat/dm/chn_1"), "/acme/-/chat/dm/chn_1"); |
| 8 | assert.equal(sitePathOf("g1t:///acme/rocket/pull/3?tab=files"), "/acme/rocket/pull/3?tab=files"); |
| 9 | assert.equal(sitePathOf("https://g1t.sh/acme"), null); |
| 10 | }); |
| 11 | |
| 12 | test("an https link to the site names the same path as a g1t:// one", () => { |
| 13 | assert.equal(linkPathOf("https://g1t.sh/acme/-/work/12"), "/acme/-/work/12"); |
| 14 | assert.equal(linkPathOf("g1t://acme/-/work/12"), "/acme/-/work/12"); |
| 15 | assert.equal(linkPathOf("https://g1t.sh/acme/-/work?repo=web#top"), "/acme/-/work?repo=web"); |
| 16 | assert.equal(linkPathOf("https://g1t.sh"), "/"); |
| 17 | assert.equal(linkPathOf("mailto:someone@example.com"), null); |
| 18 | }); |
| 19 | |
| 20 | test("Chat's pages open the app's Chat", () => { |
| 21 | assert.equal(routeFor("/acme/-/chat"), "/chat?workspace=acme"); |
| 22 | assert.equal(routeFor("/acme/-/chat/general"), "/chat/general?workspace=acme"); |
| 23 | assert.equal(routeFor("/acme/-/chat/dm/chn_1"), "/chat/chn_1?workspace=acme"); |
| 24 | assert.equal(routeFor("/acme/-/chat/browse"), null); |
| 25 | }); |
| 26 | |
| 27 | test("Work's pages open the app's Work", () => { |
| 28 | assert.equal(routeFor("/acme/-/work"), "/work?workspace=acme"); |
| 29 | assert.equal(routeFor("/acme/-/work/12"), "/work/12?workspace=acme"); |
| 30 | assert.equal(routeFor(linkPathOf("g1t://acme/-/work/12")!), "/work/12?workspace=acme"); |
| 31 | assert.equal(routeFor(linkPathOf("https://g1t.sh/acme/-/work/12")!), "/work/12?workspace=acme"); |
| 32 | assert.equal(routeFor("/acme/-/work/new"), "/work/new?workspace=acme"); |
| 33 | // The list keeps the filters the site's does, and drops anything else. |
| 34 | assert.equal(routeFor("/acme/-/work?repo=web&label=bug&page=3"), "/work?workspace=acme&label=bug&repo=web"); |
| 35 | assert.equal(routeFor("/acme/-/work/labels"), null); |
| 36 | assert.equal(routeFor("/acme/-/work/milestones/2"), null); |
| 37 | assert.equal(routeFor("/acme/-/work/12/edit"), null); |
| 38 | }); |
| 39 | |
| 40 | test("Work's board opens Work on its board", () => { |
| 41 | assert.equal(routeFor("/acme/-/work/board"), "/work?workspace=acme&view=board"); |
| 42 | assert.equal(routeFor(linkPathOf("g1t://acme/-/work/board")!), "/work?workspace=acme&view=board"); |
| 43 | assert.equal(routeFor("/acme/-/work/board/x"), null); |
| 44 | }); |
| 45 | |
| 46 | test("Work's sessions open Work on its Sessions, and a session its screen", () => { |
| 47 | assert.equal(routeFor(linkPathOf("g1t://acme/-/work/sessions")!), "/work?workspace=acme&view=sessions"); |
| 48 | assert.equal(routeFor(linkPathOf("https://g1t.sh/acme/-/work/sessions")!), "/work?workspace=acme&view=sessions"); |
| 49 | assert.equal(routeFor(linkPathOf("g1t://acme/-/work/sessions/ses_01abc")!), "/work/sessions/ses_01abc?workspace=acme"); |
| 50 | assert.equal(routeFor(linkPathOf("https://g1t.sh/acme/-/work/sessions/ses_01abc")!), "/work/sessions/ses_01abc?workspace=acme"); |
| 51 | // The list keeps the filters the site's does, and drops anything else. |
| 52 | assert.equal(routeFor("/acme/-/work/sessions?state=live&repo=web&page=2"), "/work?workspace=acme&view=sessions&state=live&repo=web"); |
| 53 | assert.equal(routeFor("/acme/-/work/sessions/ses_1/entries"), null); |
| 54 | // Sessions were once a page of their own; that address is gone, so the app has no screen for it. |
| 55 | assert.equal(routeFor("/acme/-/sessions"), null); |
| 56 | assert.equal(routeFor("/acme/-/sessions/ses_1"), null); |
| 57 | }); |
| 58 | |
| 59 | test("a session opens its page, or its pull request's for g1t's agent and a recorded one", () => { |
| 60 | assert.equal(sessionRoute({ kind: "harness", id: "ses_1", repo: "acme/web", pull: 3 }, "acme", true), "/work/sessions/ses_1?workspace=acme"); |
| 61 | assert.equal(sessionRoute({ kind: "hosted", id: "ses_2", repo: "acme/web", pull: null }, "acme", false), "/work/sessions/ses_2?workspace=acme"); |
| 62 | assert.equal(sessionRoute({ kind: "agent", id: "run_1", repo: "acme/web", pull: 3 }, "acme", true), "/code/acme/web/pull/3"); |
| 63 | assert.equal(sessionRoute({ kind: "recorded", id: "pr_1", repo: "acme/web", pull: 3 }, "acme", false), "/open?path=%2Facme%2Fweb%2Fpull%2F3%2Fsession"); |
| 64 | assert.equal(sessionRoute({ kind: "recorded", id: "pr_1", repo: "acme/web", pull: null }, "acme", true), null); |
| 65 | }); |
| 66 | |
| 67 | test("an old link to an issue asks g1t what its number names in its repository", () => { |
| 68 | assert.equal(routeFor("/acme/rocket/issues/12"), "/ref?repo=acme%2Frocket&number=12"); |
| 69 | assert.equal(routeFor(linkPathOf("https://g1t.sh/acme/rocket/issues/12")!), "/ref?repo=acme%2Frocket&number=12"); |
| 70 | assert.equal(routeFor("/acme/rocket/issues"), "/work?workspace=acme&repo=rocket"); |
| 71 | assert.equal(routeFor("/acme/rocket/issues/new"), "/work/new?workspace=acme&repo=rocket"); |
| 72 | assert.equal(routeFor("/acme/rocket/issues/12/edit"), null); |
| 73 | }); |
| 74 | |
| 75 | test("Code's pages open the app's Code", () => { |
| 76 | assert.equal(routeFor("/acme/rocket"), "/code/acme/rocket"); |
| 77 | assert.equal(routeFor("/acme/rocket/pull/14"), "/code/acme/rocket/pull/14"); |
| 78 | assert.equal(routeFor("/acme/-/overview"), "/code?workspace=acme"); |
| 79 | assert.equal(routeFor("/acme/rocket/pull/14/files"), null); |
| 80 | assert.equal(routeFor("/acme/rocket/sessions"), null); |
| 81 | }); |
| 82 | |
| 83 | test("#N is read where it was written, owner/name#N in that repository, workspace#N in that workspace", () => { |
| 84 | const here = { workspace: "acme" }; |
| 85 | assert.deepEqual(refContext(null, here), { workspace: "acme" }); |
| 86 | assert.deepEqual(refContext(null, { repo: "acme/web" }), { repo: "acme/web" }); |
| 87 | assert.deepEqual(refContext("acme/api", here), { repo: "acme/api" }); |
| 88 | assert.deepEqual(refContext("globex", here), { workspace: "globex" }); |
| 89 | assert.equal(refRoute({ workspace: "acme" }, 7), "/ref?workspace=acme&number=7"); |
| 90 | assert.equal(refRoute({ repo: "acme/web" }, 7), "/ref?repo=acme%2Fweb&number=7"); |
| 91 | }); |
| 92 | |
| 93 | test("what a reference names opens its screen, and the site reads one the app cannot", () => { |
| 94 | assert.equal(targetRoute({ kind: "work_item", workspace: "acme", number: 31, item_id: "wki_1" }), "/work/31?workspace=acme"); |
| 95 | assert.equal(targetRoute({ kind: "pull", repo: "acme/web", number: 9 }), "/code/acme/web/pull/9"); |
| 96 | assert.equal(targetRoute({ kind: "pull", repo: "nonsense", number: 9 }), null); |
| 97 | assert.equal(targetRoute({ kind: "none" }), null); |
| 98 | assert.equal(refSitePath({ repo: "acme/web" }, 9), "/acme/web/issues/9"); |
| 99 | assert.equal(refSitePath({ workspace: "acme" }, 9), "/acme/-/work/9"); |
| 100 | }); |
| 101 | |
| 102 | test("old links to Agents, Customize and the Marketplace open Home", () => { |
| 103 | assert.equal(routeFor("/acme/-/agents"), "/home?workspace=acme"); |
| 104 | assert.equal(routeFor("/acme/-/agents/skills"), "/home?workspace=acme"); |
| 105 | assert.equal(routeFor("/acme/-/agents/skills/pdf"), "/home?workspace=acme"); |
| 106 | assert.equal(routeFor("/acme/-/customize"), "/home?workspace=acme"); |
| 107 | assert.equal(routeFor("/acme/-/customize/plugins/pdf%40anthropic-agent-skills"), "/home?workspace=acme"); |
| 108 | assert.equal(routeFor("/acme/-/marketplace/integrations"), "/home?workspace=acme"); |
| 109 | }); |
| 110 | |
| 111 | test("the integrations directory stays on the site", () => { |
| 112 | assert.equal(routeFor("/acme/-/integrations"), null); |
| 113 | assert.equal(routeFor("/acme/-/integrations/github"), null); |
| 114 | }); |
| 115 | |
| 116 | test("the app's sign-in comes back to its own screen, and the site's own pages stay on the site", () => { |
| 117 | assert.equal(routeFor("/oauth/callback?code=c&state=s"), "/oauth/callback?code=c&state=s"); |
| 118 | assert.equal(routeFor("/settings/tokens"), null); |
| 119 | assert.equal(routeFor("/"), "/"); |
| 120 | }); |
| 121 | |
| 122 | test("a connect link points the app at a g1t", () => { |
| 123 | assert.equal(routeFor("/connect?server=https%3A%2F%2Fg1t.example.com"), "/connect?server=https%3A%2F%2Fg1t.example.com"); |
| 124 | assert.equal(sitePathOf("g1t://connect?server=https%3A%2F%2Fg1t.example.com"), "/connect?server=https%3A%2F%2Fg1t.example.com"); |
| 125 | // A workspace named connect is still a workspace. |
| 126 | assert.equal(routeFor("/connect/-/chat"), "/chat?workspace=connect"); |
| 127 | assert.equal(routeFor("/connect/web"), "/code/connect/web"); |
| 128 | }); |