Files
orca/tests/e2e/helpers/plugin-panel-navigation-observer.ts
T
JinjingandOrcaWin a40183389b feat: bound direct SSH reconnect fan-out and recovery (#11003)
* docs: design for direct SSH reconnect fan-out

Capture the implementation-ready plan for host-qualified, epoch-fenced
SSH reconnect recovery after two rounds of multi-model LLM counsel review.

* docs: reconcile SSH reconnect fan-out design

* docs: close reconnect design consistency gaps

* feat: implement bounded direct SSH reconnect recovery

* fix: bound direct SSH retry settlement

* fix: harden direct SSH reconnect authority

* fix: preserve split SSH retry ownership

* fix: preserve SSH split continuation authority

* docs: record final SSH reconnect validation

* fix: preserve SSH authority through retained and detached state

* fix: retain SSH authority across delayed split mounts

* fix: close SSH authority recovery gaps

* fix: fence stale SSH transport replacement

* fix: serialize SSH target teardown

* fix: settle SSH teardown failures before reconnect

* fix: retire failed SSH reset sessions

* test: reconcile current main E2E contracts

* fix: close direct SSH reconnect review gaps

* fix: fence stale SSH reconnect side effects

* fix: close final SSH reconnect lifecycle gaps

* test: stabilize current-main reliability gates

* test: prove plugin navigation containment

* test: make plugin navigation oracle authoritative

* test: make plugin navigation oracle deterministic

* ci: allow sharded e2e suite to finish

* test: wait for runtime pane publication

* test: classify pane readiness by error code

* test: select close persistence terminal by tab identity

* docs: mark reconnect implementation validated

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-07-28 12:33:17 -07:00

109 lines
3.6 KiB
TypeScript

import type { ElectronApplication } from '@stablyai/playwright-test'
import type { Event as ElectronEvent, WebContentsWillFrameNavigateEventParams } from 'electron'
export type PanelNavigationObservation = {
willFrameNavigations: { defaultPrevented: boolean; isMainFrame: boolean; url: string }[]
didFrameNavigations: { isMainFrame: boolean; url: string }[]
externalUrls: string[]
}
type MainPanelNavigationProbe = {
dispose: () => void
observation: PanelNavigationObservation
}
export async function startPanelNavigationObserver(
electronApp: ElectronApplication,
pageUrl: string
): Promise<void> {
await electronApp.evaluate(({ BrowserWindow, shell }, expectedUrl) => {
const browserWindow =
BrowserWindow.getAllWindows().find(
(candidate) => candidate.webContents.getURL() === expectedUrl
) ?? BrowserWindow.getAllWindows()[0]
if (!browserWindow) {
throw new Error('main window unavailable for panel navigation observer')
}
const contents = browserWindow.webContents
const observation: PanelNavigationObservation = {
willFrameNavigations: [],
didFrameNavigations: [],
externalUrls: []
}
const onWillFrameNavigate = (
event: ElectronEvent<WebContentsWillFrameNavigateEventParams>
): void => {
observation.willFrameNavigations.push({
defaultPrevented: event.defaultPrevented,
isMainFrame: event.isMainFrame,
url: event.url
})
}
const onDidFrameNavigate = (
_event: ElectronEvent,
url: string,
_httpResponseCode: number,
_httpStatusText: string,
isMainFrame: boolean
): void => {
observation.didFrameNavigations.push({ isMainFrame, url })
}
const probeGlobal = globalThis as typeof globalThis & {
__orcaPanelNavigationProbe?: MainPanelNavigationProbe
}
probeGlobal.__orcaPanelNavigationProbe?.dispose()
const originalOpenExternal = shell.openExternal
const recordOpenExternal = async (url: string): Promise<void> => {
observation.externalUrls.push(url)
}
contents.on('will-frame-navigate', onWillFrameNavigate)
contents.on('did-frame-navigate', onDidFrameNavigate)
shell.openExternal = recordOpenExternal
probeGlobal.__orcaPanelNavigationProbe = {
observation,
dispose: () => {
contents.off('will-frame-navigate', onWillFrameNavigate)
contents.off('did-frame-navigate', onDidFrameNavigate)
if (shell.openExternal === recordOpenExternal) {
shell.openExternal = originalOpenExternal
}
}
}
}, pageUrl)
}
export async function readPanelNavigationObserver(
electronApp: ElectronApplication
): Promise<PanelNavigationObservation> {
return electronApp.evaluate(() => {
const probe = (
globalThis as typeof globalThis & {
__orcaPanelNavigationProbe?: MainPanelNavigationProbe
}
).__orcaPanelNavigationProbe
if (!probe) {
throw new Error('panel navigation observer is not active')
}
return structuredClone(probe.observation)
})
}
export async function stopPanelNavigationObserver(
electronApp: ElectronApplication
): Promise<PanelNavigationObservation> {
return electronApp.evaluate(() => {
const probeGlobal = globalThis as typeof globalThis & {
__orcaPanelNavigationProbe?: MainPanelNavigationProbe
}
const probe = probeGlobal.__orcaPanelNavigationProbe
if (!probe) {
throw new Error('panel navigation observer is not active')
}
const observation = structuredClone(probe.observation)
probe.dispose()
delete probeGlobal.__orcaPanelNavigationProbe
return observation
})
}