agentleFS
dennisrongodennisrongo/claude-skills/skills/e2e-verify/SKILL.md

e2e-verify

Skill1 starsChanged 3 months agoMITView on GitHub

Verify a change end-to-end in a real browser, routed by one question - who needs this check to run again? Ephemeral checks walk the flows; regression-critical ones (auth, money, signup, checkout, deletion) get durable Playwright tests. An AI-walked flow yields "no issues found in the paths walked", never "e2e passes". Never production, never real user cookies. Use this skill whenever the user says "verify this in the browser", "test it end to end", "test my web app", "e2e test this", "write playwright tests", "run expect", "run browser-use", "smoke test the UI", "test my browser extension", or "/e2e-verify" - even if they do not name the skill. Not for native mobile (maestro-mobile-test), unit or integration authoring (write-tests), or debugging a failing e2e test (diagnose).

  • Installs packages

5 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

3 rules. 0 are common, 1 is distinctive, and 2 are very specific to this project.

  • 0

    Common

    Most of the 4 edited versions we read keep these.

  • 1

    Distinctive

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Do not auto-trigger for native mobile apps (maestro-mobile-test), unit/integration authoring (write-tests), debugging an already-failing …

    line 15
  2. Distinctive:

    Every flow walked is enumerated.

    line 54
  3. Very specific:

    Add the Recording: and Delivered: lines exactly as record-browser-test defines them, or Recording: none - <why>.

    line 56

“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

E2E Verify

Close the loop between "the diff looks right" and "a user can actually do the thing." Every route through this skill drives a real browser against running code; what differs is durability. The routing question is not which tool — it's who needs this check to run again? Nobody (one-off confidence in this change) → ephemeral. CI, forever (a behavior whose silent regression is expensive) → durable Playwright test in the repo. Often both: smoke now, durable test as the deliverable.

When to use this skill

  • The user says "verify this in the browser", "test it end to end", "test my web app", "verify the web UI", "e2e test this", "write playwright tests", "run expect", "run browser-use", "smoke test the UI", "does it actually work", "/e2e-verify".
  • A feature from task-executor is done and needs proof beyond unit tests; code-review or ship-it wants runtime evidence.

Do not auto-trigger for native mobile apps (maestro-mobile-test), unit/integration authoring (write-tests), debugging an already-failing e2e test (diagnose), or general browser automation that isn't testing.

The safety gate — before any browser opens

  1. Confirm the target URL is local or staging. State it in the report. If the only available URL is production, stop and ask — never assume.
  2. No real user cookies or accounts. Expect's tui extracts system-browser cookies by default — pass --no-cookies unless the user explicitly opts in for a non-prod target (its subcommands invert this: expect open takes cookies only with --cookies). Expect also records video of every session to an artifacts directory — on a target whose screens carry regulated or personal data, that recording is disclosure surface: know where it lands and delete it. Flows that mutate data (payments, deletion, invites that email people) run only against seeded/throwaway data; if none exists, that's a blocker to surface, not a reason to "carefully" test on real data.
  3. Confirm something is listening. Load the base URL and observe a real response before walking any flow. If nothing answers, start the dev server the repo's own way (its dev script / launch config) and confirm it's up — a dead port produces "every flow is broken", which is a false report about the app. Distinguish "the app failed" from "the app wasn't running" in everything you report.

Route the request

SignalRoute
"Does my change work?", pre-merge confidence, exploratoryA: Ephemeral
The flow is money/auth/signup/checkout/data-loss, or user says "add e2e tests", or the same flow has now been manually re-verified twiceB: Durable
Feature just built and it's a critical flowA now, then B — the smoke run's steps become the test's spec

Keep the user's pointer and focus out of it

A check that needs the person's mouse idle is a check they cannot run while they work, so nobody runs it twice. Drive in-page flows through the browser's debugging protocol (Playwright, CDP, every engine below), which dispatches input inside the page and never moves the OS cursor.

  • ❌ Coordinate clicks or screen-driving computer-use tools for a flow that lives inside the page — they take the real pointer and the real focus.
  • ✅ Protocol-level input, headless or in a window nobody has to watch.
  • OS-level input is for native UI the protocol cannot reach (browser toolbar, native file pickers, permission prompts), only in a driver's background mode, and the report lists that step under Not walked unless it was observed working.
  • Focus counts as much as the pointer. A browser window that opens takes the keyboard, so the user's typing lands in the test browser. Run headless; a visible window needs the user's explicit yes. Observed: a recorder's visible Chrome took the foreground from the user's window while the cursor never moved.
  • Say Input: protocol only after observing it with scripts/pointer-sample.ps1 (Windows): it parks the cursor, then samples the cursor position and the foreground window across the run. Start it in the background, run the test, read its output: one cursor position and no new foreground window is the evidence. The user must keep hands off the mouse and windows for the sampled seconds, or their input is indistinguishable from the tool's. A cursor-only check proves nothing about focus. Otherwise report Input: not checked.

