e2e 0.15.1 → 0.15.2

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 (87) hide show
  1. package/README.md +51 -24
  2. package/dist/.build.json +1 -1
  3. package/dist/agent/act.js +3 -3
  4. package/dist/agent/act.js.map +1 -1
  5. package/dist/agent/error.d.ts +16 -3
  6. package/dist/agent/error.d.ts.map +1 -1
  7. package/dist/agent/error.js +25 -6
  8. package/dist/agent/error.js.map +1 -1
  9. package/dist/agent/model/tool-choice.d.ts +24 -1
  10. package/dist/agent/model/tool-choice.d.ts.map +1 -1
  11. package/dist/agent/model/tool-choice.js +27 -1
  12. package/dist/agent/model/tool-choice.js.map +1 -1
  13. package/dist/agent/step-cache.d.ts +14 -3
  14. package/dist/agent/step-cache.d.ts.map +1 -1
  15. package/dist/agent/step-cache.js +13 -3
  16. package/dist/agent/step-cache.js.map +1 -1
  17. package/dist/agent/tool-loop.d.ts.map +1 -1
  18. package/dist/agent/tool-loop.js +62 -9
  19. package/dist/agent/tool-loop.js.map +1 -1
  20. package/dist/cache/context.d.ts +19 -6
  21. package/dist/cache/context.d.ts.map +1 -1
  22. package/dist/cache/context.js +15 -21
  23. package/dist/cache/context.js.map +1 -1
  24. package/dist/cli/init/scaffold.d.ts +1 -0
  25. package/dist/cli/init/scaffold.d.ts.map +1 -1
  26. package/dist/cli/init/scaffold.js +2 -1
  27. package/dist/cli/init/scaffold.js.map +1 -1
  28. package/dist/cli/init/sibling-versions.json +1 -1
  29. package/dist/expect/values.js +1 -1
  30. package/dist/expect/values.js.map +1 -1
  31. package/dist/run/execute.d.ts.map +1 -1
  32. package/dist/run/execute.js +21 -8
  33. package/dist/run/execute.js.map +1 -1
  34. package/dist/types.d.ts +1 -1
  35. package/dist/types.d.ts.map +1 -1
  36. package/docs/agent-steps.mdx +126 -0
  37. package/docs/agents.mdx +217 -0
  38. package/docs/api-testing.mdx +65 -0
  39. package/docs/authentication.mdx +345 -0
  40. package/docs/browser.mdx +440 -0
  41. package/docs/bug-bash.mdx +90 -0
  42. package/docs/cache.mdx +306 -0
  43. package/docs/ci.mdx +210 -0
  44. package/docs/coding-agents.mdx +183 -0
  45. package/docs/debugging.mdx +291 -0
  46. package/docs/executors.mdx +243 -0
  47. package/docs/explore.mdx +174 -0
  48. package/docs/github.mdx +184 -0
  49. package/docs/index.mdx +82 -0
  50. package/docs/integrations/eas.mdx +216 -0
  51. package/docs/integrations/index.mdx +24 -0
  52. package/docs/integrations/kernel.mdx +163 -0
  53. package/docs/migrate/cypress.mdx +124 -0
  54. package/docs/migrate/detox.mdx +140 -0
  55. package/docs/migrate/maestro.mdx +229 -0
  56. package/docs/migrate/playwright.mdx +427 -0
  57. package/docs/migrate/selenium.mdx +110 -0
  58. package/docs/mobile-ci.mdx +567 -0
  59. package/docs/mobile.mdx +555 -0
  60. package/docs/models.mdx +241 -0
  61. package/docs/quickstart.mdx +260 -0
  62. package/docs/reference/agent.mdx +524 -0
  63. package/docs/reference/app.mdx +72 -0
  64. package/docs/reference/cli.mdx +817 -0
  65. package/docs/reference/config.mdx +986 -0
  66. package/docs/reference/engine.mdx +1362 -0
  67. package/docs/reference/environment.mdx +113 -0
  68. package/docs/reference/errors.mdx +143 -0
  69. package/docs/reference/expect.mdx +513 -0
  70. package/docs/reference/mcp.mdx +202 -0
  71. package/docs/reference/mobile.mdx +522 -0
  72. package/docs/reference/reporters.mdx +216 -0
  73. package/docs/reference/screen.mdx +688 -0
  74. package/docs/reference/test.mdx +449 -0
  75. package/docs/reference/web.mdx +611 -0
  76. package/docs/security.mdx +292 -0
  77. package/docs/starting-your-app.mdx +231 -0
  78. package/docs/subscriptions.mdx +157 -0
  79. package/docs/telemetry.mdx +185 -0
  80. package/docs/tools.mdx +150 -0
  81. package/docs/viewports.mdx +146 -0
  82. package/docs/writing-an-engine.mdx +316 -0
  83. package/docs/writing-tests.mdx +256 -0
  84. package/package.json +2 -1
  85. package/skills/e2e/SKILL.md +4 -1
  86. package/skills/e2e/references/agent.md +3 -1
  87. package/skills/e2e/references/setup.md +13 -4
