MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / makeBrowserSurface

Function makeBrowserSurface

e2e/src/surfaces/browser.ts:41–207  ·  view source on GitHub ↗
(dir: string, target: Target)

Source from the content-addressed store, hash-verified

39// acquireUseRelease so a vitest timeout (fiber interruption) still closes the
40// browser and flushes video + trace — a bare promise would leak Chromium.
41export const makeBrowserSurface = (dir: string, target: Target): BrowserSurface => ({
42 session: (identity, drive) =>
43 Effect.acquireUseRelease(
44 Effect.promise(async () => {
45 const videoTmp = join(dir, ".video-tmp");
46 mkdirSync(videoTmp, { recursive: true });
47
48 // Watchable mode (E2E_FILM / E2E_DESK): slow each Playwright action so
49 // the recording is readable instead of flickering through states at
50 // machine speed. Off by default — normal CI runs stay fast.
51 const watchable = process.env.E2E_FILM === "1" || process.env.E2E_DESK === "1";
52 const slowMo = watchable ? 400 : undefined;
53 // On the desk (E2E_DESK), the browser is a real headed window on the
54 // virtual display — the desk's single screen recording films it next
55 // to the chat terminal, exactly like a developer tabbing over.
56 const browser = await chromium.launch(
57 process.env.E2E_DESK === "1"
58 ? {
59 headless: false,
60 args: ["--window-position=300,40", "--window-size=1100,830"],
61 slowMo,
62 }
63 : slowMo
64 ? { slowMo }
65 : {},
66 );
67 const context = await browser.newContext({
68 colorScheme: "dark",
69 viewport: { width: 1280, height: 800 },
70 recordVideo: { dir: videoTmp, size: { width: 1280, height: 800 } },
71 baseURL: target.baseUrl,
72 });
73 await context.tracing.start({
74 screenshots: true,
75 snapshots: true,
76 sources: true,
77 });
78 // Bake a synthetic URL bar into the recording so a shared session.mp4
79 // (and the step screenshots) shows which page each moment was on.
80 await installRecordingUrlBar(context);
81 if (identity.cookies?.length) {
82 await context.addCookies(
83 identity.cookies.map((cookie) => ({
84 ...cookie,
85 url: target.baseUrl,
86 })),
87 );
88 }
89 const page = await context.newPage();
90 // The session video's clock starts with the page; anchor it for the
91 // run's focus timeline (scripts/film.ts cuts on these).
92 markRecordingStart(dir, "browser");
93 // Main-frame navigations feed the viewer's synthetic URL bar — the
94 // recording itself is chromeless, so this is the only place the
95 // address the developer "typed" survives.
96 page.on("framenavigated", (frame) => {
97 if (frame === page.mainFrame()) markNavigation(dir, frame.url());
98 });

Callers 1

contextForFunction · 0.90

Calls 13

installRecordingUrlBarFunction · 0.90
markRecordingStartFunction · 0.90
markNavigationFunction · 0.90
appendTracesFunction · 0.90
execMethod · 0.80
pushMethod · 0.80
setMethod · 0.80
videoMethod · 0.80
startMethod · 0.65
getMethod · 0.65
deleteMethod · 0.65
responseMethod · 0.65

Tested by

no test coverage detected