Route A: ephemeral verification

Pick the engine by what's installed — the discipline is identical across engines:

  1. Scripted and recorded (if installed: record-browser-test; probe: its SKILL.md exists in the skills directory, and Chrome is present). Use it when the flow stays on one page after sign-in and someone who did not watch the run will rely on the result: write the walk as a body with a check per requirement-derived expectation and run it recorded, so the video, not your summary, shows what ran; it runs headless by default, which keeps the user's pointer and focus free. Multi-page flows, native dialogs and real-gesture-only handlers fall through to the engines below with Recording: none - <why>.
  2. Expect (/expect in the agent, or expect-cli on PATH): prefer the /expect MCP integration where it is already wired up; the CLI's own TUI is deprecated and prints a banner saying so. Flags live on the tui subcommand, never at the top level — expect --target branch exits with error: unknown option '--target'. Shape per expect tui --help on 0.1.3: expect tui --target branch -u <non-prod-url> --no-cookies -m "<what to test>" -y. Mechanics, platform gotchas and what init writes are in references/expect.md; confirm the invocation with expect --help and expect tui --help rather than trusting either file. Its report is input, not verdict — extract which flows its subagents walked and what they observed.
  3. browser-use (python -c "import browser_use" succeeds, or the user names it): an AI agent drives headless Chromium from natural-language task scripts — strongest for exploratory walking where the agent finds broken flows. Setup, task-writing guidance, structured-output schemas, red-proof discipline, and troubleshooting live in references/browser-use.md; one-time install via scripts/browser-use/setup.sh. Its report is input, not verdict — same claim shape as every engine.
  4. Claude drives the browser (Playwright MCP, claude-in-chrome, preview tools — whatever this session has): enumerate the user-visible flows the diff touches (from the diff, not imagination), walk each one as a user would, and at each step verify via DOM/accessibility state for text and behavior (screenshots only for layout questions). After each flow: check the browser console for errors and the network log for failed requests — a page that looks right while logging exceptions is a finding, not a pass.
  5. None available — offer the install, never dead-end and never install silently. One AskUserQuestion with the real options: (a) install Playwright locally (npm init playwright@latest — standard tooling, Claude then drives it), (b) install browser-use (scripts/browser-use/setup.sh — creates a local venv, needs an LLM API key), (c) install Expect (npm i -g expect-cli is inert, but state plainly what the separate expect init step does: writes an MCP server entry into every coding agent it finds on PATH, then downloads a skill tarball from the project's GitHub main branch into the agent's skill directory — an unpinned third-party fetch that requires an explicit yes), or (d) skip. Only if the user skips, report e2e: not verified — no browser tooling and stop. Never substitute code-reading for observation, and never report "verified" after a skipped install.

Reporting rule (the core of the skill): an AI-simulated user is a fallible verifier — same epistemics as any model output. The honest claim shape:

  • ❌ "Ran Expect — e2e tests pass ✅"
  • ✅ "Walked 3 flows against localhost:3000 (seeded account): login → dashboard (observed: redirect + username rendered), create invoice (observed: row appears, total 107.10, console clean), delete invoice (observed: 409 on double-delete — finding, quoted below). Not walked: mobile viewport, payment path (no test Stripe key). " Every flow walked is enumerated; every "works" is backed by a named observation; everything not walked is listed. Zero findings across enumerated flows is a valid outcome.

Add the Recording: and Delivered: lines exactly as record-browser-test defines them, or Recording: none - <why>. A walk with no recording says so; the absence is never left implied. Add Input: protocol (cursor positions: <n>, foreground changed: <yes|no>) or Input: not checked per the pointer rule above.

Route B: durable Playwright tests

