@@ -12,7 +12,8 @@ import { browserAssertionsSummary, browserStepRecord, executeBrowserInteractionS
1212import { browserCommandLivenessPolicy , isBrowserCommandLivenessError , withBrowserCommandLiveness } from "./browser-liveness.js"
1313import { serializeBrowserError } from "./browser-metrics.js"
1414import { executeBrowserObservationAssertion } from "./browser-observation-assertions.js"
15- import { browserPreviewNetworkPolicyIsActive , browserPreviewNetworkPolicySummary , browserPreviewNeedsContextRouting , browserPreviewReadinessError , browserPreviewTopology , resolveBrowserPreviewUrl , routeBrowserPreviewContextNetwork } from "./browser-preview-routing.js"
15+ import { browserPreviewNetworkPolicyIsActive , browserPreviewNetworkPolicySummary , browserPreviewNeedsContextRouting , browserPreviewReadinessError , browserPreviewTopology , closeBrowserAndDrainPreviewRoutes , createBrowserPreviewRouteTracker , resolveBrowserPreviewUrl , routeBrowserPreviewContextNetwork } from "./browser-preview-routing.js"
16+ import { browserCommandResult } from "./browser-result-sanitization.js"
1617import { BROWSER_PROBE_STATE_INIT_SCRIPT , browserProbeReplayability , browserProbeViewport } from "./browser-probe.js"
1718import { runBrowserProbeCommand , type BrowserProbeRunPlan } from "./browser-probe-runner.js"
1819import { browserActionTargetUrls , browserAuthRequest , browserProbeWaterfallArtifact , browserProbeWebSocketArtifact , browserProbeWebSocketSummary , browserRedirectDiagnosticsArtifact , browserRequestCoverageArtifact , browserStorageStateAuthSummary , browserStorageStateImportFromArgs , browserWordPressDiagnosticsArtifact , createBrowserProbeProgressTracker , fileSha256 , installBrowserWordPressDiagnostics , installWordPressAdminAuthCookies , livenessRemainingWallTimeMs , normalizeBrowserProbeScriptCheckpoint , type BrowserCommandProgressEvent , type BrowserStorageStateImport } from "./browser-probe-support.js"
@@ -133,6 +134,7 @@ export async function runBrowserActionsCommand({
133134 const browser = session ?. browser ?? await launchChromiumBrowser ( )
134135 const topology = browserPreviewTopology ( args , runtimeSpec , server . serverUrl , server . previewProxyDiagnostics ?. targetOrigin )
135136 const { preview, networkPolicy } = topology
137+ const routeTracker = session ?. routeTracker ?? createBrowserPreviewRouteTracker ( )
136138 let requestedUrl = initialUrl ? topology . resolveUrl ( initialUrl ) : preview . effectiveOrigin
137139 let finalUrl = requestedUrl
138140 let htmlSha256 : string | undefined
@@ -173,7 +175,7 @@ export async function runBrowserActionsCommand({
173175 } ) : undefined )
174176 const context = environmentRuntime ?. context ?? null
175177 if ( context && ! session ) {
176- await routeBrowserPreviewContextNetwork ( context , networkPolicy , topology . origins . localProxyOrigin )
178+ await routeBrowserPreviewContextNetwork ( context , networkPolicy , topology . origins . localProxyOrigin , routeTracker )
177179 }
178180 const page = activePage = environmentRuntime ?. page ?? await browser . newPage ( )
179181 if ( onProgress ) {
@@ -437,11 +439,12 @@ export async function runBrowserActionsCommand({
437439 pendingError = error instanceof Error ? error : new Error ( String ( error ) )
438440 errors . push ( serializeBrowserError ( "probe-error" , error ) )
439441 } finally {
440- await settleBrowserNetworkTasks ( networkTasks , livenessPolicy . networkSettleTimeoutMs )
442+ await settleBrowserNetworkTasks ( networkTasks , livenessPolicy . networkSettleTimeoutMs ) . catch ( ( error ) => errors . push ( serializeBrowserError ( "probe-error" , error ) ) )
441443 if ( activePage && resolvedEnvironment ) environmentEvidence = await observePlaywrightBrowserEnvironment ( activePage , requestedEnvironment , resolvedEnvironment ) . catch ( ( ) => environmentEvidence )
442- if ( ! session ) {
443- await environmentRuntime ?. close ( ) . catch ( ( ) => undefined )
444- await browser . close ( )
444+ const cleanupBrowser = session ? { close : async ( ) => { } } : { close : async ( ) => { await environmentRuntime ?. close ( ) ; await browser . close ( ) } }
445+ for ( const routeError of await closeBrowserAndDrainPreviewRoutes ( cleanupBrowser , routeTracker ) ) {
446+ errors . push ( serializeBrowserError ( "probe-error" , routeError ) )
447+ pendingError ??= routeError
445448 }
446449 if ( capture . has ( "steps" ) ) {
447450 await artifactSession . writeJsonLines ( "steps" , "steps.jsonl" , stepRecords )
@@ -580,9 +583,7 @@ export async function runBrowserActionsCommand({
580583 throw new Error ( "wordpress.browser-actions did not produce a browser artifact" )
581584 }
582585
583- return {
584- artifact,
585- output : `${ JSON . stringify ( {
586+ return browserCommandResult ( artifact , {
586587 command : "wordpress.browser-actions" ,
587588 requestedUrl,
588589 preview,
@@ -591,8 +592,7 @@ export async function runBrowserActionsCommand({
591592 files : artifact . files ,
592593 summary : artifact . summary ,
593594 steps : stepRecords ,
594- } , null , 2 ) } \n`,
595- }
595+ } )
596596}
597597
598598export function browserToolVerifierUnsupportedResult ( step : BrowserInteractionStep , index : number , startedAt : string ) : BrowserToolVerifierResult {
@@ -967,6 +967,7 @@ export async function runBrowserScenarioCommand({
967967 let pendingError : Error | undefined
968968 let scenarioSession : PlaywrightBrowserEnvironmentSession | undefined
969969 let scenarioBrowser : Awaited < ReturnType < typeof launchChromiumBrowser > > | undefined
970+ let scenarioRouteTracker : ReturnType < typeof createBrowserPreviewRouteTracker > | undefined
970971
971972 try {
972973 if ( runPlan . probe && runPlan . actions ) {
@@ -976,12 +977,16 @@ export async function runBrowserScenarioCommand({
976977 if ( unsupported . length > 0 ) {
977978 throw new Error ( `wordpress.browser-scenario browser environment is unsupported: ${ unsupported . join ( ", " ) } ` )
978979 }
980+ const topology = browserPreviewTopology ( args , runtimeSpec , server . serverUrl , server . previewProxyDiagnostics ?. targetOrigin )
979981 const runtime = await createPlaywrightBrowserEnvironmentContext ( browser , resolved , {
980- ...( runPlan . actions . storageStateImport ? { contextOptions : { storageState : runPlan . actions . storageStateImport . storageState } } : { } ) ,
982+ contextOptions : {
983+ ...topology . contextOptions ( ) ,
984+ ...( runPlan . actions . storageStateImport ? { storageState : runPlan . actions . storageStateImport . storageState } : { } ) ,
985+ } ,
981986 } )
982- const topology = browserPreviewTopology ( args , runtimeSpec , server . serverUrl )
983- if ( browserPreviewNeedsContextRouting ( topology . networkPolicy ) ) await routeBrowserPreviewContextNetwork ( runtime . context , topology . networkPolicy , topology . preview . effectiveOrigin )
984- scenarioSession = { browser, requested : requestedEnvironment , resolved, runtime }
987+ const routeTracker = scenarioRouteTracker = createBrowserPreviewRouteTracker ( )
988+ if ( browserPreviewNeedsContextRouting ( topology . networkPolicy ) ) await routeBrowserPreviewContextNetwork ( runtime . context , topology . networkPolicy , topology . origins . localProxyOrigin , routeTracker )
989+ scenarioSession = { browser, requested : requestedEnvironment , resolved, routeTracker , runtime }
985990 }
986991
987992 if ( runPlan . probe ) {
@@ -1006,8 +1011,15 @@ export async function runBrowserScenarioCommand({
10061011 }
10071012 }
10081013 } finally {
1009- await scenarioSession ?. runtime . close ( ) . catch ( ( ) => undefined )
1010- await scenarioBrowser ?. close ( ) . catch ( ( ) => undefined )
1014+ if ( scenarioSession && scenarioBrowser && scenarioRouteTracker ) {
1015+ const activeSession = scenarioSession
1016+ const activeBrowser = scenarioBrowser
1017+ const cleanupBrowser = { close : async ( ) => { await activeSession . runtime . close ( ) ; await activeBrowser . close ( ) } }
1018+ const routeErrors = await closeBrowserAndDrainPreviewRoutes ( cleanupBrowser , scenarioRouteTracker )
1019+ pendingError ??= routeErrors [ 0 ]
1020+ } else {
1021+ await scenarioBrowser ?. close ( ) . catch ( ( ) => undefined )
1022+ }
10111023 }
10121024
10131025 const primaryArtifact = actionsResult ?. artifact ?? probeResult ?. artifact
@@ -1067,17 +1079,14 @@ export async function runBrowserScenarioCommand({
10671079 throw new BrowserCommandArtifactError ( `wordpress.browser-scenario failed: ${ pendingError . message } ` , artifact )
10681080 }
10691081
1070- return {
1071- artifact,
1072- output : `${ JSON . stringify ( {
1082+ return browserCommandResult ( artifact , {
10731083 command : "wordpress.browser-scenario" ,
10741084 requestedUrl : artifact . requestedUrl ,
10751085 finalUrl,
10761086 files : artifact . files ,
10771087 summary : artifact . summary ,
10781088 scenario : scenarioSummary ,
1079- } , null , 2 ) } \n`,
1080- }
1089+ } )
10811090}
10821091
10831092async function browserScenarioFromArgs ( args : string [ ] ) : Promise < BrowserScenarioInput > {
0 commit comments