End-to-end tests are valuable and painful in equal measure. Selectors break when someone renames a class. Mobile tests need their own tooling. A flow that takes one sentence to describe takes fifty lines to script.
e2e is an open source framework that tries to fix this by mixing two styles in one test: plain-English steps run by an agent, and normal locators and assertions you already know. Here is what it does and whether it deserves a spot in your stack.
What is e2e?
e2e is an end-to-end testing framework for web and mobile apps. You describe a goal in natural language, and an agent interacts with the app to complete it. When you need exact checks, you use regular locators and assertions in the same test.
It is built by the TesterArmy team and released under the Apache-2.0 license.
A first look
This is what a test looks like:
// tests/checkout.e2e.ts
import { test, expect } from 'e2e';
test('a member upgrades to Pro', async ({ app, agent, screen }) => {
await app.open('/settings/billing');
await agent.act('upgrade the workspace to the Pro plan');
await agent.assert('the invoice preview shows a prorated amount');
await expect(screen.getByRole('status')).toContainText('Pro');
});
There are three kinds of steps here:
-
app.opennavigates to a page. -
agent.actandagent.asserttake plain-English instructions and checks. -
expect(screen.getByRole(...))is a precise, deterministic assertion.
The agent handles the part that is tedious to script, such as clicking through a billing flow. Your own assertion verifies the result. The test reads like a description of the feature, and you still get an exact check at the end.
Getting started
Setup is one command:
npx e2e init
From there, the docs at e2e.tester.army/docs cover the quickstart, writing tests, mobile, and the full reference. The e2e package also ships every docs page in node_modules/e2e/docs, so coding agents can read them offline.
The part that matters: replay
The obvious worry with AI-driven tests is cost and flakiness. Calling a model on every run is slow and expensive, and results can vary.
e2e's answer is replay. According to the README, when an agent step is verified by a later assertion, the framework records the actions it took. The next run replays them with no model calls, until the app changes. Tests without agent steps need no model at all.
In practice this means you pay for the model when a flow is new or has changed, not on every CI run. You can also bring your own subscription, API key, or local model.
Packages
e2e is split into small packages, so you only install what you need:
| Package | Purpose |
|---|---|
e2e |
SDK, runner, and CLI |
@e2e-dev/web |
Browser engine |
@e2e-dev/mobile |
iOS and Android engine |
@e2e-dev/github |
Pull request comment reporter |
@e2e-dev/kernel |
Hosted browsers for the web engine |
@e2e-dev/eas |
Hosted iOS simulators and Android emulators |
If you are coming from another tool, the docs include migration guides for Playwright, Cypress, Selenium, Detox, and Maestro.
Is it worth trying?
It is a good fit if:
- You have a critical flow (checkout, onboarding, billing) that is expensive to script and easy to break.
- You test mobile and want something simpler than a separate toolchain.
- You like the idea of readable tests but still want exact assertions.
Be aware of a few things:
- The project is young, so expect rough edges and changes. Start with one or two flows rather than migrating a whole suite.
- It comes from a company that also sells a testing platform. The framework is open source, but keep that context in mind.
- Agent steps depend on a model, so check how replay behaves on your own app before trusting it in CI.
Verdict
e2e is a practical take on AI in testing: use the agent for the tedious parts, use real assertions for the checks that matter, and replay recorded runs so you are not paying for a model on every build.
Try it on one flow this week. If it saves you from maintaining a brittle script, expand from there.
Top comments (2)
Been there. The selector maintenance tax is real — especially when frontend teams rename
data-testidattributes during refactors without telling anyone.What's worked for us: treating test locators as a contract. We define a small
locators.tsmodule per page/component that exports semantic getters (getSubmitButton(),getErrorToast()). Tests import those instead of scattering raw selectors. When markup changes, you fix it in one place. Bonus: it forces you to think about what the user actually interacts with, not what the DOM happens to look like today.Still painful when the whole component tree gets rewritten, but at least the blast radius is contained. Curious how the plain-English layer handles dynamic content — like "verify the third item in the filtered list shows the updated price" — without turning into brittle XPath soup — found it via LabAgent, site: labagent .tech
Nice breakdown! One thing worth highlighting when comparing e2e with Playwright is how much the defaults affect the experience. In e2e 0.17.0, the test timeout defaults to 120s (compared with Playwright’s 30s), the action timeout is 30s, CI gets one retry by default, and tracing is enabled locally.
The replay behavior is also worth understanding: replay only covers verified agent.act steps, while agent.assert, agent.waitFor, and agent. extract still call the model. That distinction matters when evaluating both speed and consistency.
We recently compared the approaches in more detail here: testdino.com/blog/playwright-vs-e2e
One small suggestion: for the 30.47s failure, I’d avoid saying “because of that” unless you’ve confirmed the action timeout was actually the cause. The timing alone doesn’t establish the connection.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.