@matware/e2e-runner 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.claude-plugin/plugin.json +9 -0
  2. package/.mcp.json +9 -0
  3. package/README.md +475 -307
  4. package/agents/test-analyzer.md +81 -0
  5. package/agents/test-creator.md +102 -0
  6. package/agents/test-improver.md +140 -0
  7. package/bin/cli.js +194 -6
  8. package/commands/create-test.md +50 -0
  9. package/commands/run.md +49 -0
  10. package/commands/verify-issue.md +63 -0
  11. package/package.json +10 -2
  12. package/skills/e2e-testing/SKILL.md +166 -0
  13. package/skills/e2e-testing/references/action-types.md +100 -0
  14. package/skills/e2e-testing/references/test-json-format.md +159 -0
  15. package/skills/e2e-testing/references/troubleshooting.md +182 -0
  16. package/src/actions.js +273 -18
  17. package/src/ai-generate.js +87 -7
  18. package/src/config.js +28 -0
  19. package/src/dashboard.js +156 -6
  20. package/src/db.js +207 -13
  21. package/src/index.js +9 -3
  22. package/src/learner-markdown.js +177 -0
  23. package/src/learner-neo4j.js +255 -0
  24. package/src/learner-sqlite.js +354 -0
  25. package/src/learner.js +413 -0
  26. package/src/mcp-tools.js +448 -18
  27. package/src/module-resolver.js +273 -0
  28. package/src/narrate.js +225 -0
  29. package/src/neo4j-pool.js +124 -0
  30. package/src/reporter.js +35 -2
  31. package/src/runner.js +120 -46
  32. package/src/verify.js +5 -3
  33. package/templates/build-dashboard.js +28 -0
  34. package/templates/dashboard/app.js +1152 -0
  35. package/templates/dashboard/styles.css +413 -0
  36. package/templates/dashboard/template.html +201 -0
  37. package/templates/dashboard.html +964 -378
  38. package/templates/docker-compose-neo4j.yml +19 -0
  39. package/templates/e2e.config.js +3 -0
package/README.md CHANGED
@@ -1,13 +1,58 @@
1
+ <p align="right">
2
+ <strong>English</strong> · <a href="LEEME.md">Español</a>
3
+ </p>
4
+
5
+ <h1 align="center">@matware/e2e-runner</h1>
6
+
7
+ <p align="center">
8
+ <strong>The AI-native E2E test runner that writes, runs, and debugs tests for you.</strong>
9
+ </p>
10
+
1
11
  <p align="center">
2
12
  <img src="https://img.shields.io/npm/v/@matware/e2e-runner?color=blue" alt="npm version" />
3
13
  <img src="https://img.shields.io/node/v/@matware/e2e-runner" alt="node version" />
4
14
  <img src="https://img.shields.io/npm/l/@matware/e2e-runner" alt="license" />
5
15
  <img src="https://img.shields.io/badge/MCP-compatible-green" alt="MCP compatible" />
16
+ <img src="https://img.shields.io/badge/AI--native-Claude%20Code-blueviolet" alt="AI native" />
6
17
  </p>
7
18
 
