Skip to content

Commit 746f289

Browse files
committed
e2e: drop the cli browser tool; develop with Playwright directly
Developing against the UI is just running Playwright, which is already in-repo and is the same thing a scenario() runs, so no bespoke browser command or daemon is needed. Use `cli up` for an instance and `cli identity` for a logged-in context, then write and run Playwright. Removes src/devbrowser.ts and the `cli browser` command.
1 parent 2bb0565 commit 746f289

3 files changed

Lines changed: 5 additions & 411 deletions

File tree

e2e/AGENTS.md

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -130,33 +130,6 @@ When handing results to the user, follow the evidence contract in the root
130130
[AGENTS.md](../AGENTS.md) (direct run links + a live instance + what to try);
131131
[RUNNING.md](../RUNNING.md) has the current sharing/demo mechanics.
132132

133-
## Driving the app while developing (`cli browser`)
134-
135-
The dev CLI can spin up a real browser pointed at a running instance and already
136-
signed in, so you can develop against the UI the way a test does. It is the SAME
137-
browser the `Browser` test surface uses (Chromium, dark mode, 1280x800, the
138-
identity's cookies), so developing with it and writing a `scenario()` are the
139-
same primitive: you drive it to figure the flow out, then write the scenario with
140-
those surfaces. There is no recording or codegen between the two.
141-
142-
```sh
143-
cd e2e
144-
bun run cli up cloud # a live instance
145-
bun run cli browser cloud up # logged-in browser, prints a CDP endpoint + page controls
146-
bun run cli browser cloud goto /policies # drive it; each verb prints the page's controls + a screenshot
147-
bun run cli browser cloud click "Add policy"
148-
bun run cli browser cloud look # re-read the page (url, title, controls)
149-
bun run cli browser cloud down # stop it
150-
```
151-
152-
Verbs: `goto <path>`, `click <text>` (matches a link/button by name, else any
153-
text), `fill <field> <value>`, `type <text>`, `press <key>`, `eval <js>`, `look`.
154-
`up --headed` shows a real window (for a human to watch); `up --no-org` signs in
155-
without an active org. The browser is a detached process that persists across
156-
calls; its state lives in `.dev/<target>.browser.json` (gitignored). Because it
157-
exposes CDP, you can also point any CDP-speaking tool (Playwright `connectOverCDP`,
158-
devtools, an agent's own browser automation) at the printed endpoint.
159-
160133
## Desktop targets (the app on real OSes, filmed)
161134

162135
The packaged desktop app runs as its own targets, each landing in its own

e2e/scripts/cli.ts

Lines changed: 5 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@
77
// bun scripts/cli.ts api <target> <group.endpoint> [json]
88
// bun scripts/cli.ts mcp <target> tools | call <tool> [json]
99
// bun scripts/cli.ts ledger <target> [workos|autumn]
10-
// bun scripts/cli.ts browser <target> up|goto|click|fill|press|eval|look|down
1110
// bun scripts/cli.ts logs <target>
1211
// bun scripts/cli.ts down <target>
1312
//
14-
// Develop against a live instance with the exact machinery the tests use (same
15-
// boot recipe, same Target/identity/surfaces), then write scenarios with those
16-
// same surfaces. `up` leaves the instance running until `down` — it IS the
17-
// handoff demo (AGENTS.md: evidence, not assertions). `--share` makes it
18-
// reachable over the user's tailnet.
13+
// Develop against a live instance with the exact machinery the tests use
14+
// (same boot recipe, same Target/identity/surfaces), then crystallize the
15+
// journey into a scenario. `up` leaves the instance running until `down` —
16+
// it IS the handoff demo (AGENTS.md: evidence, not assertions). `--share`
17+
// makes it reachable over the user's tailnet.
1918
//
2019
// Instances are tracked in .dev/<target>.json: a state file marks a
2120
// DELIBERATE long-lived instance (not a leak). Cloud's WorkOS/Autumn
@@ -444,59 +443,6 @@ const ledger = async (targetName: string, service = "workos") => {
444443
console.log(JSON.stringify(entries, null, 2));
445444
};
446445

447-
// --- browser (drive the live app while developing) -------------------------
448-
// Spin up a real, logged-in browser pointed at the running instance and target
449-
// it: drive it with the verbs here, or connect anything that speaks CDP to the
450-
// printed endpoint. The same browser the Browser test surface uses, so this and
451-
// a scenario() are the same primitive — no recording, no codegen.
452-
453-
const printObservation = (obs: import("../src/devbrowser").Observation) => {
454-
console.log(`→ ${obs.url} ${JSON.stringify(obs.title)}`);
455-
if (obs.cdpUrl) console.log(` cdp: ${obs.cdpUrl} (point any CDP browser tool here)`);
456-
console.log(` screenshot: ${obs.screenshot}`);
457-
if (obs.evalResult !== undefined) console.log(` eval: ${obs.evalResult}`);
458-
if (obs.controls.length > 0) {
459-
console.log("controls (role · name):");
460-
for (const control of obs.controls.slice(0, 40)) {
461-
console.log(` ${control.role.padEnd(9)} ${control.name}`);
462-
}
463-
if (obs.controls.length > 40) console.log(` … ${obs.controls.length - 40} more`);
464-
}
465-
};
466-
467-
const browser = async (raw: ReadonlyArray<string>) => {
468-
const target = raw[0];
469-
const verb = raw[1];
470-
if (!target || !verb) {
471-
throw new Error(
472-
"usage: browser <target> up [--headed] [--no-org] | goto <path> | click <text> | " +
473-
"fill <field> <value> | type <text> | press <key> | eval <js> | look | down",
474-
);
475-
}
476-
const { spinUp, drive, shut } = await import("../src/devbrowser");
477-
478-
if (verb === "down") {
479-
await shut(devDir, target);
480-
return console.log(`${target}: browser down`);
481-
}
482-
if (verb === "up") {
483-
const { target: resolved } = await loadTarget(target);
484-
const identity = await runEffect<import("../src/target").Identity>(
485-
resolved.newIdentity(raw.includes("--no-org") ? { org: false } : undefined),
486-
);
487-
const obs = await spinUp(devDir, target, resolved.baseUrl, identity, raw.includes("--headed"));
488-
return printObservation(obs);
489-
}
490-
// a drive verb against the already-running browser
491-
const obs = await drive(
492-
devDir,
493-
target,
494-
verb,
495-
raw.slice(2).filter((a) => !a.startsWith("--")),
496-
);
497-
printObservation(obs);
498-
};
499-
500446
// --- lifecycle commands ----------------------------------------------------
501447

502448
const status = () => {
@@ -562,18 +508,9 @@ const HELP = `e2e dev CLI — the scenario primitives, interactive (see e2e/AGEN
562508
api <target> <group.endpoint> [json] typed API call as a fresh identity
563509
mcp <target> tools | call <tool> [json] MCP session call
564510
ledger <target> [workos|autumn] the emulator's request ledger (cloud)
565-
browser <target> up [--headed] [--no-org] spin up a logged-in browser on the
566-
running app and leave it running; prints a CDP
567-
endpoint you can target with any browser tool
568-
browser <target> <verb> drive it: goto <path> | click <text> | fill <field>
569-
<value> | type <text> | press <key> | eval <js> |
570-
look | down. Each prints the page's controls + a shot
571511
logs <target> dump the instance's dev-server log
572512
down <target> tear down (kills servers, removes tailscale serves)
573513
574-
The browser is the same one the Browser test surface uses, so developing with it
575-
and writing a scenario() are the same primitive (no recording, no codegen).
576-
577514
Instances live in e2e/.dev/<target>.json — a state file marks a DELIBERATE
578515
long-lived instance. Use the booted instance for e2e too:
579516
E2E_SELFHOST_URL=<app url> vitest run --project selfhost <file>`;
@@ -597,8 +534,6 @@ const main = async () => {
597534
return mcpCall(args[0] ?? "", args[1], args.slice(2));
598535
case "ledger":
599536
return ledger(args[0] ?? "", args[1]);
600-
case "browser":
601-
return browser(rest);
602537
case "logs":
603538
return logs(args[0] ?? "");
604539
case "down":

0 commit comments

Comments
 (0)