write-tests discipline applied to the browser — plus the e2e-specific rules that keep suites from rotting:

  1. Match the repo first. Grep for playwright.config, cypress.config, an e2e/ dir. Extend the existing setup and imitate its strongest test; only scaffold fresh (npm init playwright@latest) if nothing exists, and say so. For a Chrome extension the launch, fixture, storage assertions and revision pitfalls are in references/chrome-extension.md — a normal browser context does not load extensions.
  2. Ration e2e tests by risk. Each one is 100× a unit test's cost in time and flake surface. Test through the UI only what is about the flow: the user journey, the wiring, the redirect. Business-logic variations (12 discount cases) belong in unit tests — write the one journey here and note the push-down. A handful of journeys is a suite; fifty is a liability.
  3. Selectors users would recognize: getByRole, getByLabel, getByTestId — never CSS chains or nth-child, which weld the test to today's DOM.
    • ❌ page.locator('div.card > button:nth-child(2)') — breaks on any restyle, catches nothing a user cares about.
    • ✅ page.getByRole('button', { name: 'Submit order' }) — breaks only when the user's world breaks.
  4. No sleeps. Web-first assertions (await expect(locator).toBeVisible()) auto-wait; waitForTimeout is flake by construction. If a step genuinely needs polling, poll a condition.
  5. Independent tests, cheap setup. Each test arranges its own world — seed state via API calls or fixtures, not by clicking through the UI (UI setup means test 3 fails because of the flow test 1 owns). Auth via a storageState fixture created once, not a login walk per test.
  6. Prove red-capable (non-negotiable, per write-tests): break the behavior or the assertion target, run, quote the red; revert, quote the green. An e2e test never seen red is the most expensive decoration there is.
  7. Run the suite and quote the summary line. A result you didn't observe is not run, never "passed".

Examples

Example 1: post-feature smoke → durable

User: "I just finished the invoice feature — verify it end to end."

Claude: Confirms target (localhost:3000, seeded user), no Expect installed → drives the browser: walks create/edit/void flows from the diff's touched routes, quotes observations per flow, catches a console 500 on void (finding). After the fix: "void is a money path — want the durable test?" → writes one Playwright journey extending the existing e2e/ config, getByRole selectors, proves it red against the reverted fix, quotes both runs.

Example 2: "run expect"

User: "Run expect on my branch."

Claude: Confirms the dev URL, runs expect tui --target branch -u http://localhost:3000 --no-cookies -m "test the branch changes" -y, then translates its output into the claim shape: flows walked + observations + findings + not-walked list — and flags that the checkout flow wasn't in Expect's generated plan despite being in the diff, walking it manually to close the gap.

Anti-patterns

  • ❌ Reporting an Expect or browser-walk green as "e2e tests pass" — the verifier is a model; the claim is "no issues found in the paths walked", paths listed.
  • ❌ Offering Expect's session video or a screen recording as proof of what was tested — it carries no step or check captions, so it shows activity, not which assertions ran. ✅ A scripted, recorded run, or Recording: none.
  • ❌ Trusting the generated test plan to cover the diff — diff-to-plan is lossy; check the plan against the diff's touched routes and walk what it missed.
  • ❌ Verifying against production, or letting Expect's default cookie extraction ride along silently.
  • ❌ Visual-only verification — a rendered page with console exceptions and failed XHRs is a finding.
  • ❌ Writing an e2e test for every case a unit test could cover — ration by journey, push logic down the pyramid.
  • ❌ Shipping an e2e test never seen red, or "fixing" a flaky one by adding waitForTimeout.
  • ❌ Scaffolding a fresh Playwright setup when the repo already has one (or has Cypress — extend what's there).
  • ❌ Running Expect's init script (or any third-party installer) without an explicit yes — offering the install is required, running it unasked is not consent.
  • ✅ Route by who-needs-it-again → safety gate → observations quoted per flow → durable tests proven red-capable → not-walked list always present.

Notes

  • Engines are swappable; the discipline isn't. If Expect changes licensing (FSL, hosted version coming) or a better ephemeral tool appears, only Route A's engine list changes.
  • Manual re-verification of the same flow twice is the signal to graduate it to Route B — the third time is a test.
  • Apply think-like-fable: flows chosen by risk, every "works" re-derived by observation, the not-walked list is the labeled-assumption discipline, and the report leads with findings, not the tour.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.