11// A fresh user signs up in a real browser, the client sets up its workspace
22// over stock routes, connects a placeholder provider, and creates a first
33// workbench that shows up in the sidebar. Asserts on visible UI only.
4- import { expect , test } from "bun:test" ;
5- import type { Page } from "puppeteer-core" ;
4+ import { test } from "bun:test" ;
65import { bootBrowserApp , browserGate } from "../lib/browser" ;
6+ import { runFirstRunFlow } from "../lib/first-run" ;
77
88const describeBrowser = browserGate ( import . meta. path ) ;
9- const STEP_TIMEOUT = 60_000 ;
10- const FIRST_WORKBENCH = "Summarize what shipped this week" ;
11-
12- // Page scripts are strings: this tsconfig has no DOM lib.
13- async function waitForText ( page : Page , label : string ) : Promise < void > {
14- await page . waitForFunction ( `document.body.innerText.includes(${ JSON . stringify ( label ) } )` , {
15- timeout : STEP_TIMEOUT ,
16- } ) ;
17- }
18-
19- async function clickText ( page : Page , selector : string , label : string ) : Promise < void > {
20- const script = `Array.from(document.querySelectorAll(${ JSON . stringify ( selector ) } )).find((e) => e.textContent.includes(${ JSON . stringify ( label ) } ))` ;
21- await page . waitForFunction ( script , { timeout : STEP_TIMEOUT } ) ;
22- await page . evaluate ( `(${ script } ).click()` ) ;
23- }
24-
25- async function runFlow ( page : Page , origin : string ) : Promise < void > {
26- await page . goto ( origin , { waitUntil : "networkidle0" } ) ;
27-
28- await clickText ( page , "button" , "Create an account" ) ;
29- await waitForText ( page , "Create your account" ) ;
30- await page . type ( "input[type=email]" , `alice+${ String ( Date . now ( ) ) } @example.com` ) ;
31- await page . type ( "input[type=password]" , "correct-horse-battery-staple" ) ;
32- await page . click ( "button[type=submit]" ) ;
33-
34- // Provider connect is the only onboarding step; a placeholder key is
35- // enough because connecting stores a credential without calling the provider.
36- await waitForText ( page , "Connect a brain" ) ;
37- await clickText ( page , "label" , "Anthropic" ) ;
38- await page . waitForSelector ( "input[type=password]" ) ;
39- await page . type ( "input[type=password]" , "sk-ant-placeholder" ) ;
40- await clickText ( page , "button" , "Connect" ) ;
41-
42- // Connecting installs Myra, then the ready screen hands off to the
43- // new-workbench prompt (a workspace with no workbenches).
44- await clickText ( page , "button" , "Start your first workbench" ) ;
45- await page . waitForSelector ( "textarea" , { timeout : STEP_TIMEOUT } ) ;
46- await page . type ( "textarea" , FIRST_WORKBENCH ) ;
47- await page . click ( "button[aria-label='Start this workbench']" ) ;
48-
49- // Creating the workbench navigates to its own page, which shows the prompt.
50- await page . waitForFunction ( `location.pathname.startsWith("/w/")` , { timeout : STEP_TIMEOUT } ) ;
51- await waitForText ( page , FIRST_WORKBENCH ) ;
52- expect ( new URL ( page . url ( ) ) . pathname ) . toStartWith ( "/w/" ) ;
53- }
549
5510// The test database outlives a run, so each run signs up a distinct alice.
5611describeBrowser ( "first run" , ( ) => {
@@ -59,7 +14,7 @@ describeBrowser("first run", () => {
5914 test ( "sign up, connect a provider, create a first workbench" , async ( ) => {
6015 const { page, errors } = await app ( ) . newPage ( ) ;
6116 try {
62- await runFlow ( page , app ( ) . origin ) ;
17+ await runFirstRunFlow ( page , app ( ) . origin ) ;
6318 } catch ( cause ) {
6419 const body = await page . evaluate ( "document.body.innerText" ) ;
6520 process . stderr . write (
0 commit comments