@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.
- package/.claude-plugin/plugin.json +9 -0
- package/.mcp.json +9 -0
- package/README.md +475 -307
- package/agents/test-analyzer.md +81 -0
- package/agents/test-creator.md +102 -0
- package/agents/test-improver.md +140 -0
- package/bin/cli.js +194 -6
- package/commands/create-test.md +50 -0
- package/commands/run.md +49 -0
- package/commands/verify-issue.md +63 -0
- package/package.json +10 -2
- package/skills/e2e-testing/SKILL.md +166 -0
- package/skills/e2e-testing/references/action-types.md +100 -0
- package/skills/e2e-testing/references/test-json-format.md +159 -0
- package/skills/e2e-testing/references/troubleshooting.md +182 -0
- package/src/actions.js +273 -18
- package/src/ai-generate.js +87 -7
- package/src/config.js +28 -0
- package/src/dashboard.js +156 -6
- package/src/db.js +207 -13
- package/src/index.js +9 -3
- package/src/learner-markdown.js +177 -0
- package/src/learner-neo4j.js +255 -0
- package/src/learner-sqlite.js +354 -0
- package/src/learner.js +413 -0
- package/src/mcp-tools.js +448 -18
- package/src/module-resolver.js +273 -0
- package/src/narrate.js +225 -0
- package/src/neo4j-pool.js +124 -0
- package/src/reporter.js +35 -2
- package/src/runner.js +120 -46
- package/src/verify.js +5 -3
- package/templates/build-dashboard.js +28 -0
- package/templates/dashboard/app.js +1152 -0
- package/templates/dashboard/styles.css +413 -0
- package/templates/dashboard/template.html +201 -0
- package/templates/dashboard.html +964 -378
- package/templates/docker-compose-neo4j.yml +19 -0
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 `
|
|
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 (
|
|
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"],
|
|
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
|
-
|
|
188
|
+
### Framework-Aware Actions
|
|
138
189
|
|
|
139
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
157
|
-
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
npx e2e-runner init # Scaffold project
|
|
204
|
+
// After: 1 action
|
|
205
|
+
{ "type": "type_react", "selector": "#search", "value": "term" }
|
|
162
206
|
```
|
|
163
207
|
|
|
164
|
-
|
|
208
|
+
---
|
|
165
209
|
|
|
166
|
-
|
|
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
|
-
|
|
212
|
+
### Test-Level Retry
|
|
184
213
|
|
|
185
|
-
|
|
214
|
+
Retry an entire test on failure. Set globally via config or per-test:
|
|
186
215
|
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
231
|
+
Set globally: `actionRetries` in config, `--action-retries <n>` CLI, or `ACTION_RETRIES` env var. Delay between retries: `actionRetryDelay` (default 500ms).
|
|
208
232
|
|
|
209
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
"
|
|
247
|
-
"
|
|
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
|
-
"
|
|
250
|
-
{ "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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": "
|
|
264
|
-
"
|
|
265
|
-
"
|
|
266
|
-
|
|
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
|
-
|
|
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
|
-
|
|
316
|
+
---
|
|
274
317
|
|
|
275
|
-
|
|
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
|
-
|
|
279
|
-
|
|
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
|
-
|
|
340
|
+
In Claude Code, just ask:
|
|
341
|
+
> "Fetch issue #42 and create E2E tests for it"
|
|
283
342
|
|
|
284
|
-
|
|
343
|
+
**Bug verification logic:** Generated tests assert the **correct** behavior. Test failure = bug confirmed. All tests pass = not reproducible.
|
|
285
344
|
|
|
286
|
-
|
|
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
|
-
|
|
347
|
+
---
|
|
305
348
|
|
|
306
|
-
|
|
307
|
-
|------|---------|
|
|
308
|
-
| `0` | All tests passed |
|
|
309
|
-
| `1` | One or more tests failed |
|
|
349
|
+
## Learning System
|
|
310
350
|
|
|
311
|
-
|
|
351
|
+
The runner learns from every test run — building knowledge about your test suite over time.
|
|
312
352
|
|
|
313
|
-
|
|
314
|
-
import { createRunner } from '@matware/e2e-runner';
|
|
353
|
+
Query insights via the `e2e_learnings` MCP tool:
|
|
315
354
|
|
|
316
|
-
|
|
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
|
-
|
|
319
|
-
|
|
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
|
-
|
|
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
|
-
|
|
325
|
-
const report = await runner.runFile('e2e/tests/login.json');
|
|
375
|
+
---
|
|
326
376
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
-
###
|
|
386
|
+
### Live Execution
|
|
340
387
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
359
|
-
-- npx -y -p @matware/e2e-runner e2e-runner-mcp
|
|
458
|
+
claude plugin install npm:@matware/e2e-runner
|
|
360
459
|
```
|
|
361
460
|
|
|
362
|
-
**
|
|
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
|
-
--
|
|
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
|
|
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
|
-
| `
|
|
377
|
-
| `
|
|
378
|
-
| `
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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
|
|
389
|
-
|
|
390
|
-
|
|
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
|
-
|
|
393
|
-
claude mcp list
|
|
394
|
-
# e2e-runner: ... - Connected
|
|
395
|
-
```
|
|
516
|
+
---
|
|
396
517
|
|
|
397
|
-
##
|
|
518
|
+
## Network Error Handling
|
|
398
519
|
|
|
399
|
-
|
|
520
|
+
### Explicit Assertion
|
|
400
521
|
|
|
401
|
-
|
|
522
|
+
Place `assert_no_network_errors` after critical page loads:
|
|
402
523
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
524
|
+
```json
|
|
525
|
+
{ "type": "goto", "value": "/dashboard" },
|
|
526
|
+
{ "type": "wait", "selector": ".loaded" },
|
|
527
|
+
{ "type": "assert_no_network_errors" }
|
|
528
|
+
```
|
|
406
529
|
|
|
407
|
-
###
|
|
530
|
+
### Global Flag
|
|
408
531
|
|
|
409
|
-
|
|
532
|
+
Set `failOnNetworkError: true` to automatically fail any test with network errors:
|
|
410
533
|
|
|
411
|
-
|
|
534
|
+
```bash
|
|
535
|
+
e2e-runner run --all --fail-on-network-error
|
|
536
|
+
```
|
|
412
537
|
|
|
413
|
-
|
|
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
|
-
|
|
416
|
-
# Fetch and display issue details
|
|
417
|
-
e2e-runner issue https://github.com/owner/repo/issues/42
|
|
540
|
+
### Full Network Logging
|
|
418
541
|
|
|
419
|
-
|
|
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
|
-
|
|
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
|
-
|
|
428
|
-
|
|
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
|
-
|
|
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
|
-
|
|
556
|
+
---
|
|
434
557
|
|
|
435
|
-
|
|
558
|
+
## Hooks
|
|
436
559
|
|
|
437
|
-
|
|
560
|
+
Run actions at lifecycle points. Define globally in config or per-suite:
|
|
438
561
|
|
|
439
|
-
|
|
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
|
-
|
|
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
|
-
|
|
576
|
+
---
|
|
445
577
|
|
|
446
|
-
|
|
578
|
+
## CLI
|
|
447
579
|
|
|
448
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
455
|
-
e2e-runner dashboard # Start
|
|
456
|
-
|
|
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
|
-
###
|
|
606
|
+
### CLI Options
|
|
460
607
|
|
|
461
|
-
|
|
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
|
-
|
|
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
|
-
|
|
624
|
+
## Configuration
|
|
468
625
|
|
|
469
|
-
|
|
626
|
+
Create `e2e.config.js` in your project root:
|
|
470
627
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
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
|
-
|
|
639
|
+
hooks: {
|
|
640
|
+
beforeEach: [{ type: 'goto', value: '/' }],
|
|
641
|
+
},
|
|
476
642
|
|
|
477
|
-
|
|
643
|
+
environments: {
|
|
644
|
+
staging: { baseUrl: 'https://staging.example.com' },
|
|
645
|
+
production: { baseUrl: 'https://example.com', concurrency: 5 },
|
|
646
|
+
},
|
|
647
|
+
};
|
|
648
|
+
```
|
|
478
649
|
|
|
479
|
-
|
|
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
|
-
|
|
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
|
-
|
|
657
|
+
When `--env <name>` is set, the matching profile overrides everything.
|
|
486
658
|
|
|
487
|
-
|
|
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
|
-
|
|
661
|
+
## CI/CD
|
|
492
662
|
|
|
493
|
-
|
|
663
|
+
### JUnit XML
|
|
494
664
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
665
|
+
```bash
|
|
666
|
+
e2e-runner run --all --output junit
|
|
667
|
+
```
|
|
498
668
|
|
|
499
|
-
|
|
669
|
+
### GitHub Actions
|
|
500
670
|
|
|
501
|
-
```
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
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
|
-
|
|
689
|
+
---
|
|
522
690
|
|
|
523
|
-
|
|
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
|
-
|
|
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 (
|
|
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.
|