Skip to content
Back to skills

Bearing E2e

ASecurity

Use when verifying app behaviour in a real browser, or when the user asks for a screenshot of a page/view. Covers writing a verifier in .e2e/, testing a destructive write without performing it, and capturing shots. Examples: \"check the payer editor works\", \"screenshot the dashboard\", \"does this button send the right payload\", \"verify the fix end to end\".

  • 6 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 3, 2026
ai-agentsrustgonodetestingapidocumentation

Works with

  • api

Security analysis

A100/100

Scanned September 20, 2026

npx -y skills add ReidenXerx/bearing --skill bearing-e2e --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Bearing E2e?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Bearing E2e
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/reidenxerx-bearing-e2e/badge)](https://www.skillsdirectory.com/skills/reidenxerx-bearing-e2e)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: bearing-e2e
description: "Use when verifying app behaviour in a real browser, or when the user asks for a screenshot of a page/view. Covers writing a verifier in .e2e/, testing a destructive write without performing it, and capturing shots. Examples: \"check the payer editor works\", \"screenshot the dashboard\", \"does this button send the right payload\", \"verify the fix end to end\"."
---

# The `.e2e` harness

`.e2e/` is a browser harness the project FINISHES. bearing ships the substrate (`core/`), the
contracts, and the scars; the app-specific parts are yours to build and to grow.

**Read `.e2e/README.md` before writing a verifier.** Its scars list is the point of the whole
module — every entry is a green run over a real failure.

## When to reach for it

| Situation | Do |
| --- | --- |
| "does this actually work in the browser?" | write a verifier in `.e2e/verify/` |
| "does this button send the right payload?" | `blockWrites` — assert the payload, never perform the write |
| user wants to SEE a page | `shots.take(page, '<view-key>')`, then read the png |
| a fix needs proving, not describing | a verifier that FAILS before the fix and passes after (NS-9) |
| the app is not running / no session | `skip(name, why)` — never a `check` that is a skip in disguise |

Not for unit-testable logic. A browser is the slowest way to test a pure function.

## Writing one

Copy `verify/smoke.js`. The shape:

```js
withBrowser(async (browser) => {
  const report = createReport('<what this verifies>');
  // ... check() what ran, skip(name, why) what could not
  report.finish();          // exit code IS the product
});
```

Four rules that are not negotiable, each earned:

1. **A skip is not a pass.** A run where nothing passed exits 1 even with zero failures.
2. **Poll, never sleep.** `until` / `untilAtLeast` / `untilStable`. A `waitForTimeout` is a guess
   about latency that fails as a bug report.
3. **Assert on the body, not the status** — `acceptedWrite`, because a 2xx can carry an error
   envelope and a URL pattern usually matches both the create and the list.
4. **Never perform a destructive write to see if the button works.** Write every verifier as if it
   were pointed at production.

## Screenshots

`shots.take(page, key, {note})`. The key is what the shot IS (`payers/editor`), not a filename —
the next capture of that view REPLACES it. Freshest wins, deliberately: these are documentation,
not regression baselines. Do not add diffing, do not add approval, do not write `-v2`.

Always pass `note`. A png whose meaning lives only in your head is not a catalogue entry.

## Evidence you do not have to remember to collect

Wire it once, in the verifier, next to the context:

```js
const { page } = await recording.open(browser, shots);
```

From then on: **every failed `check` photographs the page it failed on**, an uncaught throw
photographs itself before the process dies. `SHOTS=all` adds video of the whole run; `SHOTS=off`
silences everything, including deliberate shots — use it for a check that MEASURES timing, where the
shutter itself would move the number.

`shots` is a required argument, deliberately: it is where your `mask` lives, and an automatic frame
of the screen a run died on is the capture most likely to end up in a ticket.

This exists because a verifier otherwise only captures moments someone predicted, and nobody
predicts where a failure lands. **Do not add automatic frames inside interaction helpers** — that
was tried, and it took a 28-assertion verifier to 5 of 6, because callers race those helpers
against the network and a frame on either side eats the event.

## Fixtures a run creates

`core/seeds.js` ledgers what the page creates, by watching responses rather than your own API
helper — a verifier that builds fixtures by driving the UI never calls that helper.

```js
seeds.watchPage(page);            // defaults: 201 only, your own origin, nothing intercepted
await seeds.settle();             // before teardown, so a late create is still recorded
```

A clean run releases its own entries, so **what survives on disk is the leak**.
`node .e2e/tools/sweep-seeds.js` lists it; `--delete` removes it. The defaults are deliberately
narrow — override `isCreate` the moment your API creates with a `200`, nests the id, or deletes via
a different shape. Under-tracking leaves visible litter; over-tracking deletes something real.

## Auditing the verifiers themselves

`node .e2e/tools/audit-checks.js` reads `verify/` for shapes that have reported something untrue: a
`check(name, true)` that cannot fail, Playwright selector syntax handed into `page.evaluate` (where
it matches nothing, silently), a report that never calls `finish()`, fixtures created with neither a
delete nor a ledger. Run it before trusting a green suite.

It exits 1 only on LIE findings. Suppress a deliberate one in place:

```js
// audit-checks: ignore vacuous-assertion
report.check('a documented placeholder', true, 'see above');
```

`tools/audit-fixtures/` is its negative control — `AUDIT_DIR=.e2e/tools/audit-fixtures` runs the
rules against files written to trip each one, plus files that only look like they should.

## Growing the harness — bounded

When you hit something the harness handled badly, **append it to `README.md`'s scars section and
keep going.** Do not edit `core/` mid-run: results from a harness that no longer exists are not
results. Fix it at the next milestone, and say in your report that you did.

Add a helper only on the THIRD time you write the same thing. Two is a coincidence.

## Anti-patterns

- A verifier that cannot fail. Run it against the broken state first, or you have tested nothing.
- Reporting "verified" from a run whose checks all skipped — read the tally, not the exit line.
- Growing `core/` with app-specific selectors. That is what `interact/` is for.
- Reaching for the browser when reading the code would answer it.

## Photograph what a PASS rests on, not only what a failure looks like

Capturing only failures has the asymmetry backwards. A FAIL already tells you to go and look; a
**wrong PASS tells you nothing and is believed**. Every locator is a claim about the DOM, and one
that stops matching does not raise its hand — it reports ABSENCE, which reads as a clean pass.

So on the check whose verdict rests on something visible, ask for the frame:

```js
report.check('the drawer shows the masked SSN', masked, seen, { evidence: true });
```

`SHOTS=evidence` turns it on for every check in a run you are investigating; `SHOTS=off` still
means off, for a check that MEASURES timing and would be distorted by its own shutter. Default
stays failures-only — a frame per passing assertion is thousands of files, and noise that large is
indistinguishable from no evidence at all.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.