Repository navigation
e2e@0.22.0
Minor Changes
- #1437
94e6e76Thanks @okwasniewski! - Breaking: a secret fill no longer turns off screenshots for the model.agent.assert(..., { vision: 'only' }),vision: true, thescreenshotand point tools,e2e mcp, ande2e explorefindings keep working after a sign-in, in serial groups, and in tests that restore a saved session. Screenshots still mask secure fields, and secret values are still redacted from all text. A generic secret filled into a plain input, or a value the app shows outside a secure field, such as behind a show-password toggle, is in the screenshot and reaches your model provider, so use test credentials.StepExecutorContext.pixelsTaintedis removed, and a new step'svisionDegradedis neverPIXEL_TAINTED.
Patch Changes
-
#1282
7518ae5Thanks @MarcosCamara01! - Adddrag_atto the agent's pixel tools, inagent.actande2e mcp, anddragAt(from, to)toExecutorActions: a drag from one screenshot point to another, for a shape on a canvas or a pin on a map. Liketap_at, the bare points go to the engine'sdragTopointer kind, where the model aimed; an engine without it drags by id when the points land on two different listed controls, likedrag. The replay cache records both points and replays each the way it replays atap_atpoint. -
#1447
82d5095Thanks @21prnv! - A replay no longer fails its end check on an alert that shows an ISO 8601 timestamp, such asSaved at 2026-10-24T15:41:27.955Z, when the time differs from the recording. -
#1381
d2ffb31Thanks @okwasniewski! -app.startRecording()andapp.stopRecording()record one span of the screen, such as a single transition, on the web and on devices.stopRecordingreturns the videos: a filepath, or aurlwhen a hosted browser or device keeps the recording. A start fails while the test'svideorecords, so set{ video: 'off' }on the test.test('the dialog opens', { video: 'off' }, async ({ app, screen }) => { await app.open(); await app.startRecording({ name: 'dialog' }); await screen.getByRole('button', 'Open').tap(); const [video] = await app.stopRecording(); });
An engine's
startVideoandstopVideomay now be called more than once per attempt, never overlapping. -
#1387
4461e9dThanks @bheemreddy-samsara! - AddonBeforeActiontoagent.act, a hook that runs before each action, so a test can capture the screen an action started on. -
#1379
9e53c40Thanks @okwasniewski! - A mobile target withoutdeviceskips a booted simulator or emulator that another agent-device session holds, such as one another tool is driving, and drives the free ones. When every booted device is held, the run fails atpreparenaming the holding sessions instead of failing on the first one. -
#1382
3a8d6f1Thanks @okwasniewski! - Bump agent-device to 0.21.31, zod to 4.6.7, @modelcontextprotocol/server to 2.4.0, and oxc to 0.155.0. -
#1233
34287cfThanks @Varshith-Kali! - A run now exits with the cleanup error's code, usually 3, when a test's cleanup failed. The list reporter shows the cleanup failure in the summary and under the test for passed and flaky tests, so a CI job that goes red names the cleanup failure instead of reporting a green summary. -
#1351
bfae325Thanks @samanyudas! -e2e runande2e explorerefuse an empty--reporter(--reporter '',--reporter ',', or--reporter "$REPORTERS"with the variable unset) as a usage error, exit 2, instead of running with no reporters and printing nothing. -
#1287
5aec484Thanks @TheTuso! - Ane2ecommand whose config or test file leaves a timer or socket open exits two seconds after it finishes, instead of staying open. -
#1354
6901a01Thanks @samanyudas! -toHaveCountand the list forms oftoHaveTextandtoContainTextread a locator under a missing frame as zero matches, sotoHaveCount(0)passes after an iframe closes instead of failing withLOCATOR_NOT_FOUND. -
#1401
ce249b6Thanks @kacperkapusciak! -e2e explorein a project with no config runs thee2e initwizard first instead of failing withCONFIG_NOT_FOUND. The exploration starts right after when nothing is left to do by hand: dependencies installed, a model with its key set or its sign-in done, and a web target, whose URL init names. Otherwise init lists the steps left, ending with thee2e explorecommand as typed. Without a terminal, as in CI or under a coding agent, nothing changes: no files are written and the error stays. -
#1334
6c8e71fThanks @21prnv! -locator.filter()takeshasNot, which drops matches whose subtree resolves a locator, as in Playwright. Third-party engines must handle the newhasNotfield of afilterexpression. -
#960
ffed34eThanks @enekesabel! - Export the built-in agent's action tools, verdict tool, and rules frome2e/agent:createGrammarTools,createVerdictTool,BASE_RULES, andVERDICT_RULES, plusisRuntimeHardStopand theScreenOutputtype, for a custom tool loop or executor that keeps the built-in actions and verdicts. -
#1389
6b04d18Thanks @kacperkapusciak! -e2e init --example with-angularstarts a new project from the new Angular example: a standalone component greeting app with three locator tests and two agent tests, run against the Angular dev server. -
#1398
e087ed2Thanks @samanyudas! -e2e init --helpno longer says it leaves existing files untouched. It says an existing config and test files stay as they are, whilepackage.jsonand.gitignoreget only what they are missing. -
#1338
0d3e403Thanks @kacperkapusciak! -e2e initlets you select both the web and mobile engines. The engine question is now a multiselect, and--enginetakes a comma-separated list (--engine web,mobile). With both, the config gets a target for each, and the examples go intests/web.e2e.tsandtests/mobile.e2e.ts, each test withrequiresso the other target skips it. Selecting no engine replaces the None option. -
#1463
7372b0aThanks @okwasniewski! -agent.assertandagent.waitFortakeparams, likeagent.act. The judge reads{name}with its value, aunique()value included. ASecretreaches the judge by name only, so check a secret's value on screen with a locator assertion.const name = unique(`acme-${Date.now()}`); await agent.act('create a company named {name}', { params: { name } }); await agent.assert('the table shows company {name}', { params: { name } });
-
#1316
6b41857Thanks @kacperkapusciak! -e2e mcpsessions have arun_codetool. Pass it test statements as a test body writes them, such asawait screen.getByLabel('Email').fill('ada@example.com'), and the session runs them on itsscreenandappwith a test's waits and matchers. It stops at the first failure and returns each statement's result, then what changed on screen. The statements that pass, except reads, join thetest_linesdraft. A project tool namedrun_codenow fails the config load withINVALID_CONFIG. The bundled skill tells the coding agent to run the lines no action printed, such as assertions, withrun_codebefore it writes them into the test. -
#1315
3d2c362Thanks @kacperkapusciak! -e2e mcp'sopen_sessiontakes atest, named like ane2e runpositional (tests/checkout.e2e.ts:12), and runs that one test in the session before handing it over: its hooks,test.extendfixtures, and body, ase2e runruns them. The session then stays on the screen where the test passed or failed, and the opening text leads with the outcome: the error code and message, the failing line with the code around it, the URL, the nodes nearest a locator that matched nothing, and the steps that ran.afterEachhooks and fixture teardown run atclose_session. The test's own steps print no test line; the session's lines start with the agent's first action, andtest_linesreturns them as the lines that continue the test. Agent steps replay and record in the replay cache as on a run's first attempt. A name that selects several tests fails withTEST_AMBIGUOUS, and a serial group member, a test that starts from a setup test's session, or a test that runs as several agents fails withSESSION_TEST_UNSUPPORTED. The bundled skill tells the coding agent to fix a failing test this way instead of clicking through the flow again. -
#1191
9bc7c32Thanks @TheTuso! - Agentnavigateto a full URL on the app now records it without the origin, so cached steps replay when the app runs on another port or host with the sameapp.identity. Re-record older entries to pick this up. -
#1037
a481fd3Thanks @rudycelekli! -locator.filter()takeshasNotText, which drops matches whose text contains a string or matches a RegExp, as in Playwright. Third-party engines must handle the newhasNotTextfield of afilterexpression. -
#1215
d8c597bThanks @Varshith-Kali! - A structured model call that returns no parseable output (for example an emptylengthfinish) now fails asMODEL_OUTPUT_INVALIDinstead ofMODEL_PROVIDER_FAILED. -
#1328
1c4e906Thanks @DeryFerd! -e2e loginon Windows no longer opens the sign-in URL through a command interpreter. The URL comes from the provider's own response in the device flow, andcmd /c startread a|,&, or^in it as command syntax, so a URL that carried one ran a command of its own. The URL is now handed to the default handler for its scheme as a single argument, and only anhttp:orhttps:URL is opened; any other scheme is printed for you to open yourself. -
#1399
92409e5Thanks @samanyudas! - The built-in agent's instructions now say thattap_at,hover_at, anddrag_atact on the bare points when the engine supports it, and fall back to the listed controls by id only when it does not. They previously said every point tool acts on a listed control by its id. -
#1357
9837386Thanks @amoscicki! - A replayed step whose last action starts a navigation now waits up to 15 seconds for the recorded destination, instead of handing off to the agent after about 5 seconds. -
#1056
dc8f56dThanks @rudycelekli! - Report a test's duration from the attempt that decided it when a retry is interrupted or cannot start. -
#1256
2bc00e9Thanks @arun2728! -e2e/runnerexportsexplore(), the counterpart ofe2e explorethatrun()is toe2e run. It takes the project (cwd, andconfigas a file path or anE2EConfigvalue), the goal and its budgets (goal,target,agent,session,maxSteps,timeoutMs),interruptSignal, andonEvent, and resolves with the run's result plus the exploration record (explore.ended,explore.steps,explore.findings) without exiting the caller. Cancellation awaits teardown. The noticese2e exploreprints before the run starts, such as the target it chose, arrive throughonEventasrunnotices. It sharesrun()'s reservation, so overlapping calls reject withRUNNER_BUSY, and each exploration that returns a report sends onee2e_run_completedevent withcommand: "runner.explore". -
#1312
9d884f5Thanks @kacperkapusciak! - The bundled agent skill now has the coding agent write a test while it walks the flow overe2e mcp, instead of exploring first and writing the test from memory. It creates the test file before it opens the session and adds each step as it takes it. A step is anagent.actgoal, written in the words on screen before the agent walks its path, or, for an exact value, theTest line:the action printed. When the outcome shows, the agent locates it and adds theexpect. Thee2e mcpserver's instructions,e2e mcp --help, and the MCP server and coding agents docs say the same. -
#1372
0cc79f1Thanks @BiBoyang! - Report rejected recording writes as not-written. -
#1452
5b6fd01Thanks @samanyudas! - A multi-lineunique()value now replays from the cache. The screen shows it on one line, so the end check now looks for it on one line too. Before, the replay missed:REPLAY_STALE (end-mismatch)with--strict-cache, a hand-off to the agent without it. An older runner reads an entry recorded with this fix asinvalid-entry. -
#1394
e9e8c50Thanks @kacperkapusciak! -e2e upgradeupdates the project's copies of the agent skill in.agents/skills/e2eand.claude/skills/e2eto the newly installed version, instead of telling you to rune2e init. It also updates a stale copy when the packages are already up to date, and--dry-runnames the copies it would update. -
#958
85e92f9Thanks @kuishou68! -uploadandsetInputFilesaccept a button that opens a file chooser, such as one over a hidden file input. The agent'suploadtool says so, so the model can pick the button it sees. -
#1429
3a841bbThanks @KrzysztofMoch! - Aweb()target takesapp.permissionswith'grant'states, granted to every page of the attempt:permissions: { 'clipboard-read': 'grant', 'clipboard-write': 'grant' }lets the app use the clipboard in headless Chromium. Names are checked against the browser's at config load;'deny'and'reset'are refused on web.