mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
* feat(browser): replace flat snapshot with ARIA tree and page-side refs * feat(browser): trusted CDP input with actionability waits * feat(browser): auto-handle javascript dialogs * feat(browser): add browser_evaluate * feat(browser): add scroll, resize, and close_tab tools * fix(browser): review fixes for snapshot/input/dialog seams * fix(browser): address review findings on dialog capture, truncation, and keypress targets * fix(harness): drop resize check that cannot run under parked compositor surfaces * fix(browser): second review round — snapshot fidelity, key input, dialog scoping
70 lines
3.4 KiB
Markdown
70 lines
3.4 KiB
Markdown
# Browser Capture Harness
|
|
|
|
The desktop capture harness is the real-Electron verification path for browser screenshots.
|
|
It validates the compositor behavior that unit tests cannot see:
|
|
|
|
- the resident automation `<webview>` starts in the production parking state;
|
|
- the parked guest remains paintable and has a copyable viewport frame;
|
|
- the resident webview guest is sized to 1280x800 logical pixels;
|
|
- multiple resident webviews are parked as an overlapping stack without per-capture
|
|
stacking changes;
|
|
- a newly attached resident webview whose first useful frame is delayed can be captured
|
|
by retrying until the frame appears;
|
|
- both viewport `capturePage` and full-page CDP screenshots return real pixels from
|
|
the permanent production parking state;
|
|
- guest background throttling can be disabled once at attach without per-capture
|
|
renderer coordination.
|
|
|
|
Run it with the repo Electron:
|
|
|
|
```bash
|
|
npm run capture-harness --workspace=@getpaseo/desktop
|
|
```
|
|
|
|
Run the browser automation fixture with:
|
|
|
|
```bash
|
|
PASEO_CAPTURE_HARNESS_GROUP=automation npm run capture-harness --workspace=@getpaseo/desktop
|
|
```
|
|
|
|
The automation group uses a real guest webview to verify the page-side ref contract:
|
|
ARIA-like snapshot text includes headings, static text, and controls; refs survive
|
|
`pushState` when the element still matches; same-URL rerenders stale old refs; and a
|
|
file-input ref can be resolved to a CDP backend node id for upload. It also verifies
|
|
page-context evaluation, including passing a resolved ref element as the function argument.
|
|
|
|
On macOS the harness process must set `app.setActivationPolicy("accessory")` and
|
|
hide the Dock icon before creating any window. `showInactive()` only prevents window
|
|
focus; a normal Electron app launch can still activate the app and steal focus.
|
|
Harness windows are then created hidden, positioned in a screen corner, skipped from
|
|
the taskbar where Electron supports it, and revealed with `showInactive()` from
|
|
`ready-to-show`. Do not replace this with `show()`, `focus()`, or `app.focus()`:
|
|
the compositor only needs visible inactive windows, and harness runs must not steal
|
|
focus from the person using the machine.
|
|
|
|
The harness writes PNG evidence and `results.json` to:
|
|
|
|
```text
|
|
packages/desktop/capture-harness/out/
|
|
```
|
|
|
|
A passing run prints `PASS` lines for the production P1 attach-off parking state,
|
|
including fresh, settled, 75-second soak, multi-tab, viewport, and full-page checks. The
|
|
PNG sizes may be device-pixel scaled; on a Retina display the 1280x800 logical viewport
|
|
is usually saved as 2560x1600.
|
|
|
|
## Mechanism
|
|
|
|
Electron captures copy from the guest web contents' compositor surface. A resident
|
|
webview parked with `display:none`, offscreen coordinates, or `opacity:0` can lose its
|
|
copyable surface. The production parking state keeps the host fixed at `left:0`, `top:0`,
|
|
`width:1px`, `height:1px`, `overflow:hidden`, `opacity:1`, and `pointer-events:none`.
|
|
The webviews inside stay full-size at 1280x800, `display:inline-flex`, and absolutely
|
|
overlap at `left:0`, `top:0`.
|
|
|
|
There is no renderer prep/restore handshake. Main disables guest background throttling
|
|
once when the webview attaches, then screenshot capture uses the shared serialized queue,
|
|
invalidates before each attempt, and retries known first-frame failures within the
|
|
5-second capture budget. Viewport screenshots use `capturePage({ stayHidden:false })`;
|
|
full-page screenshots use the existing CDP path with layout metrics and screenshot clip.
|