# What's new in e2e 0.23

> e2e 0.23 includes agent steps that run on your Claude Code login, real iOS and Android devices on BrowserStack, e2e doctor, MCP test runs, and an engine protocol.

By Oskar Kwasniewski. Published 2026-11-05. Canonical URL: https://e2e.com/blog/e2e-0-23

e2e 0.23 includes agent steps on your Claude Code subscription, real devices on BrowserStack, a setup check, test runs from your coding agent, and an engine protocol. Highlights:

- [**Claude Code subscription**](#use-your-claude-code-subscription): agent steps run on your own Claude login
- [**BrowserStack**](#real-ios-and-android-devices-on-browserstack): real iOS and Android devices for the mobile engine
- [**e2e doctor**](#e2e-doctor): checks that `e2e run` can start, without starting anything
- [**MCP test runs**](#tests-from-inside-your-coding-agent-mcp): your coding agent runs tests without a shell
- [**Engine protocol**](#engines-in-any-process-or-language): run an engine in another process, machine, or language

Upgrade `e2e`, your `@e2e-dev/*` packages and the e2e skill with:

```bash
npx e2e@latest upgrade
```

Or start a new project with `npx e2e@latest init`.

## Use your Claude Code subscription

Your agent steps can now run on Claude Code, signed in with your own Claude login. No separate model provider needed. Install `@e2e-dev/acp` and Zed's Claude Code adapter, sign in with `claude` (or set `ANTHROPIC_API_KEY`), and point your agent at `claudeCode()`:

```bash
npm install -D @e2e-dev/acp @agentclientprotocol/claude-agent-acp
```

```ts
import type { E2EConfig } from "e2e";
import { web } from "@e2e-dev/web";
import { claudeCode } from "@e2e-dev/acp";

export default {
  targets: [{ engine: web(), app: { url: "http://localhost:3000" } }],
  agents: { default: { executor: claudeCode({ model: "sonnet" }) } },
} satisfies E2EConfig;
```

Claude Code only gets e2e's step tools. No built-in tools, no file system, no terminal. Every action goes through the runner, so steps replay from cache without the agent. Codex works the same way with `codex()`, and `acp({ command, args })` starts any other ACP agent ([#960](https://github.com/tester-army/e2e/pull/960), [guide](https://e2e.com/docs/subscriptions#use-your-coding-agent)).

## Real iOS and Android devices on BrowserStack

The new `@e2e-dev/browserstack` package adds `browserstack()`, which leases BrowserStack App Automate real devices for the mobile engine. An `https` app uploads once per run, and each attempt's video links to BrowserStack's recording of the session ([#1307](https://github.com/tester-army/e2e/pull/1307)).

## e2e doctor

`e2e doctor` checks that `e2e run` can start, without starting anything. It covers Node.js, your config and targets, each engine's own checks for web and mobile, and the model each agent resolves to. It exits with code 2 when a check fails. Run it first in CI as a preflight ([#1493](https://github.com/tester-army/e2e/pull/1493)).

```bash
npx e2e doctor --check-model   # also calls each model once
npx e2e doctor --json          # machine-readable report
```

## Tests from inside your coding agent (MCP)

`e2e mcp` now has a `run_tests` tool. A coding agent can run a file, a single test, or the whole suite without a shell ([#1520](https://github.com/tester-army/e2e/pull/1520)). `run_code` runs test statements in a live session and adds the ones that pass to a test draft ([#1316](https://github.com/tester-army/e2e/pull/1316)). On web targets, the agent can also resize the viewport with the new `resize_viewport` tool to check desktop, tablet, and phone layouts ([#1524](https://github.com/tester-army/e2e/pull/1524)).

```txt
run_tests {files: ["tests/checkout.e2e.ts:12"]}
```

## Engines in any process or language

The new engine protocol lets `connectEngine` and `serveEngine` in `e2e/engine` run an engine in another process, on another machine, or in another language, over LSP-style JSON-RPC. Every engine built with `defineEngine`, ours included, now goes through the same protocol in process. So a custom engine gets driven exactly like `web()` or `mobile()` ([#1232](https://github.com/tester-army/e2e/pull/1232)).

## Also new

- Faster startup: `e2e --version` and `--help` take about 25% less time, and `e2e list` on a web project about 44% less ([#1576](https://github.com/tester-army/e2e/pull/1576)).
- `test.fail` marks a test that's expected to fail, and it fails with `UNEXPECTED_PASS` once it passes ([#1539](https://github.com/tester-army/e2e/pull/1539)).
- `e2e explore` digs deeper into covered flows and can run up to 100 steps or 2 hours ([#1522](https://github.com/tester-army/e2e/pull/1522), [#1523](https://github.com/tester-army/e2e/pull/1523)).
- A failed test's report quotes the first 3 errors the app logged ([#1480](https://github.com/tester-army/e2e/pull/1480)).
- In CI, the `list` reporter prints each test as it finishes and ends with a `Failed` row per failed test ([#1482](https://github.com/tester-army/e2e/pull/1482)).
- `drag_at` lets the agent drag between screenshot points, such as canvas shapes or map pins ([#1282](https://github.com/tester-army/e2e/pull/1282)).
- `e2e init` can set up web and mobile together with `--engine web,mobile` ([#1338](https://github.com/tester-army/e2e/pull/1338)).
- A new e2e logo in `e2e init` and `--help`, and docs links now point to [e2e.com/docs](https://e2e.com/docs) ([#1575](https://github.com/tester-army/e2e/pull/1575), [#1572](https://github.com/tester-army/e2e/pull/1572)).

Everything else is in the [0.22.0](https://github.com/tester-army/e2e/releases/tag/e2e%400.22.0) and [0.23.0](https://github.com/tester-army/e2e/releases/tag/e2e%400.23.0) release notes.

## Upgrading

Some behavior changed and might break a test:

- A secret fill no longer turns off screenshots for the model. Secure fields are still masked. A secret typed into a plain input can show up in screenshots, so use test credentials ([#1437](https://github.com/tester-army/e2e/pull/1437)).
- `inputValue()` on a node with no value and `isChecked()` on a node with no checked state now throw `ACTION_FAILED`, and `uncheck()` on an ARIA radio clicks it ([#1552](https://github.com/tester-army/e2e/pull/1552)).
- `app.baseUrl` no longer ends in a slash. Write `${app.baseUrl}/api/users` ([#1479](https://github.com/tester-army/e2e/pull/1479)).
- `browser.evaluate` returns plain JSON only; return `rect.toJSON()` or plain fields instead of class instances ([#1553](https://github.com/tester-army/e2e/pull/1553)).
- `tap({ position })` measures from inside the border ([#1547](https://github.com/tester-army/e2e/pull/1547)).
- `ActionEvent` from `onAction` is now a union keyed by `action` ([#1500](https://github.com/tester-army/e2e/pull/1500)).
- `Engine.dispose` runs only after `init` was called ([#1232](https://github.com/tester-army/e2e/pull/1232)).
- `timeout: 0` means no deadline of its own ([#1554](https://github.com/tester-army/e2e/pull/1554)).
- `easSimulators()` is now `expoSimulators()`. The old name still works but is deprecated ([#1517](https://github.com/tester-army/e2e/pull/1517)).

## Credits

Thanks to everyone who contributed:

- **[@kdy1](https://github.com/kdy1)** - faster startup ([#1576](https://github.com/tester-army/e2e/pull/1576)), web performance (lazy element handles, native screenshot hashing, [#1571](https://github.com/tester-army/e2e/pull/1571)) and CI Chromium apt caching ([#1569](https://github.com/tester-army/e2e/pull/1569))
- **[@NathanWalker](https://github.com/NathanWalker)** - NativeScript test ids in the e2e skill ([#1567](https://github.com/tester-army/e2e/pull/1567))
- **[@shamilovtim](https://github.com/shamilovtim)** - mobile screen-recording stop fix ([#1559](https://github.com/tester-army/e2e/pull/1559))
- **[@enekesabel](https://github.com/enekesabel)** - ACP package ([#960](https://github.com/tester-army/e2e/pull/960))
- **[@malopezr7](https://github.com/malopezr7)** - BrowserStack package ([#1307](https://github.com/tester-army/e2e/pull/1307))
- **[@MarcosCamara01](https://github.com/MarcosCamara01)** - `drag_at` ([#1282](https://github.com/tester-army/e2e/pull/1282))
- **[@bheemreddy-samsara](https://github.com/bheemreddy-samsara)** - `onBeforeAction` ([#1387](https://github.com/tester-army/e2e/pull/1387)), point coordinates in `onAction` ([#1500](https://github.com/tester-army/e2e/pull/1500)), agent-device hosted-fill fixes ([#1410](https://github.com/tester-army/e2e/pull/1410))
- **[@leszko11](https://github.com/leszko11)** - video and shared-app test fixes ([#1566](https://github.com/tester-army/e2e/pull/1566))
- **[@dajiaohuang](https://github.com/dajiaohuang)** - security docs ([#1519](https://github.com/tester-army/e2e/pull/1519))
- **[@WhitePepperLambSoup](https://github.com/WhitePepperLambSoup)** - Playwright migration docs ([#1508](https://github.com/tester-army/e2e/pull/1508))
- **[@kacperkapusciak](https://github.com/kacperkapusciak)**, **[@samanyudas](https://github.com/samanyudas)**, **[@21prnv](https://github.com/21prnv)**, **[@rudycelekli](https://github.com/rudycelekli)**, **[@DeryFerd](https://github.com/DeryFerd)**, **[@Varshith-Kali](https://github.com/Varshith-Kali)**, **[@thymikee](https://github.com/thymikee)**, **[@amoscicki](https://github.com/amoscicki)**, **[@piotrpasztor](https://github.com/piotrpasztor)**, and others across docs, mobile, report, and examples