@@ -0,0 +1,202 @@
1
+ ---
2
+ title: MCP server (e2e mcp)
3
+ description: Let a coding agent inspect and interact with your app over MCP.
4
+ ---
5
+
6
+ <CodeGroup>
7
+ ```bash npm
8
+ npx e2e mcp [--config <path>] [--target <name>] [--headless] [--max-sessions <n>]
9
+ ```
10
+
11
+ ```bash pnpm
12
+ pnpm exec e2e mcp [--config <path>] [--target <name>] [--headless] [--max-sessions <n>]
13
+ ```
14
+
15
+ ```bash bun
16
+ bunx e2e mcp [--config <path>] [--target <name>] [--headless] [--max-sessions <n>]
17
+ ```
18
+ </CodeGroup>
19
+
20
+ `e2e mcp` lets coding agents such as Claude Code and Cursor inspect your app,
21
+ try locators, and take masked screenshots before writing tests. It runs over
22
+ stdio and uses the project's configured engine.
23
+
24
+ Four MCP tools manage the session and call its available app tools. The app
25
+ tool catalog reloads from the config whenever a session opens.
26
+
27
+ ## Setup
28
+
29
+ The server ships with `e2e`. `e2e init` offers to register it in
30
+ `.mcp.json` (Claude Code) and `.cursor/mcp.json` (Cursor). By hand:
31
+
32
+ <CodeGroup>
33
+ ```bash npm
34
+ claude mcp add e2e -- npx e2e mcp
35
+ ```
36
+
37
+ ```bash pnpm
38
+ claude mcp add e2e -- pnpm exec e2e mcp
39
+ ```
40
+
41
+ ```bash bun
42
+ claude mcp add e2e -- bunx e2e mcp
43
+ ```
44
+ </CodeGroup>
45
+
46
+ For clients that use a `mcpServers` config, add:
47
+
48
+ ```json
49
+ {
50
+ "mcpServers": {
51
+ "e2e": { "command": "npx", "args": ["e2e", "mcp"] }
52
+ }
53
+ }
54
+ ```
55
+
56
+ Start the server in the project directory. Config discovery works like
57
+ `e2e run`. Set `--config` for another location, or pass `config` to
58
+ `open_session` for one session.
59
+
60
+ | Flag | Behavior |
61
+ | --- | --- |
62
+ | `--config <path>` | The config every session loads unless `open_session` names one. Configs are reloaded on every `open_session`, with every file they import by path. |
63
+ | `--target <name>` | The target every session opens on. Otherwise `open_session` names one, or the only target is used; several targets and no name is `TARGET_REQUIRED`. |
64
+ | `--headless` | Hide the browser or simulator. Sessions are headed by default outside CI. |
65
+ | `--max-sessions <n>` | How many sessions may be open at once, 1 through 16; default 4. Each session is its own browser or device. |
66
+
67
+ Operator output goes to stderr, prefixed `e2e mcp:`. Stdout carries only the
68
+ protocol; anything a config module writes to stdout is redirected.
69
+
70
+ ## Tools
71
+
72
+ | Tool | Arguments | Result |
73
+ | --- | --- | --- |
74
+ | `open_session` | `target` (optional), `config` (optional path) | Loads the config, starts the target's app command, boots the engine, starts one attempt, opens the app URL when the engine can navigate. Returns the session id, the catalog, and the first observation. |
75
+ | `tools` | `tool` (optional), `session` (required while several are open) | The catalog, one line per tool. With `tool`, its full description and argument schema. |
76
+ | `call` | `tool`, `args` (optional), `session` (required while several are open) | Runs one catalog tool. Arguments are validated against the tool's closed schema first: a wrong type or an argument the tool does not declare is `INVALID_ARGUMENT`, and nothing runs. An action that fails is an error result that still carries the screen it re-observed, and leads with the tool, its target, and the code: `navigate file:///etc/passwd failed: POLICY_DENIED: forbidden URL scheme: file:`. |
77
+ | `close_session` | `session` (required while several are open) | Saves a recording still running, ends the attempt, disposes the engine, stops the app processes the session started once no other session uses them. |
78
+
79
+ ## Several sessions
80
+
81
+ Several sessions can be open at once, up to `--max-sessions`, each on its
82
+ own attempt and its own browser or device. Parallel agents, such as a
83
+ coding agent's subagents, share one server this way: each opens a session
84
+ and passes its id to every `tools`, `call`, and `close_session`.
85
+
86
+ - `session` may be left out only while exactly one session is open. With
87
+ several open, a call without it fails with `SESSION_REQUIRED` and the
88
+ list of open sessions.
89
+ - A `session` id that is not open fails with `NO_SESSION`; for a session
90
+ that is closing or ended, the message says why.
91
+ - An `open_session` past the limit fails with `SESSION_OPEN`. A session
92
+ holds its slot from `open_session` until its attempt has closed, so
93
+ sessions still booting or still closing count toward it.
94
+ - Sessions open at once share one config: credentials and secrets resolve
95
+ through one registry per process. An `open_session` on another config
96
+ fails with `CONFIG_IN_USE` until the others close.
97
+ - While the server shuts down it cancels sessions still opening and waits
98
+ for them, closes every session, and refuses new ones with `SESSION_OPEN`.
99
+ A client that cancels an `open_session`, or disconnects, cancels it too.
100
+ A cancelled open fails with `CANCELLED` once what it started (an app command
101
+ still waiting on its `readyUrl`, say) has stopped.
102
+ - Each session loads the config afresh, down to the files it imports by
103
+ path, such as a base config it spreads, so each gets engine instances of
104
+ its own. An engine created inside a package is one instance every session
105
+ shares, and a second session on it fails with `ENGINE_IN_USE`.
106
+ - Sessions on one app command share its process: the first session starts
107
+ it, and it stops when the last of them closes. A URL declared with port
108
+ `0` gets its own port in each session, and so its own process. A shared
109
+ start that every waiting session gave up on is cancelled, and the next
110
+ session starts it afresh.
111
+ - On mobile, each session needs its own simulator or emulator: declare one
112
+ target per device, each naming its `device`, and open each session on its
113
+ own target.
114
+
115
+ [Bug bashes](/bug-bash) use this: every verifying subagent drives its own
116
+ session.
117
+
118
+ ### The catalog
119
+
120
+ What `call` can run depends on the session's target:
121
+
122
+ | Catalog tool | Arguments | Result |
123
+ | --- | --- | --- |
124
+ | `observe` | none | A fresh observation, one node per line as `#id role "name" ...`, with the current path and revision. A link's `href` is its path when it is on the app URL's origin, else origin and path; `mailto:`, `tel:`, and `blob:` targets keep their scheme. `…` marks what is left out: `?…` a query, `#…` a fragment, `data:…` or `javascript:…` an inline payload, a trailing `…` a target cut at 256 characters. |
125
+ | `tap`, `double_tap`, `long_press`, `right_click`, `hover`, `type`, `press`, `select`, `check`, `scroll`, `scroll_to`, `drag`, `upload`, `navigate`, `back`, `type_secret` | A node id from the newest observation, plus the value, key, `checked` state, direction, drop target, project-relative `files`, URL, or secret name | The action's summary and what changed on screen. A verb the engine does not declare is not in the catalog. `upload` refuses a path outside the project, a hidden file, or a file under a hidden directory with `POLICY_DENIED`. `type_secret` is listed when the config declares `credentials` or `secrets`; the plaintext never reaches the agent. |
126
+ | `dismiss_keyboard` | none | Hides the on-screen keyboard. Listed when the engine's keyboard declares `dismiss`, as the device engines do. |
127
+ | `locate` | Exactly one of `role` (with optional `name`), `text`, `label`, `placeholder`, `testId`; `exact` | How many nodes match, which, and the `screen.*` call to write. Zero or several matches name the error a test would get. What it shows of a node passes the secret ledger, as `observe` does: a filled secret reads `<secret:name>`. |
128
+ | `screenshot` | none | The masked viewport as an image. From then on every action result carries a fresh screenshot. Once a secret has been filled it answers `PIXEL_TAINTED` instead, for the rest of the session. |
129
+ | `tap_at` | `x`, `y` in the latest screenshot's pixels | Taps that point: a listed control under it by id, otherwise the bare point through the engine's `performAt`; without `performAt` the point must land on a listed control. Listed when the engine declares `tap` or `performAt`. |
130
+ | `hover_at` | `x`, `y` in the latest screenshot's pixels | Hovers that point the same way: a listed control under it by id, otherwise the bare point through `performAt`'s `hover` kind. Listed when the engine declares the `hover` action or pointer kind. |
131
+ | `type_at` | `x`, `y`, `value`; `replace` on an engine with a keyboard | Fills a listed input under the point by id. With a keyboard, anything else is tapped to focus it and typed into, at the caret unless `replace` is set; without one, a point on nothing listed fails. Listed when the engine declares `type` or a keyboard. |
132
+ | `press_at` | `x`, `y`, `key` | Sends the key to a listed control under the point by id; with a keyboard, anything else is tapped to focus it and the key goes through the keyboard. Listed when the engine declares `press` or a keyboard. |
133
+ | `select_at` | `x`, `y`, `value`, the option's visible label | Picks the option in the listed select-like control under the point; nothing listed there fails. Listed when the engine declares `select`. |
134
+ | `start_recording` | `name` (optional; up to 64 letters, digits, `-`, and `_`, starting with a letter or digit) | Starts a video of the app. One recording at a time; a second start reports the one running. Listed when the engine records video. |
135
+ | `stop_recording` | none | Stops the recording and returns the absolute path of each video file. Listed when the engine records video. |
136
+
137
+ The five point tools answer `PIXEL_TAINTED` once a secret has been filled.
138
+ Before the session's first `screenshot` each answers with the line that says
139
+ to take one, at no cost.
140
+
141
+ Project tools in `agents.default.tools` follow in the catalog under
142
+ their own names, scoped to the target's platform. A mobile project that
143
+ passes `mobileTools(...)` also gets `open_app`, `swipe`,
144
+ and `alert`. A project tool named like a built-in fails the config load with `INVALID_CONFIG`. An unknown
145
+ name fails with `UNKNOWN_TOOL` and the list of names.
146
+
147
+ ### Recording
148
+
149
+ A session records video only between `start_recording` and
150
+ `stop_recording`, as many times as needed; the configured
151
+ [`video`](/reference/config#video) mode applies to runs, not sessions. The
152
+ configured [`trace`](/reference/config#trace) mode does apply: a session is
153
+ one attempt that closes as passed, so it keeps a trace under `on` (the local
154
+ default) and records none under a retry mode (the CI default) or
155
+ `retain-on-failure`. A `trace` the config sets on an engine that cannot
156
+ trace is skipped with a notice in the server log, as a run skips it. Each recording is saved to
157
+ `<output>/videos/<session>/<n>[-<name>].webm` (`.mp4` on mobile, and
158
+ [`output`](/reference/config#output) is `.e2e` by default), where `n`
159
+ counts the session's recordings. A web recording that spans a restart or a
160
+ state reset has one file per page, `-part2`, `-part3`, and so on, in play
161
+ order. A browser or device provider that records the lease itself records
162
+ the session instead: [Kernel](/integrations/kernel) downloads its replay,
163
+ saved here as `<n>[-<name>].mp4` like any other file, and a provider that
164
+ keeps its recordings is listed by URL instead of a file. `close_session`, the idle timeout, and the session
165
+ TTL save a recording still running, and the close result lists its files.
166
+
167
+ Recordings are not masked and are not withheld after a secret was filled:
168
+ they are files for a person to watch, and no tool returns their pixels. A
169
+ secret typed into a plain input while recording is readable in the video,
170
+ and a recording stopped after a secret was filled says so.
171
+
172
+ A session is one attempt on one target. A `call` before any session is
173
+ open fails with `NO_SESSION`. A session closes on `close_session`, after 30
174
+ idle minutes, after 4 hours, when the client disconnects, and on SIGINT or
175
+ SIGTERM. The client disconnects when it closes the server's stdin or dies,
176
+ so the pipes break under the server: every session closes, the app commands
177
+ the sessions started stop, and the server exits.
178
+
179
+ Sessions enforce what tests enforce. Node ids are valid only against the
180
+ newest observation. A secret fills only through `type_secret`; once one has
181
+ been filled, `screenshot` and the point tools (`tap_at`, `hover_at`,
182
+ `type_at`, `press_at`, `select_at`) stay in the catalog but answer
183
+ `PIXEL_TAINTED` for the rest of the session. Every text a `call` returns, a node `locate` found,
184
+ an action's result, or an error, passes the attempt's secret ledger. Nothing a
185
+ session does is recorded as a test result or into the replay cache; its
186
+ artifacts land under `<output>/artifacts/<target>/sessions/`, its videos under
187
+ `<output>/videos/`. A later `e2e run` clears `<output>/artifacts`; the
188
+ videos stay.
189
+
190
+ ## Resources
191
+
192
+ | URI | Content |
193
+ | --- | --- |
194
+ | `e2e://guide` | The agent skill's overview, the text `e2e guide` prints. |
195
+ | `e2e://guide/{topic}` | One topic: `setup`, `writing-tests`, `agent`, `running`, `explore`, `debugging`, `mcp`, `bug-bash`. |
196
+
197
+ ## Exit codes
198
+
199
+ `e2e mcp` exits 0 when the client disconnects, with or without a session
200
+ open, or a signal ends it, and 2
201
+ when the command line is invalid. Config and engine failures come back as
202
+ tool errors with the same codes the CLI prints.