Use local browser automation to verify UI behavior with evidence. First reuse the repo's own Playwright, browser, or Electron harness if it exists; otherwise assemble a temporary local harness around the app's dev server or Chromium debug port.
Use local browser automation to verify UI behavior with evidence. First reuse the repo's own Playwright, browser, or Electron harness if it exists; otherwise assemble a temporary local harness around the app's dev server or Chromium debug port.
24 unchanged lines
- Reproducing UI bugs that depend on real browser focus, keyboard input, scrolling, resizing, or rendering.
- Reproducing UI bugs that depend on real browser focus, keyboard input, scrolling, resizing, or rendering.
- Verifying visual or accessibility changes with screenshots and snapshots.
- Verifying visual or accessibility changes with screenshots and snapshots.
- Checking local web, IDE, or Electron behavior before shipping.
- Checking local web, IDE, or Electron behavior before shipping.
- Capturing console logs, network logs, CPU profiles, traces, or heap snapshots.
- Capturing console logs, network logs, CPU profiles, traces, or heap snapshots.
- Creating before/after evidence for `verify-this`.
- Creating before/after evidence for `verify-this`.
## Setup Pattern
## Setup Pattern
1. Start the app locally using the repo's documented dev command.
1. Start the app locally using the repo's documented dev command.
2. Discover existing local harnesses: Playwright tests, Cypress specs, Storybook, browser scripts, Electron launch scripts, or snapshot tools.
2. Discover existing local harnesses: Playwright tests, Cypress specs, Storybook, browser scripts, Electron launch scripts, or snapshot tools.
3. For a web app, connect to the local URL with the existing browser tooling.
3. For a web app, connect to the local URL with the existing browser tooling.
4. For Electron/Chromium, enable a remote debugging port when supported.
4. For Electron/Chromium, enable a remote debugging port when supported.
5. Select the correct page by stable app markers, not by tab order alone.
5. Select the correct page by stable app markers, not by tab order alone.
6. Prefer accessibility roles, labels, and stable `data-*` selectors over coordinates.
6. Prefer accessibility roles, labels, and stable `data-*` selectors over coordinates.
## Generic Web Harness
## Generic Web Harness
Use the repo's installed browser tooling when possible. If the repo already has Playwright, a minimal one-off probe looks like:
Use the repo's installed browser tooling when possible. If the repo already has Playwright, a minimal one-off probe looks like:
```javascript
```javascript
import { chromium } from "playwright";
import { chromium } from "playwright";
const browser = await chromium.launch();
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
await page.getByRole("button", { name: /submit/i }).click();
await page.getByRole("button", { name: /submit/i }).click();
24 unchanged lines
Do not add Playwright as a project dependency just for this probe unless the user asks. Prefer existing dev dependencies or external browser tools already available in the environment.
Do not add Playwright as a project dependency just for this probe unless the user asks. Prefer existing dev dependencies or external browser tools already available in the environment.
## Generic CDP Harness
## Generic CDP Harness
For Electron or a Chromium app launched with `--remote-debugging-port=<port>`, connect over CDP:
For Electron or a Chromium app launched with `--remote-debugging-port=<port>`, connect over CDP:
```javascript
```javascript
import { chromium } from "playwright";
import { chromium } from "playwright";
const browser = await chromium.connectOverCDP("http://127.0.0.1:<debug-port>");
const browser = await chromium.connectOverCDP("http://127.0.0.1:<debug-port>");
const pages = browser.contexts().flatMap((context) => context.pages());
const pages = browser.contexts().flatMap((context) => context.pages());
for (const candidate of pages) {
for (const candidate of pages) {
if (await candidate.locator("<app-root-selector>").count()) {
if (await candidate.locator("<app-root-selector>").count()) {
page = candidate;
page = candidate;
console.log(await Promise.all(pages.map(async (p) => ({
console.log(await Promise.all(pages.map(async (p) => ({
title: await p.title(),
title: await p.title(),
url: p.url(),
url: p.url(),
3. Perform exactly one structural action: click, type, keypress, drag, scroll, navigate, or resize.
3. Perform exactly one structural action: click, type, keypress, drag, scroll, navigate, or resize.
20 unchanged lines
Use raw CDP only when higher-level browser APIs are insufficient:
Use raw CDP only when higher-level browser APIs are insufficient:
- Performance: CPU profiles, traces, paint flashing, FPS meter, layout shift inspection.
- Performance: CPU profiles, traces, paint flashing, FPS meter, layout shift inspection.
- Memory: heap snapshots and forced GC for leak investigations.
- Memory: heap snapshots and forced GC for leak investigations.
- Network: request blocking, throttling, cache disablement, request/response logs.
- Network: request blocking, throttling, cache disablement, request/response logs.
- Rendering: viewport changes, color scheme emulation, reduced motion, accessibility checks.
- Rendering: viewport changes, color scheme emulation, reduced motion, accessibility checks.
- Debugging: console streaming, exception capture, DOM snapshots.
- Debugging: console streaming, exception capture, DOM snapshots.
## Page Selection
## Page Selection
When multiple app windows/tabs share a debug port:
When multiple app windows/tabs share a debug port:
- Prefer a positive marker for the surface under test, such as an app root selector.
- Prefer a positive marker for the surface under test, such as an app root selector.
- Use a negative marker to avoid the wrong surface when necessary.
- Use a negative marker to avoid the wrong surface when necessary.
- If no page matches, list available page titles and URLs instead of guessing.
- If no page matches, list available page titles and URLs instead of guessing.
## Guardrails
## Guardrails
- Do not rely on stale element references after navigation or structural changes.
- Do not rely on stale element references after navigation or structural changes.
- Avoid coordinate clicks unless a fresh screenshot was captured immediately before the click.
- Avoid coordinate clicks unless a fresh screenshot was captured immediately before the click.
- Do not hard-code selectors, ports, or script paths from another repository. Discover the current repo's local app markers.
- Do not hard-code selectors, ports, or script paths from another repository. Discover the current repo's local app markers.
- Clean up dev servers, debug sessions, and temp profiles when done.
- Clean up dev servers, debug sessions, and temp profiles when done.