Skip to content

Commit 3605347

Browse files
authored
Navigate multi-actor browser sessions (#1948)
1 parent 95a3778 commit 3605347

2 files changed

Lines changed: 41 additions & 0 deletions

File tree

packages/runtime-playground/src/browser-multi-actor-scenario-runner.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { Page } from "playwright"
12
import { type BrowserMultiActorScenario, type RuntimeCreateSpec } from "@automattic/wp-codebox-core"
23
import { now } from "@automattic/wp-codebox-core/internals"
34
import { BrowserArtifactSession } from "./browser-artifact-session.js"
@@ -35,6 +36,7 @@ export async function runBrowserMultiActorScenarioCommand(input: {
3536

3637
try {
3738
const clientEntries: Array<[string, BrowserMultiActorClient]> = []
39+
const actorPages: Array<{ actor: string; page: Pick<Page, "goto"> }> = []
3840
// Playground PHP commands share one runtime endpoint, so provision identities
3941
// and install cookies serially before actions begin concurrently.
4042
for (const actor of scenario.actors) {
@@ -50,8 +52,10 @@ export async function runBrowserMultiActorScenarioCommand(input: {
5052
const networkTasks: Array<Promise<void>> = []
5153
attachBrowserCaptureListeners({ captureConsole: captures.has("console"), captureErrors: captures.has("errors"), captureNetwork: true, consoleMessages: actorEvidence.console, errors: actorEvidence.errors, network: actorEvidence.network, networkTasks, page })
5254
clientEntries.push([actor.name, actorClient({ actor: actor.name, artifacts, captures, context, evidence: actorEvidence, networkTasks, page, scenario, previewOrigin: topology.preview.effectiveOrigin })])
55+
actorPages.push({ actor: actor.name, page })
5356
}
5457
const clients = Object.fromEntries(clientEntries)
58+
await navigateBrowserMultiActorPages(actorPages, topology.resolveUrl(scenario.url))
5559
result = await runBrowserMultiActorScenario(scenario, clients)
5660
} catch (error) {
5761
failure = error instanceof Error ? error : new Error(String(error))
@@ -78,6 +82,20 @@ export async function runBrowserMultiActorScenarioCommand(input: {
7882
return { artifact, output: `${JSON.stringify({ command: "wordpress.browser-scenario", files: artifact.files, summary: artifact.summary, scenario: summary }, null, 2)}\n` }
7983
}
8084

85+
export async function navigateBrowserMultiActorPages(
86+
actorPages: Array<{ actor: string; page: Pick<Page, "goto"> }>,
87+
url: string,
88+
): Promise<void> {
89+
await Promise.all(actorPages.map(async ({ actor, page }) => {
90+
try {
91+
await page.goto(url, { waitUntil: "load" })
92+
} catch (error) {
93+
const message = error instanceof Error ? error.message : String(error)
94+
throw new Error(`Actor ${actor} failed to navigate to ${url}: ${message}`)
95+
}
96+
}))
97+
}
98+
8199
interface ActorEvidence {
82100
console: Record<string, unknown>[]
83101
errors: BrowserProbeErrorRecord[]

tests/browser-multi-actor-scenario.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,29 @@
11
import assert from "node:assert/strict"
22
import { BROWSER_MULTI_ACTOR_SCENARIO_SCHEMA, type BrowserMultiActorScenario } from "../packages/runtime-core/src/browser-multi-actor-scenario-contracts.js"
33
import { BrowserMultiActorScenarioError, runBrowserMultiActorScenario, type BrowserMultiActorClient } from "../packages/runtime-playground/src/browser-multi-actor-scenario.js"
4+
import { navigateBrowserMultiActorPages } from "../packages/runtime-playground/src/browser-multi-actor-scenario-runner.js"
5+
6+
const navigationStarted: string[] = []
7+
let releaseNavigation!: () => void
8+
const navigationRelease = new Promise<void>((resolve) => { releaseNavigation = resolve })
9+
const navigation = navigateBrowserMultiActorPages([
10+
{ actor: "author", page: { async goto(url) { navigationStarted.push(`author:${url}`); await navigationRelease; return null } } },
11+
{ actor: "reviewer", page: { async goto(url) { navigationStarted.push(`reviewer:${url}`); await navigationRelease; return null } } },
12+
], "https://example.test/wp-admin/post.php?post=1&action=edit")
13+
await new Promise((resolve) => setTimeout(resolve, 0))
14+
assert.deepEqual(navigationStarted, [
15+
"author:https://example.test/wp-admin/post.php?post=1&action=edit",
16+
"reviewer:https://example.test/wp-admin/post.php?post=1&action=edit",
17+
])
18+
releaseNavigation()
19+
await navigation
20+
21+
await assert.rejects(
22+
navigateBrowserMultiActorPages([
23+
{ actor: "reviewer", page: { async goto() { throw new Error("net::ERR_FAILED") } } },
24+
], "https://example.test/editor"),
25+
/Actor reviewer failed to navigate to https:\/\/example\.test\/editor: net::ERR_FAILED/,
26+
)
427

528
const closed: string[] = []
629
const actions: string[] = []

0 commit comments

Comments
 (0)