| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | |
| 4 | import { |
| 5 | branchSegment, |
| 6 | branchesPath, |
| 7 | movedTab, |
| 8 | movedView, |
| 9 | notificationView, |
| 10 | notificationViewAt, |
| 11 | notificationsAddress, |
| 12 | notificationsPath, |
| 13 | profilePath, |
| 14 | profileTab, |
| 15 | pullPath, |
| 16 | pullTab, |
| 17 | rulesAt, |
| 18 | rulesPath, |
| 19 | } from "./tab-paths.ts"; |
| 20 | |
| 21 | const at = (address: string) => new URL(address, "https://g1t.sh"); |
| 22 | |
| 23 | test("a profile's tabs are paths, and its overview is the profile", () => { |
| 24 | assert.equal(profilePath("ada"), "/u/ada"); |
| 25 | assert.equal(profilePath("ada", "overview"), "/u/ada"); |
| 26 | assert.equal(profilePath("ada", "pulls"), "/u/ada/pulls"); |
| 27 | assert.equal(profilePath("ada", "issues"), "/u/ada/issues"); |
| 28 | assert.equal(profilePath("ada", "stars"), "/u/ada/stars"); |
| 29 | // A tab it never had (GitHub's repositories) is the overview. |
| 30 | assert.equal(profilePath("ada", "repositories"), "/u/ada"); |
| 31 | assert.equal(profileTab(undefined), "overview"); |
| 32 | assert.equal(profileTab("pulls"), "pulls"); |
| 33 | assert.equal(profileTab("Stars"), "stars"); |
| 34 | // The overview has one address; anything else is no page. |
| 35 | assert.equal(profileTab("overview"), null); |
| 36 | assert.equal(profileTab("repositories"), null); |
| 37 | }); |
| 38 | |
| 39 | test("an old profile address with ?tab= goes to the tab's path, keeping its filters", () => { |
| 40 | const to = (address: string) => movedTab(at(address), (tab) => profilePath("ada", tab)); |
| 41 | assert.equal(to("/u/ada?tab=pulls"), "/u/ada/pulls"); |
| 42 | assert.equal(to("/u/ada?tab=pulls&state=merged"), "/u/ada/pulls?state=merged"); |
| 43 | assert.equal(to("/u/ada?state=open&tab=issues&repo=acme%2Fweb&sort=oldest"), "/u/ada/issues?state=open&repo=acme%2Fweb&sort=oldest"); |
| 44 | assert.equal(to("/u/ada?tab=STARS"), "/u/ada/stars"); |
| 45 | assert.equal(to("/u/ada?tab=overview"), "/u/ada"); |
| 46 | assert.equal(to("/u/ada?tab=repositories"), "/u/ada"); |
| 47 | // A click's data request: `_routes` is the router's, not the page's. |
| 48 | assert.equal(to("/u/ada.data?tab=pulls&_routes=root,routes/user"), "/u/ada/pulls"); |
| 49 | // No ?tab=: nothing moved. |
| 50 | assert.equal(to("/u/ada/pulls?state=open"), null); |
| 51 | assert.equal(to("/u/ada"), null); |
| 52 | }); |
| 53 | |
| 54 | test("a pull request's tabs are /session and /files", () => { |
| 55 | assert.equal(pullPath("/acme/web", 12), "/acme/web/pull/12"); |
| 56 | assert.equal(pullPath("/acme/web", 12, "conversation"), "/acme/web/pull/12"); |
| 57 | assert.equal(pullPath("/acme/web", 12, "session"), "/acme/web/pull/12/session"); |
| 58 | assert.equal(pullPath("/acme/web", 12, "changes"), "/acme/web/pull/12/files"); |
| 59 | assert.equal(pullPath("/acme/web", "12", "files"), "/acme/web/pull/12/files"); |
| 60 | assert.equal(pullPath("/acme/web", 12, "commits"), "/acme/web/pull/12"); |
| 61 | assert.equal(pullTab(undefined), "conversation"); |
| 62 | assert.equal(pullTab("files"), "changes"); |
| 63 | assert.equal(pullTab("session"), "session"); |
| 64 | assert.equal(pullTab("Files"), "changes"); |
| 65 | assert.equal(pullTab("changes"), null); |
| 66 | assert.equal(pullTab("conversation"), null); |
| 67 | assert.equal(pullTab("commits"), null); |
| 68 | }); |
| 69 | |
| 70 | test("an old pull request address with ?tab= goes to the tab's path, keeping the rest", () => { |
| 71 | const to = (address: string) => movedTab(at(address), (tab) => pullPath("/acme/web", "12", tab)); |
| 72 | assert.equal(to("/acme/web/pull/12?tab=changes"), "/acme/web/pull/12/files"); |
| 73 | assert.equal(to("/acme/web/pull/12?tab=session"), "/acme/web/pull/12/session"); |
| 74 | assert.equal(to("/acme/web/pull/12?tab=conversation"), "/acme/web/pull/12"); |
| 75 | assert.equal(to("/acme/web/pull/12?tab=files"), "/acme/web/pull/12/files"); |
| 76 | assert.equal(to("/acme/web/pull/12?tab=changes&w=1"), "/acme/web/pull/12/files?w=1"); |
| 77 | assert.equal(to("/acme/web/pull/12"), null); |
| 78 | }); |
| 79 | |
| 80 | test("the Branches page's tabs are paths", () => { |
| 81 | assert.equal(branchesPath("/acme/web"), "/acme/web/branches"); |
| 82 | assert.equal(branchesPath("/acme/web", "stale"), "/acme/web/branches/stale"); |
| 83 | assert.equal(branchesPath("/acme/web", "nope"), "/acme/web/branches"); |
| 84 | assert.equal(branchSegment(undefined), "overview"); |
| 85 | assert.equal(branchSegment("yours"), "yours"); |
| 86 | assert.equal(branchSegment("overview"), null); |
| 87 | assert.equal(branchSegment("main"), null); |
| 88 | const to = (address: string) => movedTab(at(address), (tab) => branchesPath("/acme/web", tab)); |
| 89 | assert.equal(to("/acme/web/branches?tab=stale&q=fix"), "/acme/web/branches/stale?q=fix"); |
| 90 | assert.equal(to("/acme/web/branches?tab=overview"), "/acme/web/branches"); |
| 91 | }); |
| 92 | |
| 93 | test("rules' Insights is a path, for a repository and a workspace", () => { |
| 94 | assert.equal(rulesPath("/acme/web/settings/rules"), "/acme/web/settings/rules"); |
| 95 | assert.equal(rulesPath("/acme/web/settings/rules", "insights"), "/acme/web/settings/rules/insights"); |
| 96 | assert.equal(rulesPath("/acme/-/rules", "insights"), "/acme/-/rules/insights"); |
| 97 | assert.equal(rulesAt("/acme/web/settings/rules/insights"), "insights"); |
| 98 | assert.equal(rulesAt("/acme/web/settings/rules/insights.data"), "insights"); |
| 99 | assert.equal(rulesAt("/acme/-/rules/insights"), "insights"); |
| 100 | assert.equal(rulesAt("/acme/web/settings/rules"), "rulesets"); |
| 101 | assert.equal(rulesAt("/acme/web/settings/rules.data"), "rulesets"); |
| 102 | const to = (address: string) => movedTab(at(address), (tab) => rulesPath("/acme/web/settings/rules", tab)); |
| 103 | assert.equal(to("/acme/web/settings/rules?tab=insights&before=abc"), "/acme/web/settings/rules/insights?before=abc"); |
| 104 | assert.equal(to("/acme/web/settings/rules?tab=rulesets&branch=main"), "/acme/web/settings/rules?branch=main"); |
| 105 | }); |
| 106 | |
| 107 | test("notifications' Saved and Done are paths; the severity tabs and reasons narrow them", () => { |
| 108 | assert.equal(notificationsPath(), "/notifications"); |
| 109 | assert.equal(notificationsPath("saved"), "/notifications/saved"); |
| 110 | assert.equal(notificationsPath("done"), "/notifications/done"); |
| 111 | assert.equal(notificationsPath("nope"), "/notifications"); |
| 112 | assert.equal(notificationView(undefined), "inbox"); |
| 113 | assert.equal(notificationView("done"), "done"); |
| 114 | assert.equal(notificationView("inbox"), null); |
| 115 | assert.equal(notificationViewAt("/notifications/saved"), "saved"); |
| 116 | assert.equal(notificationViewAt("/notifications"), "inbox"); |
| 117 | assert.equal(notificationsAddress({ view: "done", tab: "needs", reason: "mention" }), "/notifications/done?tab=needs&reason=mention"); |
| 118 | assert.equal(notificationsAddress({ view: "inbox", tab: "all", reason: null, before: null }), "/notifications"); |
| 119 | assert.equal(notificationsAddress({ view: null, before: "c1" }), "/notifications?before=c1"); |
| 120 | assert.equal(movedView(at("/notifications?view=done&reason=mention")), "/notifications/done?reason=mention"); |
| 121 | assert.equal(movedView(at("/notifications?view=inbox&tab=needs")), "/notifications?tab=needs"); |
| 122 | assert.equal(movedView(at("/notifications?tab=needs")), null); |
| 123 | }); |