8
- # @matware/e2e-runner
19
+ <p align="center">
20
+ <img src="https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/docs/screenshots/blog-dashboard-live-running.png" alt="E2E Runner Dashboard - Live Execution" width="800" />
21
+ </p>
22
+
23
+ ---
24
+
25
+ **E2E Runner** is a zero-code browser testing framework where tests are plain JSON files — no Playwright scripts, no Cypress boilerplate, no test framework to learn. Define what to click, type, and assert, and the runner executes it in parallel against a shared Chrome pool.
26
+
27
+ But what makes it truly different is its **deep AI integration**. With a built-in [MCP server](https://modelcontextprotocol.io/), Claude Code can create tests from a conversation, run them, read the results, capture screenshots, and even visually verify that pages look correct — all without leaving the chat. Paste a GitHub issue URL and get a runnable test back. That's the workflow.
28
+
29
+ ### What you get
30
+
31
+ 🧪 **Zero-code tests** — JSON files that anyone on your team can read and write. No JavaScript, no compilation, no framework lock-in.
32
+
33
+ 🤖 **AI-powered testing** — Claude Code creates, executes, and debugs tests natively through 13 MCP tools. Ask it to "test the checkout flow" and it builds the JSON, runs it, and reports back.
34
+
35
+ 🐛 **Issue-to-Test pipeline** — Paste a GitHub or GitLab issue URL. The runner fetches it, generates E2E tests, runs them, and tells you: *bug confirmed* or *not reproducible*.
36
+
37
+ 👁️ **Visual verification** — Describe what the page should look like in plain English. The AI captures a screenshot and judges pass/fail against your description. No pixel-diffing setup needed.
38
+
39
+ 🧠 **Learning system** — Tracks test stability across runs. Detects flaky tests, unstable selectors, slow APIs, and error patterns — then surfaces actionable insights.
40
+
41
+ ⚡ **Parallel execution** — Run N tests simultaneously against a shared Chrome pool (browserless/chrome). Serial mode available for tests that share state.
42
+
43
+ 📊 **Real-time dashboard** — Live execution view, run history with pass-rate charts, screenshot gallery with hash-based search, expandable network request logs.
44
+
45
+ 🔁 **Smart retries** — Test-level and action-level retries with configurable delays. Flaky tests are detected and flagged automatically.
46
+
47
+ 📦 **Reusable modules** — Extract common flows (login, navigation, setup) into parameterized modules and reference them with `$use`.
9
48
 
10
- JSON-driven E2E test runner. Define browser tests as simple JSON action arrays, run them in parallel against a Chrome pool. No JavaScript test files, no complex setup.
49
+ 🏗️ **CI-ready** JUnit XML output, exit code 1 on failure, auto-captured error screenshots. Drop-in GitHub Actions example included.
50
+
51
+ 🌐 **Multi-project** — One dashboard aggregates test results from all your projects. One Chrome pool serves them all.
52
+
53
+ 🐳 **Portable** — Chrome runs in Docker, tests are JSON files in your repo. Works on any machine with Node.js and Docker.
54
+
55
+ ### This is a test
11
56
 
12
57
  ```json
13
58
  [
@@ -25,15 +70,9 @@ JSON-driven E2E test runner. Define browser tests as simple JSON action arrays,
25
70
  ]
26
71
  ```
27
72
 
28
- ---
29
-
30
- ## Why
73
+ No imports. No `describe`/`it`. No compilation step. Just a JSON file that describes what a user does — and the runner makes it happen.
31
74
 
32
- - **No code** -- Tests are JSON files. QA, product, and devs can all write them.
33
- - **Parallel** -- Run N tests simultaneously against a shared Chrome pool.
34
- - **Portable** -- Chrome runs in Docker, tests run anywhere.
35
- - **CI-ready** -- JUnit XML output, exit code 1 on failure, error screenshots.
36
- - **AI-native** -- Built-in MCP server for Claude Code integration.
75
+ ---
37
76
 
38
77
  ## Quick Start
39
78
 
@@ -43,8 +82,6 @@ JSON-driven E2E test runner. Define browser tests as simple JSON action arrays,
43
82
  curl -fsSL https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/scripts/quickstart.sh | bash
44
83
  ```
45
84
 
46
- This checks prerequisites, installs the package, scaffolds the project, starts the Chrome pool, and runs the sample tests.
47
-
48
85
  **Step by step:**
49
86
 
50
87
  ```bash
@@ -67,19 +104,17 @@ npx e2e-runner dashboard
67
104
  **Add to Claude Code** (once, available in all projects):
68
105
 
69
106
  ```bash
107
+ # Full plugin: MCP tools + skills + commands + agents
108
+ claude plugin install npm:@matware/e2e-runner
109
+
110
+ # Or MCP-only (tools without skills/commands/agents):
70
111
  claude mcp add --transport stdio --scope user e2e-runner \
71
112
  -- npx -y -p @matware/e2e-runner e2e-runner-mcp
72
113
  ```
73
114
 
74
- The `init` command creates:
115
+ The **plugin** is the recommended approach — it installs the 13 MCP tools *plus* a skill that teaches Claude the optimal workflow, 3 slash commands (`/e2e-runner:run`, `/e2e-runner:create-test`, `/e2e-runner:verify-issue`), and 2 specialized agents for test analysis and creation.
75
116
 
76
- ```
77
- e2e/
78
- tests/
79
- 01-sample.json # Sample test suite
80
- screenshots/ # Reports and error screenshots
81
- e2e.config.js # Configuration file
82
- ```
117
+ ---
83
118
 
84
119
  ## Test Format
85
120
 
@@ -110,422 +145,565 @@ Suite files can have numeric prefixes for ordering (`01-auth.json`, `02-dashboar
110
145
  | `click` | `selector` or `text` | Click by CSS selector or visible text content |
111
146
  | `type` / `fill` | `selector`, `value` | Clear field and type text |
112
147
  | `wait` | `selector`, `text`, or `value` (ms) | Wait for element, text, or fixed delay |
113
- | `assert_text` | `text` | Assert text exists on the page |
114
- | `assert_url` | `value` | Assert current URL contains value |
115
- | `assert_visible` | `selector` | Assert element is visible |
116
- | `assert_count` | `selector`, `value` | Assert element count matches |
117
148
  | `screenshot` | `value` (filename) | Capture a screenshot |
118
149
  | `select` | `selector`, `value` | Select a dropdown option |
119
150
  | `clear` | `selector` | Clear an input field |
120
- | `press` | `value` | Press a keyboard key (e.g. `Enter`, `Tab`) |
151
+ | `press` | `value` | Press a keyboard key (`Enter`, `Tab`, etc.) |
121
152
  | `scroll` | `selector` or `value` (px) | Scroll to element or by pixel amount |
122
153
  | `hover` | `selector` | Hover over an element |
123
154
  | `evaluate` | `value` | Execute JavaScript in the browser context |
155
+ | `navigate` | `value` | Browser navigation (`back`, `forward`, `reload`) |
156
+ | `clear_cookies` | — | Clear all cookies for the current page |
157
+
158
+ ### Assertions
159
+
160
+ | Action | Fields | Description |
161
+ |--------|--------|-------------|
162
+ | `assert_text` | `text` | Assert text exists anywhere on the page (substring) |
163
+ | `assert_element_text` | `selector`, `text`, optional `value: "exact"` | Assert element's text contains (or exactly matches) the expected text |
164
+ | `assert_url` | `value` | Assert current URL path or full URL. Paths (`/dashboard`) compare against pathname only |
165
+ | `assert_visible` | `selector` | Assert element exists and is visible |
166
+ | `assert_not_visible` | `selector` | Assert element is hidden or doesn't exist |
167
+ | `assert_attribute` | `selector`, `value` | Check attribute: `"type=email"` for value, `"disabled"` for existence |
168
+ | `assert_class` | `selector`, `value` | Assert element has a CSS class |
169
+ | `assert_input_value` | `selector`, `value` | Assert input/select/textarea `.value` contains text |
170
+ | `assert_matches` | `selector`, `value` (regex) | Assert element text matches a regex pattern |
171
+ | `assert_count` | `selector`, `value` | Assert element count: exact (`"5"`), or operators (`">3"`, `">=1"`, `"<10"`) |
172
+ | `assert_no_network_errors` | — | Fail if any network requests failed (e.g. `ERR_CONNECTION_REFUSED`) |
173
+ | `get_text` | `selector` | Extract element text (non-assertion, never fails). Result: `{ value: "..." }` |
124
174
 
125
175
  ### Click by Text
126
176
 
127
- When `click` uses `text` instead of `selector`, it searches across interactive elements:
177
+ When `click` uses `text` instead of `selector`, it searches across common interactive and content elements:
128
178
 
129
179
  ```
130
- button, a, [role="button"], [role="tab"], [role="menuitem"], div[class*="cursor"], span
180
+ button, a, [role="button"], [role="tab"], [role="menuitem"], [role="option"],
181
+ [role="listitem"], div[class*="cursor"], span, li, td, th, label, p, h1-h6
131
182
  ```
132
183
 
133
184
  ```json
134
185
  { "type": "click", "text": "Sign In" }
135
186
  ```
136
187
 
137
- ## CLI
188
+ ### Framework-Aware Actions
138
189
 
139
- ```bash
140
- # Run tests
141
- npx e2e-runner run --all # All suites
142
- npx e2e-runner run --suite auth # Single suite
143
- npx e2e-runner run --tests path/to.json # Specific file
144
- npx e2e-runner run --inline '<json>' # Inline JSON
145
-
146
- # Pool management
147
- npx e2e-runner pool start # Start Chrome container
148
- npx e2e-runner pool stop # Stop Chrome container
149
- npx e2e-runner pool status # Check pool health
190
+ These actions handle common patterns in React/MUI apps that normally require verbose `evaluate` boilerplate:
150
191
 
151
- # Issue-to-test
152
- npx e2e-runner issue <url> # Fetch issue details
153
- npx e2e-runner issue <url> --generate # Generate test file via AI
154
- npx e2e-runner issue <url> --verify # Generate + run + report
192
+ | Action | Fields | Description |
193
+ |--------|--------|-------------|
194
+ | `type_react` | `selector`, `value` | Type into React controlled inputs using the native value setter. Dispatches `input` + `change` events so React state updates correctly. |
195
+ | `click_regex` | `text` (regex), optional `selector`, optional `value: "last"` | Click element whose textContent matches a regex (case-insensitive). Default: first match. Use `value: "last"` for last match. |
196
+ | `click_option` | `text` | Click a `[role="option"]` element by text — common in autocomplete/select dropdowns. |
197
+ | `focus_autocomplete` | `text` (label text) | Focus an autocomplete input by its label text. Supports MUI and generic `[role="combobox"]`. |
198
+ | `click_chip` | `text` | Click a chip/tag element by text. Searches `[class*="Chip"]`, `[class*="chip"]`, `[data-chip]`. |
155
199
 
156
- # Dashboard
157
- npx e2e-runner dashboard # Start web dashboard
200
+ ```json
201
+ // Before: 5 lines of evaluate boilerplate
202
+ { "type": "evaluate", "value": "const input = document.querySelector('#search'); const nativeSet = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set; nativeSet.call(input, 'term'); input.dispatchEvent(new Event('input', {bubbles: true})); input.dispatchEvent(new Event('change', {bubbles: true}));" }
158
203
 
159
- # Other
160
- npx e2e-runner list # List available suites
161
- npx e2e-runner init # Scaffold project
204
+ // After: 1 action
205
+ { "type": "type_react", "selector": "#search", "value": "term" }
162
206
  ```
163
207
 
164
- ### CLI Options
208
+ ---
165
209
 
166
- | Flag | Default | Description |
167
- |------|---------|-------------|
168
- | `--base-url <url>` | `http://host.docker.internal:3000` | Application base URL |
169
- | `--pool-url <ws>` | `ws://localhost:3333` | Chrome pool WebSocket URL |
170
- | `--tests-dir <dir>` | `e2e/tests` | Tests directory |
171
- | `--screenshots-dir <dir>` | `e2e/screenshots` | Screenshots/reports directory |
172
- | `--concurrency <n>` | `3` | Parallel test workers |
173
- | `--timeout <ms>` | `10000` | Default action timeout |
174
- | `--retries <n>` | `0` | Retry failed tests N times |
175
- | `--retry-delay <ms>` | `1000` | Delay between retries |
176
- | `--test-timeout <ms>` | `60000` | Per-test timeout |
177
- | `--output <format>` | `json` | Report format: `json`, `junit`, `both` |
178
- | `--env <name>` | `default` | Environment profile |
179
- | `--pool-port <port>` | `3333` | Chrome pool port |
180
- | `--max-sessions <n>` | `10` | Max concurrent Chrome sessions |
181
- | `--project-name <name>` | dir name | Project display name for dashboard |
210
+ ## Retries
182
211
 
183
- ## Configuration
212
+ ### Test-Level Retry
184
213
 
185
- Create `e2e.config.js` (or `e2e.config.json`) in your project root:
214
+ Retry an entire test on failure. Set globally via config or per-test:
186
215
 
187
- ```js
188
- export default {
189
- baseUrl: 'http://host.docker.internal:3000',
190
- concurrency: 4,
191
- retries: 2,
192
- testTimeout: 30000,
193
- outputFormat: 'both',
216
+ ```json
217
+ { "name": "flaky-test", "retries": 3, "timeout": 15000, "actions": [...] }
218
+ ```
194
219
 
195
- hooks: {
196
- beforeEach: [{ type: 'goto', value: '/' }],
197
- afterEach: [{ type: 'screenshot', value: 'after-test.png' }],
198
- },
220
+ Tests that pass after retry are flagged as **flaky** in the report and learning system.
199
221
 
200
- environments: {
201
- staging: { baseUrl: 'https://staging.example.com' },
202
- production: { baseUrl: 'https://example.com', concurrency: 5 },
203
- },
204
- };
222
+ ### Action-Level Retry
223
+
224
+ Retry a single action without rerunning the entire test. Useful for timing-sensitive clicks and waits:
225
+
226
+ ```json
227
+ { "type": "click", "selector": "#dynamic-btn", "retries": 3 }
228
+ { "type": "wait", "selector": ".lazy-loaded", "retries": 2 }
205
229
  ```
206
230
 
207
- ### Config Priority (highest wins)
231
+ Set globally: `actionRetries` in config, `--action-retries <n>` CLI, or `ACTION_RETRIES` env var. Delay between retries: `actionRetryDelay` (default 500ms).
208
232
 
209
- 1. CLI flags (`--base-url`, `--concurrency`, ...)
210
- 2. Environment variables (`BASE_URL`, `CONCURRENCY`, ...)
211
- 3. Config file (`e2e.config.js` or `e2e.config.json`)
212
- 4. Defaults
233
+ ---
213
234
 
214
- When `--env <name>` is set, the matching profile from `environments` overrides everything.
215
-
216
- ### Environment Variables
217
-
218
- | Variable | Maps to |
219
- |----------|---------|
220
- | `BASE_URL` | `baseUrl` |
221
- | `CHROME_POOL_URL` | `poolUrl` |
222
- | `TESTS_DIR` | `testsDir` |
223
- | `SCREENSHOTS_DIR` | `screenshotsDir` |
224
- | `CONCURRENCY` | `concurrency` |
225
- | `DEFAULT_TIMEOUT` | `defaultTimeout` |
226
- | `POOL_PORT` | `poolPort` |
227
- | `MAX_SESSIONS` | `maxSessions` |
228
- | `RETRIES` | `retries` |
229
- | `RETRY_DELAY` | `retryDelay` |
230
- | `TEST_TIMEOUT` | `testTimeout` |
231
- | `OUTPUT_FORMAT` | `outputFormat` |
232
- | `E2E_ENV` | `env` |
233
- | `PROJECT_NAME` | `projectName` |
234
- | `ANTHROPIC_API_KEY` | `anthropicApiKey` |
235
- | `ANTHROPIC_MODEL` | `anthropicModel` |
235
+ ## Serial Tests
236
236
 
237
- ## Hooks
237
+ Tests that share state (e.g., two tests modifying the same record) can race when running in parallel. Mark them as serial:
238
+
239
+ ```json
240
+ { "name": "create-patient", "serial": true, "actions": [...] }
241
+ { "name": "verify-patient-list", "serial": true, "actions": [...] }
242
+ ```
238
243
 
239
- Hooks run actions at lifecycle points. Define them globally in config or per-suite in the JSON file:
244
+ Serial tests run one at a time **after** all parallel tests finish preventing interference without slowing down independent tests.
245
+
246
+ ---
247
+
248
+ ## Reusable Modules
249
+
250
+ Extract common flows into parameterized modules:
240
251
 
241
252
  ```json
253
+ // e2e/modules/auth.json
242
254
  {
243
- "hooks": {
244
- "beforeAll": [{ "type": "goto", "value": "/login" }],
245
- "beforeEach": [{ "type": "goto", "value": "/" }],
246
- "afterEach": [],
247
- "afterAll": []
255
+ "$module": "auth-jwt",
256
+ "description": "Inject JWT token into localStorage",
257
+ "params": {
258
+ "token": { "required": true, "description": "JWT token" },
259
+ "storageKey": { "default": "accessToken" }
248
260
  },
249
- "tests": [
250
- { "name": "test-1", "actions": [...] }
261
+ "actions": [
262
+ { "type": "evaluate", "value": "localStorage.setItem('{{storageKey}}', '{{token}}')" },
263
+ { "type": "goto", "value": "/dashboard" }
264
+ ]
265
+ }
266
+ ```
267
+
268
+ Use in tests:
269
+
270
+ ```json
271
+ {
272
+ "name": "dashboard-loads",
273
+ "actions": [
274
+ { "$use": "auth-jwt", "params": { "token": "eyJhbG..." } },
275
+ { "type": "assert_text", "text": "Dashboard" }
251
276
  ]
252
277
  }
253
278
  ```
254
279
 
255
- Suite-level hooks override global hooks per key (non-empty array wins). The plain array format (`[{ name, actions }]`) is still supported.
280
+ Modules support parameter validation (required params fail fast), conditional blocks (`{{#param}}...{{/param}}`), nested composition, and cycle detection.
281
+
282
+ ---
283
+
284
+ ## Exclude Patterns
256
285
 
257
- ## Retries and Timeouts
286
+ Skip exploratory or draft tests from `--all` runs:
287
+
288
+ ```js
289
+ // e2e.config.js
290
+ export default {
291
+ exclude: ['explore-*', 'debug-*', 'draft-*'],
292
+ };
293
+ ```
258
294
 
259
- Override globally or per-test:
295
+ Individual suite runs (`--suite`) are not affected by exclude patterns.
296
+
297
+ ---
298
+
299
+ ## Visual Verification
300
+
301
+ Describe what the page should look like — AI judges pass/fail from screenshots:
260
302
 
261
303
  ```json
262
304
  {
263
- "name": "flaky-test",
264
- "retries": 3,
265
- "timeout": 15000,
266
- "actions": [...]
305
+ "name": "dashboard-loads",
306
+ "expect": "Patient list with at least 3 rows, no error messages, sidebar with navigation links",
307
+ "actions": [
308
+ { "type": "goto", "value": "/dashboard" },
309
+ { "type": "wait", "selector": ".patient-list" }
310
+ ]
267
311
  }
268
312
  ```
269
313
 
270
- - **Retries**: Each attempt gets its own fresh timeout. Tests that pass after retry are flagged as "flaky" in the report.
271
- - **Timeout**: Applied via `Promise.race()`. Defaults to 60s.
314
+ After test actions complete, the runner auto-captures a verification screenshot. The MCP response includes the screenshot hash Claude Code retrieves it and visually verifies against your `expect` description. No API key required.
272
315
 
273
- ## CI/CD
316
+ ---
274
317
 
275
- ### JUnit XML
318
+ ## Issue-to-Test
319
+
320
+ Turn GitHub and GitLab issues into executable E2E tests. Paste an issue URL and get runnable tests — automatically.
321
+
322
+ **How it works:**
323
+
324
+ 1. **Fetch** — Pulls issue details (title, body, labels) via `gh` or `glab` CLI
325
+ 2. **Generate** — AI creates JSON test actions based on the issue description
326
+ 3. **Run** — Optionally executes the tests immediately to verify if a bug is reproducible
276
327
 
277
328
  ```bash
278
- npx e2e-runner run --all --output junit
279
- # or: --output both (JSON + XML)
329
+ # Fetch and display
330
+ e2e-runner issue https://github.com/owner/repo/issues/42
331
+
332
+ # Generate a test file via Claude API
333
+ e2e-runner issue https://github.com/owner/repo/issues/42 --generate
334
+
335
+ # Generate + run + report
336
+ e2e-runner issue https://github.com/owner/repo/issues/42 --verify
337
+ # -> "BUG CONFIRMED" or "NOT REPRODUCIBLE"
280
338
  ```
281
339
 
282
- Output saved to `e2e/screenshots/junit.xml`.
340
+ In Claude Code, just ask:
341
+ > "Fetch issue #42 and create E2E tests for it"
283
342
 
284
- ### GitHub Actions
343
+ **Bug verification logic:** Generated tests assert the **correct** behavior. Test failure = bug confirmed. All tests pass = not reproducible.
285
344
 
286
- ```yaml
287
- jobs:
288
- e2e:
289
- runs-on: ubuntu-latest
290
- steps:
291
- - uses: actions/checkout@v4
292
- - uses: actions/setup-node@v4
293
- with:
294
- node-version: 20
295
- - run: npm ci
296
- - run: npx e2e-runner pool start
297
- - run: npx e2e-runner run --all --output junit
298
- - uses: mikepenz/action-junit-report@v4
299
- if: always()
300
- with:
301
- report_paths: e2e/screenshots/junit.xml
302
- ```
345
+ **Auth:** GitHub requires `gh` CLI, GitLab requires `glab` CLI. Self-hosted GitLab is supported.
303
346
 
304
- ### Exit Codes
347
+ ---
305
348
 
306
- | Code | Meaning |
307
- |------|---------|
308
- | `0` | All tests passed |
309
- | `1` | One or more tests failed |
349
+ ## Learning System
310
350
 
311
- ## Programmatic API
351
+ The runner learns from every test run — building knowledge about your test suite over time.
312
352
 
313
- ```js
314
- import { createRunner } from '@matware/e2e-runner';
353
+ Query insights via the `e2e_learnings` MCP tool:
315
354
 
316
- const runner = await createRunner({ baseUrl: 'http://localhost:3000' });
355
+ | Query | Returns |
356
+ |-------|---------|
357
+ | `summary` | Full health overview: pass rate, flaky tests, unstable selectors, API issues |
358
+ | `flaky` | Tests that pass only after retries |
359
+ | `selectors` | CSS selectors with high failure rates |
360
+ | `pages` | Pages with console errors, network failures, load time issues |
361
+ | `apis` | API endpoints with error rates and latency (auto-normalized: UUIDs, hashes, IDs) |
362
+ | `errors` | Most frequent error patterns, categorized |
363
+ | `trends` | Pass rate over time (auto-switches to hourly when all data is from one day) |
364
+ | `test:<name>` | Drill-down history for a specific test |
365
+ | `page:<path>` | Drill-down history for a specific page |
366
+ | `selector:<value>` | Drill-down history for a specific selector |
317
367
 
318
- // Run all suites
319
- const report = await runner.runAll();
368
+ **Storage & export:**
369
+ - SQLite (`~/.e2e-runner/dashboard.db`) — default, zero setup
370
+ - Neo4j knowledge graph — optional, for relationship-based analysis. Manage via `e2e_neo4j` MCP tool or `docker compose`
371
+ - Markdown report (`e2e/learnings.md`) — auto-generated after each run
320
372
 
321
- // Run a specific suite
322
- const report = await runner.runSuite('auth');
373
+ **Test narration:** Each test run generates a human-readable narrative of what happened step by step, visible in the CLI output and the dashboard.
323
374
 
324
- // Run a specific file
325
- const report = await runner.runFile('e2e/tests/login.json');
375
+ ---
326
376
 
327
- // Run inline test objects
328
- const report = await runner.runTests([
329
- {
330
- name: 'quick-check',
331
- actions: [
332
- { type: 'goto', value: '/' },
333
- { type: 'assert_text', text: 'Hello' },
334
- ],
335
- },
336
- ]);
377
+ ## Web Dashboard
378
+
379
+ Real-time UI for running tests, viewing results, screenshots, and network logs.
380
+
381
+ ```bash
382
+ e2e-runner dashboard # Start on default port 8484
383
+ e2e-runner dashboard --port 9090 # Custom port
337
384
  ```
338
385
 
339
- ### Lower-Level Exports
386
+ ### Live Execution
340
387
 
341
- ```js
342
- import {
343
- loadConfig,
344
- waitForPool, connectToPool, getPoolStatus, startPool, stopPool,
345
- runTest, runTestsParallel, loadTestFile, loadTestSuite, loadAllSuites, listSuites,
346
- generateReport, generateJUnitXML, saveReport, printReport,
347
- executeAction,
348
- } from '@matware/e2e-runner';
388
+ Monitor tests in real-time with step-by-step progress, durations, and active worker count.
389
+
390
+ <p align="center">
391
+ <img src="https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/docs/screenshots/blog-dashboard-live-running.png" alt="Dashboard - Live test execution" width="800" />
392
+ </p>
393
+
394
+ ### Test Suites
395
+
396
+ Browse all test suites across multiple projects. Run a single suite or all tests with one click.
397
+
398
+ <p align="center">
399
+ <img src="https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/docs/screenshots/blog-dashboard-suites.png" alt="Dashboard - Test suites grid" width="800" />
400
+ </p>
401
+
402
+ ### Run History
403
+
404
+ Track pass rate trends with the built-in chart. Click any row to expand full detail with per-test results, screenshot hashes, and errors.
405
+
406
+ <p align="center">
407
+ <img src="https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/docs/screenshots/blog-dashboard-runs.png" alt="Dashboard - Run history" width="800" />
408
+ </p>
409
+
410
+ ### Run Detail
411
+
412
+ Expanded view with PASS/FAIL badges, screenshot thumbnails with copyable hashes (`ss:77c28b5a`), formatted console errors, and network request logs.
413
+
414
+ <p align="center">
415
+ <img src="https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/docs/screenshots/blog-dashboard-run-detail.png" alt="Dashboard - Run detail" width="800" />
416
+ </p>
417
+
418
+ ### Screenshot Gallery
419
+
420
+ Browse all captured screenshots with hash search. Includes action screenshots, error screenshots, and verification captures.
421
+
422
+ <p align="center">
423
+ <img src="https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/docs/screenshots/blog-dashboard-screenshots-gallery.png" alt="Dashboard - Screenshot gallery" width="800" />
424
+ </p>
425
+
426
+ ### Pool Status
427
+
428
+ Monitor Chrome pool health: available slots, running sessions, memory pressure.
429
+
430
+ <p align="center">
431
+ <img src="https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/docs/screenshots/blog-dashboard-pool-status.png" alt="Dashboard - Pool status" width="800" />
432
+ </p>
433
+
434
+ ---
435
+
436
+ ## Screenshot Capture
437
+
438
+ Capture screenshots of any URL on demand — no test suite required:
439
+
440
+ ```bash
441
+ e2e-runner capture https://example.com
442
+ e2e-runner capture https://example.com --full-page --selector ".loaded" --delay 2000
349
443
  ```
350
444
 
351
- ## Claude Code Integration (MCP)
445
+ Via MCP, the `e2e_capture` tool supports `authToken` and `authStorageKey` for authenticated pages — it injects the token into localStorage before navigating.
352
446
 
353
- The package includes a built-in [MCP server](https://modelcontextprotocol.io/) that gives Claude Code native access to the test runner. Install once and it's available in every project.
447
+ Every screenshot gets a deterministic hash (`ss:a3f2b1c9`). Use `e2e_screenshot` to retrieve any screenshot by hash it returns the image with metadata (test name, step, type).
354
448
 
355
- **Via npm** (requires Node.js):
449
+ ---
450
+
451
+ ## Claude Code Integration
452
+
453
+ The package ships as a **Claude Code plugin** — a single install that gives Claude native access to the test runner, teaches it the optimal workflow, and adds slash commands and specialized agents.
454
+
455
+ ### Install as Plugin (recommended)
356
456
 
357
457
  ```bash
358
- claude mcp add --transport stdio --scope user e2e-runner \
359
- -- npx -y -p @matware/e2e-runner e2e-runner-mcp
458
+ claude plugin install npm:@matware/e2e-runner
360
459
  ```
361
460
 
362
- **Via Docker** (no Node.js required):
461
+ **What you get:**
462
+
463
+ | Component | Description |
464
+ |-----------|-------------|
465
+ | **13 MCP tools** | Run tests, create test files, capture screenshots, query network logs, manage dashboard, verify issues, query learnings |
466
+ | **Skill** | Teaches Claude the full e2e-runner workflow — how to combine tools, interpret results, debug failures, create tests |
467
+ | **3 Commands** | `/e2e-runner:run` — run & analyze tests<br>`/e2e-runner:create-test` — explore UI and create tests<br>`/e2e-runner:verify-issue <url>` — verify GitHub/GitLab bugs |
468
+ | **2 Agents** | **test-analyzer** — diagnoses failures, analyzes flaky tests, drills into network errors<br>**test-creator** — explores UI, discovers selectors, designs and validates tests |
469
+
470
+ ### Install MCP-only (alternative)
471
+
472
+ If you only want the 13 MCP tools without skills, commands, or agents:
363
473
 
364
474
  ```bash
365
475
  claude mcp add --transport stdio --scope user e2e-runner \
366
- -- docker run -i --rm fastslack/e2e-runner-mcp
476
+ -- npx -y -p @matware/e2e-runner e2e-runner-mcp
367
477
  ```
368
478
 
479
+ ### Slash Commands
480
+
481
+ | Command | Description |
482
+ |---------|-------------|
483
+ | `/e2e-runner:run` | Check pool, list suites, run tests, analyze results with screenshots and network drill-down |
484
+ | `/e2e-runner:create-test` | Explore the UI with screenshots, find selectors in source code, design test actions, create and validate |
485
+ | `/e2e-runner:verify-issue <url>` | Fetch a GitHub/GitLab issue, create tests that verify correct behavior, report bug confirmed or not reproducible |
486
+
369
487
  ### MCP Tools
370
488
 
371
489
  | Tool | Description |
372
490
  |------|-------------|
373
- | `e2e_run` | Run tests (all suites, by suite name, or by file path) |
491
+ | `e2e_run` | Run tests: all suites, by name, or by file. Supports `concurrency`, `baseUrl`, `retries`, `failOnNetworkError` overrides. Returns verification results if tests have `expect`. |
374
492
  | `e2e_list` | List available test suites with test names and counts |
375
- | `e2e_create_test` | Create a new test JSON file |
376
- | `e2e_pool_status` | Check Chrome pool availability and capacity |
377
- | `e2e_screenshot` | Retrieve a screenshot by its hash (e.g. `ss:a3f2b1c9`) |
378
- | `e2e_issue` | Fetch a GitHub/GitLab issue and generate E2E tests |
379
-
380
- > **Note:** Pool start/stop are only available via CLI (`e2e-runner pool start|stop`), not via MCP — restarting the pool kills all active sessions from other clients.
381
-
382
- All tools accept an optional `cwd` parameter (absolute path to the project root). Claude Code passes its current working directory so the MCP server resolves `e2e/tests/`, `e2e.config.js`, and `.e2e-pool/` relative to the correct project — even when switching between multiple projects in the same session.
383
-
384
- Once installed, Claude Code can run tests, analyze failures, and create new test files as part of its normal workflow. Just ask:
493
+ | `e2e_create_test` | Create a new test JSON file with name, tests, and optional hooks |
494
+ | `e2e_create_module` | Create a reusable module with parameterized actions |
495
+ | `e2e_pool_status` | Check Chrome pool availability, running sessions, capacity |
496
+ | `e2e_screenshot` | Retrieve a screenshot by hash (`ss:a3f2b1c9`). Returns image + metadata |
497
+ | `e2e_capture` | Capture screenshot of any URL. Supports `authToken`, `fullPage`, `selector`, `delay` |
498
+ | `e2e_dashboard_start` | Start the web dashboard |
499
+ | `e2e_dashboard_stop` | Stop the web dashboard |
500
+ | `e2e_issue` | Fetch GitHub/GitLab issue and generate tests. `mode: "prompt"` or `mode: "verify"` |
501
+ | `e2e_network_logs` | Query network request/response logs by `runDbId`. Filter by test name, method, status, URL pattern. Supports headers and bodies |
502
+ | `e2e_learnings` | Query the learning system: `summary`, `flaky`, `selectors`, `pages`, `apis`, `errors`, `trends` |
503
+ | `e2e_neo4j` | Manage Neo4j knowledge graph container: `start`, `stop`, `status` |
504
+
505
+ > **Note:** Pool start/stop are CLI-only (`e2e-runner pool start|stop`) — not exposed via MCP to prevent killing active sessions.
506
+
507
+ ### What You Can Ask Claude Code
385
508
 
386
509
  > "Run all E2E tests"
387
510
  > "Create a test that verifies the checkout flow"
388
- > "What's the status of the Chrome pool?"
389
-
390
- ### Verify Installation
511
+ > "What tests are flaky? Show me the learning summary"
512
+ > "Capture a screenshot of /dashboard with auth"
513
+ > "Fetch issue #42 and create tests for it"
514
+ > "What's the API error rate for the last 7 days?"
391
515
 
392
- ```bash
393
- claude mcp list
394
- # e2e-runner: ... - Connected
395
- ```
516
+ ---
396
517
 
397
- ## Issue-to-Test
518
+ ## Network Error Handling
398
519
 
399
- Turn GitHub and GitLab issues into executable E2E tests. Paste an issue URL and get runnable tests -- automatically.
520
+ ### Explicit Assertion
400
521
 
401
- ### How It Works
522
+ Place `assert_no_network_errors` after critical page loads:
402
523
 
403
- 1. **Fetch** -- Pulls issue details (title, body, labels) via `gh` or `glab` CLI
404
- 2. **Generate** -- AI creates JSON test actions based on the issue description
405
- 3. **Run** -- Optionally executes the tests immediately to verify if a bug is reproducible
524
+ ```json
525
+ { "type": "goto", "value": "/dashboard" },
526
+ { "type": "wait", "selector": ".loaded" },
527
+ { "type": "assert_no_network_errors" }
528
+ ```
406
529
 
407
- ### Two Modes
530
+ ### Global Flag
408
531
 
409
- **Prompt mode** (default, no API key): Returns issue data + a structured prompt. Claude Code uses its own intelligence to create tests via `e2e_create_test` and run them.
532
+ Set `failOnNetworkError: true` to automatically fail any test with network errors:
410
533
 
411
- **Verify mode** (requires `ANTHROPIC_API_KEY`): Calls Claude API directly, generates tests, runs them, and reports whether the bug is confirmed or not reproducible.
534
+ ```bash
535
+ e2e-runner run --all --fail-on-network-error
536
+ ```
412
537
 
413
- ### CLI
538
+ When disabled (default), the runner still collects and reports network errors — the MCP response includes a warning when tests pass but have network errors.
414
539
 
415
- ```bash
416
- # Fetch and display issue details
417
- e2e-runner issue https://github.com/owner/repo/issues/42
540
+ ### Full Network Logging
418
541
 
419
- # Generate a test file via Claude API
420
- e2e-runner issue https://github.com/owner/repo/issues/42 --generate
421
- # -> Creates e2e/tests/issue-42.json
542
+ All XHR/fetch requests are captured with: URL, method, status, duration, request/response headers, and response body (truncated at 50KB). Viewable in the dashboard with expandable request detail rows.
422
543
 
423
- # Generate + run + report bug status
424
- e2e-runner issue https://github.com/owner/repo/issues/42 --verify
425
- # -> "BUG CONFIRMED" or "NOT REPRODUCIBLE"
544
+ **MCP drill-down flow:**
426
545
 
427
- # Output AI prompt as JSON (for piping)
428
- e2e-runner issue https://github.com/owner/repo/issues/42 --prompt
546
+ ```
547
+ 1. e2e_run → compact networkSummary + runDbId
548
+ 2. e2e_network_logs(runDbId) → all requests (url, method, status, duration)
549
+ 3. e2e_network_logs(runDbId, errorsOnly: true) → only failed requests
550
+ 4. e2e_network_logs(runDbId, includeHeaders: true) → with headers
551
+ 5. e2e_network_logs(runDbId, includeBodies: true) → full request/response bodies
429
552
  ```
430
553
 
431
- ### MCP
554
+ The `e2e_run` response stays compact (~5KB) regardless of how many requests were captured. Use `e2e_network_logs` with the returned `runDbId` to drill into details on demand.
432
555
 
433
- In Claude Code, the `e2e_issue` tool handles everything:
556
+ ---
434
557
 
435
- > "Fetch issue https://github.com/owner/repo/issues/42 and create E2E tests for it"
558
+ ## Hooks
436
559
 
437
- Claude Code receives the issue data, generates appropriate test actions, saves them via `e2e_create_test`, and runs them with `e2e_run`.
560
+ Run actions at lifecycle points. Define globally in config or per-suite:
438
561
 
439
- ### Auth Requirements
562
+ ```json
563
+ {
564
+ "hooks": {
565
+ "beforeAll": [{ "type": "goto", "value": "/setup" }],
566
+ "beforeEach": [{ "type": "goto", "value": "/" }],
567
+ "afterEach": [{ "type": "screenshot", "value": "after.png" }],
568
+ "afterAll": []
569
+ },
570
+ "tests": [...]
571
+ }
572
+ ```
440
573
 
441
- - **GitHub**: `gh` CLI authenticated (`gh auth login`)
442
- - **GitLab**: `glab` CLI authenticated (`glab auth login`)
574
+ > **Important:** `beforeAll` runs on a separate browser page that is closed before tests start. Use `beforeEach` for state that tests need (cookies, localStorage, auth tokens).
443
575
 
444
- Provider is auto-detected from the URL. Self-hosted GitLab is supported via `glab` config.
576
+ ---
445
577
 
446
- ### Bug Verification Logic
578
+ ## CLI
447
579
 
448
- Generated tests assert the **correct** behavior. If the tests fail, the correct behavior doesn't work -- bug confirmed. If all tests pass, the bug is not reproducible.
580
+ ```bash
581
+ # Run tests
582
+ e2e-runner run --all # All suites
583
+ e2e-runner run --suite auth # Single suite
584
+ e2e-runner run --tests path/to.json # Specific file
585
+ e2e-runner run --inline '<json>' # Inline JSON
449
586
 
450
- ## Web Dashboard
587
+ # Pool management (CLI only, not MCP)
588
+ e2e-runner pool start # Start Chrome container
589
+ e2e-runner pool stop # Stop Chrome container
590
+ e2e-runner pool status # Check pool health
451
591
 
452
- Real-time UI for running tests, viewing results, screenshots, and run history.
592
+ # Issue-to-test
593
+ e2e-runner issue <url> # Fetch issue
594
+ e2e-runner issue <url> --generate # Generate test via AI
595
+ e2e-runner issue <url> --verify # Generate + run + report
453
596
 
454
- ```bash
455
- e2e-runner dashboard # Start on default port 8484
456
- e2e-runner dashboard --port 9090 # Custom port
597
+ # Dashboard
598
+ e2e-runner dashboard # Start web dashboard
599
+
600
+ # Other
601
+ e2e-runner list # List available suites
602
+ e2e-runner capture <url> # On-demand screenshot
603
+ e2e-runner init # Scaffold project
457
604
  ```
458
605
 
459
- ### Live Execution
606
+ ### CLI Options
460
607
 
461
- Monitor tests in real-time as they run. Each test shows its steps with individual durations, pass/fail status, and active connection count.
608
+ | Flag | Default | Description |
609
+ |------|---------|-------------|
610
+ | `--base-url <url>` | `http://host.docker.internal:3000` | Application base URL |
611
+ | `--pool-url <ws>` | `ws://localhost:3333` | Chrome pool WebSocket URL |
612
+ | `--concurrency <n>` | `3` | Parallel test workers |
613
+ | `--retries <n>` | `0` | Retry failed tests N times |
614
+ | `--action-retries <n>` | `0` | Retry failed actions N times |
615
+ | `--test-timeout <ms>` | `60000` | Per-test timeout |
616
+ | `--timeout <ms>` | `10000` | Default action timeout |
617
+ | `--output <format>` | `json` | Report: `json`, `junit`, `both` |
618
+ | `--env <name>` | `default` | Environment profile |
619
+ | `--fail-on-network-error` | `false` | Fail tests with network errors |
620
+ | `--project-name <name>` | dir name | Project display name |
462
621
 
463
- <p align="center">
464
- <img src="https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/docs/screenshots/blog-dashboard-live-running.png" alt="Dashboard - Live test execution" width="900" />
465
- </p>
622
+ ---
466
623
 
467
- ### Test Suites
624
+ ## Configuration
468
625
 
469
- Browse all test suites across multiple projects. Run a single suite or all tests with one click.
626
+ Create `e2e.config.js` in your project root:
470
627
 
471
- <p align="center">
472
- <img src="https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/docs/screenshots/blog-dashboard-suites.png" alt="Dashboard - Test suites grid" width="900" />
473
- </p>
628
+ ```js
629
+ export default {
630
+ baseUrl: 'http://host.docker.internal:3000',
631
+ concurrency: 4,
632
+ retries: 2,
633
+ actionRetries: 1,
634
+ testTimeout: 30000,
635
+ outputFormat: 'both',
636
+ failOnNetworkError: true,
637
+ exclude: ['explore-*', 'debug-*'],
474
638
 
475
- ### Run History
639
+ hooks: {
640
+ beforeEach: [{ type: 'goto', value: '/' }],
641
+ },
476
642
 
477
- Track pass rate trends over time with the bar chart. Click any row to expand the full run detail with per-test results, screenshots, and console errors.
643
+ environments: {
644
+ staging: { baseUrl: 'https://staging.example.com' },
645
+ production: { baseUrl: 'https://example.com', concurrency: 5 },
646
+ },
647
+ };
648
+ ```
478
649
 
479
- <p align="center">
480
- <img src="https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/docs/screenshots/blog-dashboard-runs.png" alt="Dashboard - Run history with trend chart" width="900" />
481
- </p>
650
+ ### Config Priority (highest wins)
482
651
 
483
- ### Run Detail
652
+ 1. CLI flags
653
+ 2. Environment variables
654
+ 3. Config file (`e2e.config.js` or `e2e.config.json`)
655
+ 4. Defaults
484
656
 
485
- Expanded view shows each test with PASS/FAIL badge, screenshot thumbnails with copyable hashes (`ss:77c28b5a`), and formatted console errors.
657
+ When `--env <name>` is set, the matching profile overrides everything.
486
658
 
487
- <p align="center">
488
- <img src="https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/docs/screenshots/blog-dashboard-run-detail.png" alt="Dashboard - Run detail with screenshot hashes" width="900" />
489
- </p>
659
+ ---
490
660
 
491
- ### Screenshot Gallery
661
+ ## CI/CD
492
662
 
493
- Browse all captured screenshots per project. Includes both manual captures and error screenshots.
663
+ ### JUnit XML
494
664
 
495
- <p align="center">
496
- <img src="https://raw.githubusercontent.com/fastslack/mtw-e2e-runner/main/docs/screenshots/blog-dashboard-screenshots-gallery.png" alt="Dashboard - Screenshot gallery" width="900" />
497
- </p>
665
+ ```bash
666
+ e2e-runner run --all --output junit
667
+ ```
498
668
 
499
- ## Architecture
669
+ ### GitHub Actions
500
670
 
501
- ```
502
- bin/cli.js CLI entry point (manual argv parsing)
503
- bin/mcp-server.js MCP server entry point (stdio transport)
504
- src/config.js Config cascade: defaults -> file -> env -> CLI -> profile
505
- src/pool.js Chrome pool: Docker Compose lifecycle + WebSocket
506
- src/runner.js Parallel test executor with retries and timeouts
507
- src/actions.js Action engine: maps JSON actions to Puppeteer calls
508
- src/reporter.js JSON reports, JUnit XML, console output
509
- src/mcp-server.js MCP server: exposes tools for Claude Code
510
- src/mcp-tools.js Shared MCP tool definitions and handlers
511
- src/dashboard.js Web dashboard: HTTP server, REST API, WebSocket
512
- src/db.js SQLite multi-project database
513
- src/issues.js GitHub/GitLab issue fetching (gh/glab CLI)
514
- src/ai-generate.js AI test generation (prompt builder + Claude API)
515
- src/verify.js Bug verification orchestrator
516
- src/logger.js ANSI colored logger
517
- src/index.js Programmatic API (createRunner)
518
- templates/ Scaffolding templates for init command
671
+ ```yaml
672
+ jobs:
673
+ e2e:
674
+ runs-on: ubuntu-latest
675
+ steps:
676
+ - uses: actions/checkout@v4
677
+ - uses: actions/setup-node@v4
678
+ with:
679
+ node-version: 20
680
+ - run: npm ci
681
+ - run: npx e2e-runner pool start
682
+ - run: npx e2e-runner run --all --output junit
683
+ - uses: mikepenz/action-junit-report@v4
684
+ if: always()
685
+ with:
686
+ report_paths: e2e/screenshots/junit.xml
519
687
  ```
520
688
 
521
- ### How It Works
689
+ ---
522
690
 
523
- 1. **Pool**: A Docker container running [browserless/chrome](https://github.com/browserless/browserless) provides shared Chrome instances via WebSocket.
524
- 2. **Runner**: Spawns N parallel workers. Each worker connects to the pool, opens a new page, and executes actions sequentially.
525
- 3. **Actions**: Each JSON action maps to a Puppeteer call (`page.goto`, `page.click`, `page.type`, etc.).
526
- 4. **Reports**: Results are collected, aggregated into a report, and saved as JSON and/or JUnit XML.
691
+ ## Programmatic API
527
692
 
528
- The `baseUrl` defaults to `http://host.docker.internal:3000` because Chrome runs inside Docker and needs to reach the host machine.
693
+ ```js
694
+ import { createRunner } from '@matware/e2e-runner';
695
+
696
+ const runner = await createRunner({ baseUrl: 'http://localhost:3000' });
697
+
698
+ const report = await runner.runAll();
699
+ const report = await runner.runSuite('auth');
700
+ const report = await runner.runFile('e2e/tests/login.json');
701
+ const report = await runner.runTests([
702
+ { name: 'quick-check', actions: [{ type: 'goto', value: '/' }] },
703
+ ]);
704
+ ```
705
+
706
+ ---
529
707
 
530
708
  ## Requirements
531
709
 
@@ -536,14 +714,4 @@ The `baseUrl` defaults to `http://host.docker.internal:3000` because Chrome runs
536
714
 
537
715
  Copyright 2025 Matias Aguirre (fastslack)
538
716
 
539
- Licensed under the Apache License, Version 2.0 (the "License");
540
- you may not use this file except in compliance with the License.
541
- You may obtain a copy of the License at
542
-
543
- http://www.apache.org/licenses/LICENSE-2.0
544
-
545
- Unless required by applicable law or agreed to in writing, software
546
- distributed under the License is distributed on an "AS IS" BASIS,
547
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
548
- See the License for the specific language governing permissions and
549
- limitations under the License.
717
+ Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for details.