Public: anyone can read this; the crew can change it.

The terminal's 'Working now' tests wait for the line they expect, so they pass beside the full gate #2487

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/2482-the-terminal-s-working-now-tests-wait-fo → main 1 commit fork

  • Merged. scout/2482-the-terminal-s-working-now-tests-wait-fo was merged into main as af50b6b.

Review

Sign in to review this change.
1 file changed +39 −13
test/tui-working-yours.test.ts +39 −13
@@ -29,7 +29,16 @@ let alice: User;
2929 let bob: User;
3030 let repo: Repo;
3131
32 async function palette(user: User, keys: string[] = [":"]): Promise<string> {
32 /** The longest a screen gets to show what an assertion reads. */
33 const SHOW_MS = 2000;
34
35 /**
36 * Open the palette as `user`, type `keys`, and return the screen once the
37 * list has rendered: the search is no longer "searching…", and when the
38 * caller expects a row (`shows`) that row is on screen. A negative assertion
39 * made on the result therefore reads a drawn list, not an empty frame.
40 */
41 async function palette(user: User, keys: string[], shows?: string): Promise<string> {
3342 const terminal = headlessTerminal(120, 40);
3443 const { app: tui, session } = createForgeApp(
3544 app,
@@ -43,11 +52,24 @@ async function palette(user: User, keys: string[] = [":"]): Promise<string> {
4352 terminal.feed(k);
4453 await settleApp(tui);
4554 }
46 const text = tui.screen.toText();
55 const deadline = Date.now() + SHOW_MS;
56 let text = tui.screen.toText();
57 while (Date.now() < deadline && (text.includes("searching…") || (shows !== undefined && !text.includes(shows)))) {
58 await new Promise<void>((r) => setTimeout(r, 10));
59 await settleApp(tui);
60 text = tui.screen.toText();
61 }
4762 tui.stop?.();
4863 return text;
4964 }
5065
66 /** A live agent run of this test's own; `done()` finishes it. */
67 function liveRun(summary: string, issueId?: string): { id: string; done: () => void } {
68 const run = createRun(app.db, { repoId: repo.id, kind: "agent", issueId, actorId: alice.id, summary });
69 claimRun(app.db, run.id);
70 return { id: run.id, done: () => void finishRun(app.db, run.id, { state: "ok", summary: "done" }) };
71 }
72
5173 beforeAll(async () => {
5274 dir = await mkdtemp(join(tmpdir(), "forge-tui-working-"));
5375 app = createApp({ dataDir: dir, port: 0 });
@@ -74,32 +96,36 @@ afterAll(async () => {
7496 describe("working now in the terminal", () => {
7597 test("shown while a run is live, gone once it finishes", async () => {
7698 expect(await palette(bob, [":", "Working"])).not.toContain("Working now");
77 const run = createRun(app.db, { repoId: repo.id, kind: "agent", actorId: alice.id, summary: "LIVEJOB sanding the door" });
78 claimRun(app.db, run.id);
79 expect(await palette(bob, [":", "Working"])).toContain("Working now: LIVEJOB sanding the door");
80 finishRun(app.db, run.id, { state: "ok", summary: "done" });
99 const run = liveRun("LIVEJOB sanding the door");
100 try {
101 expect(await palette(bob, [":", "Working"], "LIVEJOB")).toContain("Working now: LIVEJOB sanding the door");
102 } finally {
103 run.done();
104 }
81105 expect(await palette(bob, [":", "Working"])).not.toContain("Working now");
82106 });
83107
84108 test("a run on a sealed issue is hidden from bob and shown to its filer", async () => {
85109 const sealed = createIssue(app.db, { repoId: repo.id, authorId: alice.id, title: "hole", sealed: true });
86110 if (!sealed.ok) throw new Error(sealed.error);
87 const run = createRun(app.db, { repoId: repo.id, kind: "agent", issueId: sealed.value.id, actorId: alice.id, summary: "SEALEDJOB" });
88 claimRun(app.db, run.id);
89 expect(await palette(bob, [":", "Working"])).not.toContain("SEALEDJOB");
90 expect(await palette(alice, [":", "Working"])).toContain("SEALEDJOB");
91 finishRun(app.db, run.id, { state: "ok", summary: "done" });
111 const run = liveRun("SEALEDJOB", sealed.value.id);
112 try {
113 expect(await palette(alice, [":", "Working"], "SEALEDJOB")).toContain("SEALEDJOB");
114 expect(await palette(bob, [":", "Working"])).not.toContain("SEALEDJOB");
115 } finally {
116 run.done();
117 }
92118 });
93119 });
94120
95121 describe("make it yours in the terminal", () => {
96122 test("a writer does not see it; a reader who cannot write does", async () => {
97123 expect(await palette(alice, [":", "Make it"])).not.toContain("Make it yours");
98 expect(await palette(bob, [":", "Make it"])).toContain("alice/lobby — Make it yours");
124 expect(await palette(bob, [":", "Make it"], "Make it yours")).toContain("alice/lobby — Make it yours");
99125 });
100126
101127 test("it opens the fork screen", async () => {
102 const text = await palette(bob, [":", "make it", "\r"]);
128 const text = await palette(bob, [":", "make it", "\r"], "Fork");
103129 expect(text).toContain("Fork");
104130 });
105131 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs