Writes and debugs end-to-end browser tests — Playwright, Cypress, Selenium — covering selector strategy, waiting, test data, and the flakiness that makes suites get ignored. Use this whenever the user mentions E2E tests, browser tests, UI tests, Playwright, Cypress, Selenium, or a flaky or slow browser suite, and also when a bug is only reproducible through the UI. For testing logic below the UI, use unit-testing.
Scanned 9/3/2026
Install to Claude Code
npx -y skills add OKHP3/skillz --skill browser-testing --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Browser Testing?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/okhp3-browser-testing)More formats (shields.io, HTML) on the badges page.
---
name: browser-testing
description: Writes and debugs end-to-end browser tests — Playwright, Cypress, Selenium — covering selector strategy, waiting, test data, and the flakiness that makes suites get ignored. Use this whenever the user mentions E2E tests, browser tests, UI tests, Playwright, Cypress, Selenium, or a flaky or slow browser suite, and also when a bug is only reproducible through the UI. For testing logic below the UI, use unit-testing.
license: MIT
---
# Browser testing
Browser tests are the most expensive tests you own — slowest to run, most likely to break for
reasons unrelated to your code, hardest to debug. That cost buys one thing nothing else does:
proof that the pieces work together in a real browser.
Spend that budget on a small number of journeys that must never break. A large E2E suite is not
thorough; it is slow, flaky, and eventually ignored, and an ignored suite provides no safety
while still consuming CI time.
**Rule of thumb:** if a case can be covered below the UI, cover it there. E2E is for the wiring.
## 1. Choose the journeys
Pick the paths where failure is unacceptable, typically five to fifteen for a whole product:
- Sign up, sign in, sign out
- The core action the product exists for
- Anything involving money
- The path most users take on first visit
For each, test the **happy path plus the one failure that matters** (declined card, taken
username). Every remaining permutation belongs in a cheaper test.
**Done when:** the journey list is written and short enough to defend.
## 2. Select elements the way a user identifies them
Selector choice determines whether the suite survives a redesign. In order of preference:
1. **Role and accessible name** — `getByRole("button", { name: "Save" })`. Closest to how a
person finds the control, and it fails when accessibility breaks, which is a real bug.
2. **Visible text** — `getByText`, for non-interactive content.
3. **Dedicated test attributes** — `data-testid`. Explicit contract, immune to restyling. Use
when the first two are ambiguous.
4. **CSS or XPath structure**, a last resort. `div > div:nth-child(3) > span` encodes the DOM
shape, and it breaks on a layout change that broke nothing for users.
**Done when:** no selector in the suite depends on the DOM's structure.
## 3. Never wait for time
Fixed sleeps are the single largest source of flakiness. `sleep(2000)` is simultaneously too
long on a fast machine and too short on a loaded CI runner — it wastes time *and* fails
randomly, the worst of both.
Wait for the **state you actually need**: an element to be visible, a request to resolve, text
to change, a URL to update. Modern frameworks auto-wait on assertions — lean on that rather
than adding explicit waits.
The exception worth knowing: waiting for something to *not* appear genuinely requires a
timeout, since absence has no event. Keep it short and rare.
**Done when:** the suite contains no unconditional sleeps.
## 4. Make each test own its data
Tests that share fixtures fail in ways that depend on execution order, and order-dependent
failures cost hours to diagnose.
- Create what the test needs, in the test — via API or direct DB setup, not by clicking through
the UI. Setting up state through the UI makes every test depend on every other feature.
- Use unique values — timestamped or random emails, names, IDs, so parallel runs cannot collide.
- Clean up after, but **never** rely on cleanup for correctness. Assume the previous run crashed
halfway.
**Done when:** any single test passes alone, and the full suite passes in parallel.
## 5. Make failures diagnosable
A browser test that fails in CI with "element not found" and nothing else will be marked flaky
and skipped. Configure, before you need them:
- **Screenshot on failure**, always
- **Video or trace** for the failing test — a Playwright trace is worth more than any log line
- **Console and network logs** captured as artifacts
- **A meaningful test name** that identifies the journey and the step
**Done when:** you could diagnose a CI-only failure without reproducing it locally.
## 6. Handle flakiness as a defect
When a test fails intermittently, find the cause before touching retries. Almost always one of:
- **A race:** asserting before the app finished updating. Fix the wait, not the timing.
- **Animation:** an element present but still moving. Disable animations in the test
environment; this removes a whole class of flake at once.
- **Shared state:** see step 4.
- **Genuine non-determinism:** real time, random ordering, timezone. Control it: freeze the
clock, seed the randomness, pin the timezone.
- **A real bug:** the one that intermittently fails is sometimes telling the truth about a race
in the application. Rule this in or out before dismissing it.
Retries hide all five. Use them only as a temporary measure with the flake tracked as an issue —
an automatic retry on a real race means shipping the race.
**Done when:** the test passes 20 consecutive runs, or the flake is filed with a cause.
## Keeping the suite affordable
Run it in parallel, and shard in CI. Keep a **smoke subset**, two or three journeys — that runs
on every commit, with the full suite on merge or nightly. Fast feedback on the critical path
beats complete feedback nobody waits for.
When a journey stops being critical, delete its test. A suite that only ever grows becomes the
thing people route around.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!