Public: anyone can read this; the crew can change it.
A test proves the steer box on a run page is shown only to a writer, on a live agent run with an issue #10061
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/10044-a-test-proves-the-steer-box-on-a-run-pag → main 1 commit fork
1 file
changed +69
−0
test/studio-runs.test.ts +69
| @@ -580,6 +580,75 @@ describe("working: a run's own page in the studio", () => { | ||
| 580 | 580 | expect(page).not.toContain("run-actions"); |
| 581 | 581 | }); |
| 582 | 582 | |
| 583 | test("the steer box is a writer's, on an agent run with an issue, never for a reader or a signed-out visitor", async () => { | |
| 584 | const made = await createRepo(app, alice, { | |
| 585 | name: "open", | |
| 586 | visibility: "public", | |
| 587 | description: "a public app", | |
| 588 | }); | |
| 589 | if (!made.ok) throw new Error(String(made.error)); | |
| 590 | const open = made.value; | |
| 591 | const seeded = await commitToBranch(app, alice, open, { | |
| 592 | message: "Start", | |
| 593 | files: [{ path: "README.md", content: "open\n" }], | |
| 594 | }); | |
| 595 | if (!seeded.ok) throw new Error(JSON.stringify(seeded.error)); | |
| 596 | const tell = openIssue(app, alice, open, { title: "Steer me" }); | |
| 597 | if (!tell.ok) throw new Error(String(tell.error)); | |
| 598 | const mk = (issueId?: string) => { | |
| 599 | const run = createRun(app.db, { | |
| 600 | repoId: open.id, | |
| 601 | kind: "agent", | |
| 602 | issueId, | |
| 603 | actorId: scoutId, | |
| 604 | reason: "assigned", | |
| 605 | }); | |
| 606 | claimRun(app.db, run.id); | |
| 607 | return run; | |
| 608 | }; | |
| 609 | const page = async (id: string, cookie?: string) => { | |
| 610 | const res = await fetch(`${base}/alice/open/runs/${id}`, { | |
| 611 | headers: { cookie: `${cookie ?? ""}; forge_mode=studio` }, | |
| 612 | redirect: "manual", | |
| 613 | }); | |
| 614 | return { status: res.status, text: await res.text() }; | |
| 615 | }; | |
| 616 | const live = mk(tell.value.id); | |
| 617 | const asWriter = await page(live.id, writerCookie); | |
| 618 | expect(asWriter.status).toBe(200); | |
| 619 | expect(asWriter.text).toContain('id="steer-text"'); | |
| 620 | expect(asWriter.text).toContain('id="run-steer"'); | |
| 621 | // A reader of a public repository sees the run, not the box. | |
| 622 | const asReader = await page(live.id, readerCookie); | |
| 623 | expect(asReader.status).toBe(200); | |
| 624 | expect(asReader.text).toContain('data-word='); | |
| 625 | expect(asReader.text).not.toContain('id="steer-text"'); | |
| 626 | expect(asReader.text).not.toContain('id="run-steer"'); | |
| 627 | const signedOut = await page(live.id); | |
| 628 | expect(signedOut.status).toBe(200); | |
| 629 | expect(signedOut.text).toContain('data-word='); | |
| 630 | expect(signedOut.text).not.toContain('id="steer-text"'); | |
| 631 | expect(signedOut.text).not.toContain('id="run-steer"'); | |
| 632 | // No issue to speak on: no box, even to a writer. | |
| 633 | const bare = mk(); | |
| 634 | const bareWriter = await page(bare.id, writerCookie); | |
| 635 | expect(bareWriter.status).toBe(200); | |
| 636 | expect(bareWriter.text).toContain('data-word='); | |
| 637 | expect(bareWriter.text).not.toContain('id="steer-text"'); | |
| 638 | // A finished run keeps the box for a writer only, as "tell it for its | |
| 639 | // next run" (the comment starts a run); a reader never gets it. | |
| 640 | finishRun(app.db, live.id, { state: "ok", summary: "done" }); | |
| 641 | const over = await page(live.id, writerCookie); | |
| 642 | expect(over.text).toContain('data-running="0"'); | |
| 643 | expect(over.text).toContain("The run is over"); | |
| 644 | for (const cookie of [readerCookie, undefined]) { | |
| 645 | const seen = await page(live.id, cookie); | |
| 646 | expect(seen.status).toBe(200); | |
| 647 | expect(seen.text).not.toContain('id="steer-text"'); | |
| 648 | expect(seen.text).not.toContain('id="run-steer"'); | |
| 649 | } | |
| 650 | }); | |
| 651 | ||
| 583 | 652 | test("the cancel form sits in a .bar.mt row for an issue-less agent run and a non-agent run", async () => { |
| 584 | 653 | const agent = createRun(app.db, { |
| 585 | 654 | repoId: repo.id, |