Optional e2e stage of dynamic-workflow: validate a UI feature end-to-end. Runs existing automation, else grows a driver script step by step — agentic driving only for steps a script can't do. Consumes the e2e test-case file spec-design produced.
Installs into .claude/skills of the current project.
Are you the author of E2e?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/voxlo-dev-e2e)
---
name: e2e
description: "Optional e2e stage of dynamic-workflow: validate a UI feature end-to-end. Runs existing automation, else grows a driver script step by step — agentic driving only for steps a script can't do. Consumes the e2e test-case file spec-design produced."
---
# E2E
Validate a UI feature end-to-end as cheaply as possible: **the script is the tester, the agent is the exception.** Input is the test case `spec-design` wrote (`artefacts/{sprint}/e2e_{feature}.md`) — missing → ask the user (write one now / skip e2e / verify manually).
**Never end a turn on a run you didn't watch.** Foreground every build, test and driver invocation and wait it out; where a tool forces the background, poll to exit and read the output before reporting — a pending run handed back is a verdict nobody saw.
A red step is a **product bug** → back to implementation (`dynamic-workflow` step 2); red from a selector, a wait or a fixture is a **script bug** → fix the script, never the product. Either way the fix is **scoped to that step's cause**, then re-run the flow. **Three failed attempts on one step → stop and ask the user** — an attempt is one new hypothesis carried into a rerun, and there is no fourth: report the step, what the three changed, and what you need.
1. **Automation already runnable?** — run it first, before any delegation: one command, its invocation in `docs/dev.md`. Not just this feature's: the **flow index** (step 7) says which persistent flows guard the changed area — run those. The full suite in one pass is `close-sprint`'s. **A persistent test tree with no index, or no single command for the whole suite, is this step's first job** — build what is missing (step 7 / step 2) before running; nobody else checks. Green → step 5, then the report, and the stage is done. Red → triage per the rule above, except red **before this run touched anything**: that is a pre-existing defect, not this run's problem — ticket it and carry on with the case at hand.
2. **Driver** — **`docs/dev.md` owns this choice**: take the one it names rather than picking by what happens to be installed. Nothing recorded → the framework already in the project; none installable → every step is an agent step. Five rules hold whatever the driver: a **plain-text reporter on stdout is your only input** (never open an HTML report), with the build tool silenced to it — the run's own step report is the whole input, never the build log · **read the running app for a selector, never its source** — every UI stack has a tree dump (accessibility tree, DOM, layout dump); reconstructing a screen from its components plus its string resources costs far more and gets the computed result wrong, and anything ambiguous in that tree wants a test id in the product code, not a cleverer match · **a red step prints the screen it died on** — a tagged block (`[step-N-failure-screen]`) carrying that tree's text, so the cause is one grep away instead of a hand-driven device · a **screenshot only where text can't decide**, beside step 5's one UI pass · **every artifact into `.temp/e2e/`**. The first run configures the driver once and **writes both invocations into `docs/dev.md`** — this flow, and **one command for the whole suite** (write the runner where the framework gives none; `close-sprint`'s full pass exists only through it). Obligatory, and not memory's job: the next run is usually a subagent, which reads the repo and may never see project memory. **The first case's helpers are the project's harness**: a driver is the case's own steps plus the vocabulary for driving that project's screens (open this, tap that, read that value back), and the second case inherits that vocabulary instead of re-deriving it — extract it into one shared base, in whatever form the framework wants (base class, fixture, page object). Re-deriving it is this stage's single largest cost, and it is paid on every run.
3. **Classify each test-case step** `auto` (default) or `agent`. `agent` only for what no assertion can reach: another app, a system dialog, notification, camera, store flow, physical device · a qualitative judgement (does it *look* right, does it feel janky).
4. **Grow the script, one step at a time** — **pick the script to grow first**: the flow index names the flow this case overlaps and the case extends *that* one; a new script is the exception, with a stated reason. Free here, whereas folding after green means rebuilding working code and every run rightly refuses. Then append a step, rerun it whole from the top, read stdout. Never deliberate over whether scripting is worth it: red → fix → rerun is the normal path, free by script and full price by agent, so it pays for itself inside this run.
5. **Look at the UI once** — only where this run designed a UI (`ui-design` left a mockup): the driver **screenshots every screen the feature touched** into `.temp/e2e/`, and you open them once the flow is green. Judge against the mockup and `docs/design/Styleguide.html` — layout, spacing, hierarchy, element states, theme; a deviation is a **product bug** → the fix path above, named in the report. One pass per run, a second is the user's call.
6. **Agent steps** — drive through the project's MCP server if one is present, otherwise write the user the exact steps and take their result.
7. **Persist or discard** — the script always gets written; only its home is a decision: **persistent** (the flow stays in the product) → the project's test tree, committed, wired into the suite · **temporary** → `.temp/e2e/`, dies with the sprint. Then update the **flow index** `test/e2e/FLOWS.md` (or the test tree's equivalent path): one line per flow — flow · script · what it asserts · the product area it guards; it covers **every** persistent flow, not only this run's, and is pointed at from `docs/dev.md` beside the invocations.
8. **Report & board** — write `artefacts/{sprint}/e2e-report_{feature}.md` from `templates/e2e-report.md`. Green and verified → flip the ticket to `done` on the sprint board; one the user still has to eyeball stays at `to test`.