git:20261108.c4c38d2 to git:20261108.e5c0491

5 added, 4 removed. Audit A to A.

---
name: write-e2e-tests
description: >-
Use when the user wants browser UI e2e as a Playwright Test spec —
converting a completed cuawright-web run, or unblocking a missing
Playwright toolchain or cuawright-web run first. Not for API-level end-to-end
tests.
license: MIT
metadata:
capabilities: shell, network, installs-tools, browser, runs-repo-commands
---
# Write E2E Tests
Turns a browser UI flow into a checked-in Playwright Test spec.
[CUAWright](https://github.com/microsoft/CUAWright) is the exploration engine:
it produces `plan.md` and `final_script.py`. This skill unblocks a missing
toolchain or run after confirmation, then converts.
## Scope
The output is always a Playwright Test spec — no per-project detection of
another framework, no cross-framework translation. An existing Cypress or
Selenium suite stays; confirm before adding Playwright beside it.
## Workflow
1. **Inventory.** In the target project, mark each of these present or
absent: a JS package manifest and its package manager; `@playwright/test`
and `playwright.config`; the cuawright-web skill; a qualifying run; another
e2e stack (Cypress, Selenium); existing CI files; cuawright-web artifact
paths git still tracks. CUAWright is present when the session's
skill list names `cuawright-web` (or legacy `webwright`), bare or
plugin-prefixed. Leave this step when every item is marked.
No package manifest — stop and report.
2. **Toolchain.** If Playwright, browsers, or cuawright-web are missing, confirm
once for those items and follow
[references/setup.md](references/setup.md). Another e2e stack without
Playwright — confirm adding Playwright beside it.
3. **Find a qualifying run.** Search `outputs/`, `final_runs/`, and any
path the user named for `plan.md` plus `final_script.py` whose
Critical Points are all checked. Found — show the path and reuse it
unless the user asks to re-run. Otherwise go to *explore*.
4. **Explore.** Confirm on its own before driving the real site. If the
- user has not named the flow, ask. Invoke the `cuawright-web` skill and
- run it to Done. Leave this step when cuawright-web reports Done and a
- qualifying run from step 3 is on disk. Reading source is not
- Explore. Convert is the next step. Exploration stays in cuawright-web.
+ user has not named the flow, ask. Invoke the `cuawright-web` skill with the
+ target browser (default Chromium, e.g. `playwright.chromium`) and run it
+ to Done. Leave this step when cuawright-web reports Done and a qualifying run
+ from step 3 is on disk. Reading source is not Explore. Convert is the next
+ step. Exploration stays in cuawright-web.
5. **Repo — gitignore.** Propose `.gitignore` rules when unignored
cuawright-web artifacts exist (`outputs/`, `final_runs/`, screenshots/logs)
or this run just scaffolded Playwright (`test-results/`,
`playwright-report/`). Write only after confirmation. Add rules only;
do not `git rm --cached` already-tracked files.
6. **Convert.** Start only when step 3's `plan.md` and `final_script.py`
exist; missing — return to Explore. How to handle a scan hit is in
[references/security.md](references/security.md).
- **Scan input.** Run `scripts/scan-secrets.sh` on `final_script.py`.
Non-zero exit: follow that doc. A visual read of the script is not
a scan. Draft only after the scan exits 0, or after every hit has a
confirmed `process.env` mapping.
- **Map and draft.** Map each Critical Point in `plan.md` one-to-one to an
`expect()` assertion; that mapping is the whole of the conversion.
Use `final_script.py` for selectors and action order only. Write
credential fields as `process.env` names; leave selectors and
non-credential fixtures as literals. Never emit static delays
(`page.waitForTimeout()` or `time.sleep` conversions) — use event-driven
waits (`expect(locator).toBeVisible()`, `waitForLoadState('domcontentloaded')`,
or `waitForResponse()`). Check optional dialogues (tours, cookie banners)
with immediate `await locator.isVisible()` rather than blocking `waitFor`.
Reuse authenticated sessions via `storageState` or API requests (`request.post`),
avoiding repeated UI login form submissions in `beforeEach` unless testing auth itself.
For tests mutating shared database or server state, isolate with `{ lock: '-exclusive-' }`
rather than disabling `fullyParallel` across the entire suite.
- **Scan output.** Run `scripts/scan-secrets.sh` on the drafted spec
before writing it. Non-zero exit: follow that doc. Write only a spec
the script accepts.
Place the spec in the project's existing e2e test directory (its
Playwright config's `testDir`, or the project's established
convention), named after the flow being converted.
7. **Validate.** Run all three gates, in order:
- **Run** — execute the generated spec once; it passes.
- **Stable** — re-run it 3 consecutive times; all 3 pass.
- **Discoverable** — the project's test-run command finds the new spec
file. A remote pipeline is not required.
On failure, attempt an automatic fix and re-validate, up to 2 attempts.
Still failing after that — stop and report. Hand back only a spec that
has passed all three gates.
8. **Repo — CI.** After Validate, follow
[references/ci.md](references/ci.md). Write only after confirmation.