Public: anyone can read this; the crew can change it.
A test pins the terminal palette's entries, in order, for each kind of session #7735
Check · Review · Land · Live done — Landed and live in production.
mason/forge:mason/7730-a-test-pins-the-terminal-palette-s-entri → main 1 commit fork
1 file
changed +209
−0
test/palette-roster.test.ts added +209
| @@ -0,0 +1,209 @@ | ||
| 1 | import { afterAll, beforeAll, expect, test } from "bun:test"; | |
| 2 | import { mkdtemp, rm } from "node:fs/promises"; | |
| 3 | import { tmpdir } from "node:os"; | |
| 4 | import { join } from "node:path"; | |
| 5 | import { createApp, type App } from "../src/app.ts"; | |
| 6 | import { createUser, type User } from "../src/core/users.ts"; | |
| 7 | import { forgeCommands, Session } from "../src/tui/forge.ts"; | |
| 8 | import { quietLogs } from "./helpers/globals.ts"; | |
| 9 | ||
| 10 | quietLogs(); | |
| 11 | ||
| 12 | let dir: string; | |
| 13 | let app: App; | |
| 14 | let admin: User; | |
| 15 | let member: User; | |
| 16 | ||
| 17 | const identity = (user?: User) => ({ | |
| 18 | sshUsername: user?.username ?? "git", | |
| 19 | remoteAddress: "127.0.0.1", | |
| 20 | fingerprint: "SHA256:test", | |
| 21 | user, | |
| 22 | }); | |
| 23 | const roster = (user?: User) => | |
| 24 | forgeCommands(new Session(app, identity(user)))({} as never).map((c) => [c.id, c.title, c.hint]); | |
| 25 | ||
| 26 | beforeAll(async () => { | |
| 27 | dir = await mkdtemp(join(tmpdir(), "forge-palette-roster-")); | |
| 28 | app = createApp({ dataDir: dir, url: "https://forge.test", port: 0 }); | |
| 29 | const mk = async (username: string, isAdmin: boolean) => { | |
| 30 | const r = await createUser(app.db, { | |
| 31 | origin: "seed", | |
| 32 | trusted: true, username, email: `${username}@forge.local`, password: "a-good-passphrase", isAdmin, | |
| 33 | }); | |
| 34 | if (!r.ok) throw new Error(r.error); | |
| 35 | return r.value; | |
| 36 | }; | |
| 37 | admin = await mk("alice", true); | |
| 38 | member = await mk("bob", false); | |
| 39 | }); | |
| 40 | afterAll(async () => { | |
| 41 | app.db.close(); | |
| 42 | await rm(dir, { recursive: true, force: true }); | |
| 43 | }); | |
| 44 | ||
| 45 | // The palette's entries as main has them: id, title, hint, in order, for each kind of session. | |
| 46 | test("a site-admin person is offered the whole roster", () => { | |
| 47 | expect(roster(admin)).toEqual([ | |
| 48 | ["home", "Home", "your repositories"], | |
| 49 | ["explore", "Explore", "on the web"], | |
| 50 | ["profile", "Open a profile", "username or org"], | |
| 51 | ["repo", "Open a repository", "owner/name"], | |
| 52 | ["issues", "Issues in a repository", "owner/name"], | |
| 53 | ["pulls", "Pull requests in a repository", "owner/name"], | |
| 54 | ["milestones", "Milestones in a repository", "owner/name"], | |
| 55 | ["repo-usage", "Usage of a repository", "owner/name"], | |
| 56 | ["new-issue", "New issue", "owner/name"], | |
| 57 | ["new-pull", "New pull request", "owner/name"], | |
| 58 | ["settings", "Repository settings", "owner/name"], | |
| 59 | ["new-repo", "New repository", undefined], | |
| 60 | ["new-org", "New organization", "an organization you own, for a client's apps"], | |
| 61 | ["migrate", "Migrate a repository", "bring one in from an origin or a URL, pick its branch, put a crew on it"], | |
| 62 | ["new-forge", "New forge", "spawn a client's forge and get its claim link"], | |
| 63 | ["asked", "Asked", "your thoughts and what became of them"], | |
| 64 | ["decider", "Decider", "what it closed, deferred and asked you about today"], | |
| 65 | ["notify", "Phone notifications", "where the crew reaches your phone; s sets, x turns off"], | |
| 66 | ["ssh-keys", "SSH keys", "list, add and remove the keys that sign in as you"], | |
| 67 | ["account", "Account settings", undefined], | |
| 68 | ["signins", "Signed in", "your browsers and tokens; d signs a browser out"], | |
| 69 | ["sentinel", "Sentinel", "the forge's open faults"], | |
| 70 | ["boards", "Boards", "the forge's boards and their panels"], | |
| 71 | ["system-memory", "System memory", "RSS beside the JS heap, hourly for 24 h"], | |
| 72 | ["flow", "Flow", "the pipeline's bottleneck and throughput"], | |
| 73 | ["system", "System", "the machine now: CPU, memory, disks, processes"], | |
| 74 | ["telemetry", "Telemetry", "which agents may read flow and system; enter flips the grant"], | |
| 75 | ["capacity", "Capacity", "concurrency and guards, live; e changes a settable one"], | |
| 76 | ["resilience", "Resilience", "where snapshots go and the mirror; each protection green, red or untested"], | |
| 77 | ["api", "API", "the forge's endpoints; run a GET"], | |
| 78 | ["changelog", "Changelog", "the last 30 releases and their pulls"], | |
| 79 | ["releases", "Releases", "the live release and the kept ones"], | |
| 80 | ["stalled", "Stalled steps", "pulls whose check is red or was never asked for; enter re-runs"], | |
| 81 | ["file-holds", "Held files", "hold new work on a file, release it, or list the holds"], | |
| 82 | ["access", "Access", "what outside agents tried"], | |
| 83 | ["flags", "Flags", "declared flags and their live values"], | |
| 84 | ["secrets", "Secrets", "sealed secrets by name; set or remove one"], | |
| 85 | ["trusted-hosts", "Trusted hosts", "internal hosts an origin may reach"], | |
| 86 | ["usage", "Usage", "every route, unused ones first"], | |
| 87 | ["crew-scorecard", "Crew scorecard", "agent runs per model and per prompt version"], | |
| 88 | ["crew-handover", "Crew hand-overs", "issues parked twice, and the last restore drill"], | |
| 89 | ["scorecard", "Crew scorecard per agent", "each agent's pulls landed, review rounds, red checks, reverts, time to land"], | |
| 90 | ["proposal-tokens", "Proposal tokens", "mint, list and revoke what a child proposes with"], | |
| 91 | ["model", "Model budget", "what your crew may spend, and add your own subscription"], | |
| 92 | ["model-grant", "Model grant", "give an account dollars a month, or take it back"], | |
| 93 | ["model-ceiling", "Model ceiling", "set an account's dollars a day and a run"], | |
| 94 | ["can", "What I can do", "your role and what it allows here"], | |
| 95 | ["people", "People", "who is a guest, a member or an admin; promote or demote"], | |
| 96 | ["quotas", "Account quotas", "what one account may own, and who changed it"], | |
| 97 | ["limits", "Limits", "what the forge caps, with default and bounds; change one"], | |
| 98 | ["teams", "Crew teams", "each team's charter, dial and members"], | |
| 99 | ["invites", "Invite links", "make a single-use link, see which are open, revoke one"], | |
| 100 | ["subscriptions", "Crew subscriptions", "each account's budget and rest; wake one, set its budget, add or remove one"], | |
| 101 | ["cloud", "Cloud accounts", "provider tokens, what they are used for, today's calls"], | |
| 102 | ["domains", "Failure domains", "failure domains and their last drill"], | |
| 103 | ["owner", "Owner's needs", "what needs the owner, snapshots, failure domains"], | |
| 104 | ["forges", "Forges you sent", "each forge sent, claimed or not, and its apps"], | |
| 105 | ["family", "Family", "the forge that sent this one, and the forges it sent"], | |
| 106 | ["chain", "Chain", "the forges this forge's code descends from, root first"], | |
| 107 | ["quit", "Quit", "disconnect"], | |
| 108 | ]); | |
| 109 | }); | |
| 110 | ||
| 111 | test("a site-admin agent is offered the roster without the person-only entries", () => { | |
| 112 | expect(roster({ ...admin, kind: "agent" })).toEqual([ | |
| 113 | ["home", "Home", "your repositories"], | |
| 114 | ["explore", "Explore", "on the web"], | |
| 115 | ["profile", "Open a profile", "username or org"], | |
| 116 | ["repo", "Open a repository", "owner/name"], | |
| 117 | ["issues", "Issues in a repository", "owner/name"], | |
| 118 | ["pulls", "Pull requests in a repository", "owner/name"], | |
| 119 | ["milestones", "Milestones in a repository", "owner/name"], | |
| 120 | ["repo-usage", "Usage of a repository", "owner/name"], | |
| 121 | ["new-issue", "New issue", "owner/name"], | |
| 122 | ["new-pull", "New pull request", "owner/name"], | |
| 123 | ["settings", "Repository settings", "owner/name"], | |
| 124 | ["new-repo", "New repository", undefined], | |
| 125 | ["migrate", "Migrate a repository", "bring one in from an origin or a URL, pick its branch, put a crew on it"], | |
| 126 | ["new-forge", "New forge", "spawn a client's forge and get its claim link"], | |
| 127 | ["asked", "Asked", "your thoughts and what became of them"], | |
| 128 | ["decider", "Decider", "what it closed, deferred and asked you about today"], | |
| 129 | ["ssh-keys", "SSH keys", "list, add and remove the keys that sign in as you"], | |
| 130 | ["account", "Account settings", undefined], | |
| 131 | ["signins", "Signed in", "your browsers and tokens; d signs a browser out"], | |
| 132 | ["sentinel", "Sentinel", "the forge's open faults"], | |
| 133 | ["resilience", "Resilience", "where snapshots go and the mirror; each protection green, red or untested"], | |
| 134 | ["api", "API", "the forge's endpoints; run a GET"], | |
| 135 | ["changelog", "Changelog", "the last 30 releases and their pulls"], | |
| 136 | ["releases", "Releases", "the live release and the kept ones"], | |
| 137 | ["stalled", "Stalled steps", "pulls whose check is red or was never asked for; enter re-runs"], | |
| 138 | ["file-holds", "Held files", "hold new work on a file, release it, or list the holds"], | |
| 139 | ["secrets", "Secrets", "sealed secrets by name; set or remove one"], | |
| 140 | ["crew-scorecard", "Crew scorecard", "agent runs per model and per prompt version"], | |
| 141 | ["crew-handover", "Crew hand-overs", "issues parked twice, and the last restore drill"], | |
| 142 | ["scorecard", "Crew scorecard per agent", "each agent's pulls landed, review rounds, red checks, reverts, time to land"], | |
| 143 | ["proposal-tokens", "Proposal tokens", "mint, list and revoke what a child proposes with"], | |
| 144 | ["can", "What I can do", "your role and what it allows here"], | |
| 145 | ["cloud", "Cloud accounts", "provider tokens, what they are used for, today's calls"], | |
| 146 | ["forges", "Forges you sent", "each forge sent, claimed or not, and its apps"], | |
| 147 | ["family", "Family", "the forge that sent this one, and the forges it sent"], | |
| 148 | ["chain", "Chain", "the forges this forge's code descends from, root first"], | |
| 149 | ["quit", "Quit", "disconnect"], | |
| 150 | ]); | |
| 151 | }); | |
| 152 | ||
| 153 | test("a member person is offered the signed-in roster without the admin entries", () => { | |
| 154 | expect(roster(member)).toEqual([ | |
| 155 | ["home", "Home", "your repositories"], | |
| 156 | ["explore", "Explore", "on the web"], | |
| 157 | ["profile", "Open a profile", "username or org"], | |
| 158 | ["repo", "Open a repository", "owner/name"], | |
| 159 | ["issues", "Issues in a repository", "owner/name"], | |
| 160 | ["pulls", "Pull requests in a repository", "owner/name"], | |
| 161 | ["milestones", "Milestones in a repository", "owner/name"], | |
| 162 | ["repo-usage", "Usage of a repository", "owner/name"], | |
| 163 | ["new-issue", "New issue", "owner/name"], | |
| 164 | ["new-pull", "New pull request", "owner/name"], | |
| 165 | ["settings", "Repository settings", "owner/name"], | |
| 166 | ["new-repo", "New repository", undefined], | |
| 167 | ["new-org", "New organization", "an organization you own, for a client's apps"], | |
| 168 | ["migrate", "Migrate a repository", "bring one in from an origin or a URL, pick its branch, put a crew on it"], | |
| 169 | ["new-forge", "New forge", "spawn a client's forge and get its claim link"], | |
| 170 | ["asked", "Asked", "your thoughts and what became of them"], | |
| 171 | ["decider", "Decider", "what it closed, deferred and asked you about today"], | |
| 172 | ["notify", "Phone notifications", "where the crew reaches your phone; s sets, x turns off"], | |
| 173 | ["ssh-keys", "SSH keys", "list, add and remove the keys that sign in as you"], | |
| 174 | ["account", "Account settings", undefined], | |
| 175 | ["signins", "Signed in", "your browsers and tokens; d signs a browser out"], | |
| 176 | ["api", "API", "the forge's endpoints; run a GET"], | |
| 177 | ["changelog", "Changelog", "the last 30 releases and their pulls"], | |
| 178 | ["stalled", "Stalled steps", "pulls whose check is red or was never asked for; enter re-runs"], | |
| 179 | ["file-holds", "Held files", "hold new work on a file, release it, or list the holds"], | |
| 180 | ["proposal-tokens", "Proposal tokens", "mint, list and revoke what a child proposes with"], | |
| 181 | ["model", "Model budget", "what your crew may spend, and add your own subscription"], | |
| 182 | ["can", "What I can do", "your role and what it allows here"], | |
| 183 | ["family", "Family", "the forge that sent this one, and the forges it sent"], | |
| 184 | ["chain", "Chain", "the forges this forge's code descends from, root first"], | |
| 185 | ["quit", "Quit", "disconnect"], | |
| 186 | ]); | |
| 187 | }); | |
| 188 | ||
| 189 | test("signed out, the palette offers sign-in and the public entries", () => { | |
| 190 | expect(roster()).toEqual([ | |
| 191 | ["home", "Home", "your repositories"], | |
| 192 | ["explore", "Explore", "on the web"], | |
| 193 | ["profile", "Open a profile", "username or org"], | |
| 194 | ["repo", "Open a repository", "owner/name"], | |
| 195 | ["issues", "Issues in a repository", "owner/name"], | |
| 196 | ["pulls", "Pull requests in a repository", "owner/name"], | |
| 197 | ["milestones", "Milestones in a repository", "owner/name"], | |
| 198 | ["repo-usage", "Usage of a repository", "owner/name"], | |
| 199 | ["new-issue", "New issue", "owner/name"], | |
| 200 | ["new-pull", "New pull request", "owner/name"], | |
| 201 | ["settings", "Repository settings", "owner/name"], | |
| 202 | ["signin", "Sign in", undefined], | |
| 203 | ["api", "API", "the forge's endpoints; run a GET"], | |
| 204 | ["changelog", "Changelog", "the last 30 releases and their pulls"], | |
| 205 | ["family", "Family", "the forge that sent this one, and the forges it sent"], | |
| 206 | ["chain", "Chain", "the forges this forge's code descends from, root first"], | |
| 207 | ["quit", "Quit", "disconnect"], | |
| 208 | ]); | |
| 209 | }); |
new above
offline