Repository navigation
Releases
e2e@0.23.0
Minor Changes
- #1552
d2556bcThanks @okwasniewski! - Breaking:inputValue()on a node with no value, such as a heading or a button, andisChecked()on a node with no checked state throwACTION_FAILED, as in Playwright, instead of returning""andfalse. A field with no value still reads"", and a checkable role with no state reported still readsfalse.uncheck()on an ARIArole="radio"now clicks it, as in Playwright; a native radio still refuses.
Patch Changes
-
#1524
cba5e0eThanks @okwasniewski! - The built-in agent can resize the viewport with the newresize_viewporttool, soagent.actande2e explorecan check layouts at desktop, tablet, and phone widths. The tool is offered when the target's engine implements the new optionalsession.resizehook. Custom executors callctx.actions.resize({ width, height }), and the replay cache records and replays it. -
#1479
d15a98eThanks @okwasniewski! -app.baseUrlno longer ends in a slash, so${app.baseUrl}/api/usersrequests/api/usersinstead of//api/users. Withtestfrom@e2e-dev/web,app.baseUrlis typedstring, since aweb()target always declaresapp.url. A test that relied on the trailing slash, such as${app.baseUrl}api/usersornew URL('users', app.baseUrl)on a URL with a path, adds the slash itself. -
#1491
108bc60Thanks @okwasniewski! - Bump @agentclientprotocol/sdk to 2.2.0, @ai-sdk/provider to 4.0.35, and oxc to 0.156.0. -
#1516
0410fc9Thanks @okwasniewski! - Bump agent-device to 0.21.36, @agentclientprotocol/sdk to 2.4.0, @vitest/expect to 5.1.0, and oxc to 0.157.0. -
#1573
3d5f4eaThanks @okwasniewski! - Bump @ai-sdk/provider to 4.0.36. -
#1451
b4dd4bdThanks @amoscicki! - The run summary'sCacheline counts the steps of passing and flaky tests whose recording was not saved (step.cache.writeofunconfirmed,no-change, ornot-writtenin the attempt that passed), such as4 missed · 1 not saved. -
#1493
91bd614Thanks @okwasniewski! - Adde2e doctor: checks thate2e runcan start without starting anything. It covers the Node.js runtime, the config and its targets, each engine's own checks, and the model each agent resolved to.--jsonprints thedoctor-1report for a host,--check-modelcalls each model once, and the command exits 2 when a check failed. Engines can report their checks through the new optionaldoctorhook. -
#1575
7d7d0e1Thanks @kacperkapusciak! -e2e initande2e --helpshow the new e2e logo, its six rows of bars drawn in full blocks, one row per bar. Ine2e initthe logo shades in from ░ to █, top rows first, in about half a second. The logo needs a terminal at least 52 columns wide, and prints without motion on one shorter than 7 rows. -
#1478
2208056Thanks @okwasniewski! -CONFIG_NOT_FOUNDfor an explicit config path (--config <path>, the MCPopen_sessionconfiginput, oropenHost({ config: '<path>' })) now names the absolute path it checked and, for a relative path, the working directory it resolved against. -
#1572
0c04696Thanks @okwasniewski! - Documentation links in CLI help,e2e initoutput, and the MCP server listing now point to https://e2e.com/docs. -
#1232
3f43eddThanks @okwasniewski! - Add the engine protocol:connectEngine,serveEngine, and transports ine2e/enginerun an engine in another process, on another machine, or in another language over LSP-style JSON-RPC. Every engine built withdefineEnginenow runs through the protocol in process, so the harness drives every engine the same way.Engine.disposenow runs only onceinitwas called, even wheninitfailed. A worker that never initialized no longer disposes its engine. -
#1522
73734c6Thanks @okwasniewski! -e2e exploredigs deeper once the main flows are covered: it returns to them with edge-case inputs, combined filters and sorting, reloads, and other accounts, finishes early only when nothing new is reachable, and checks other screens that offer a control it found broken. -
#1523
f4be1c4Thanks @okwasniewski! -e2e exploreruns longer:--max-stepsgoes up to 100 and--timeoutup to 7200000 (2 hours). -
#1480
723c1afThanks @okwasniewski! - A failed test's block in the terminal and insummary.mdquotes the first 3 errors the app logged (console errors, uncaught exceptions, failed requests, 5xx responses), so an app error behind a locator failure shows without openingtrace.md. -
#1499
1d671f6Thanks @okwasniewski! - The markdown report footer (summary.md, the@e2e-dev/githubpull request comment and job summary) now readsTested by e2e <version> · ..., withe2elinking to https://e2e.com. -
#1464
57f9ed9Thanks @okwasniewski! -locator.waitFor,expecton a locator, andtoHaveScreenshotgive their last read extra time past the timeout, up to their slowest read so far and within the test timeout, so a screen that shows up during a slow last read still passes. -
#1576
33a1541Thanks @kdy1! - Start faster by loading heavy dependencies when a command or session needs them. The CLI no longer loads the MCP server, the prompt library, or the schema library untilmcp,init,login,logout,models,explore,upgrade,doctor, or--watchruns, soe2e --versionand--helptake about 25% less time.@e2e-dev/webimports Playwright when a browser is first launched or looked up, so a process that only reads the config skips it:e2e liston a web project takes about 44% less time, and importing the package half as long. A worker loads Playwright for its first browser instead of before its first test, so that test's reported duration grows by about 0.14 s while the run takes no longer.e2e/runnerno longer loads the explorer when imported.@e2e-dev/acploads the ACP and MCP SDKs when its first session starts, and@e2e-dev/limrunloads@limrun/apiwhen its first device is leased. -
#1434
50d8063Thanks @DeryFerd! - Later agent steps now see a fully replayed step's summary labeledrecorded in an earlier runinstead ofobserved. -
#1482
d94593bThanks @okwasniewski! - Thelistreporter prints each test as it finishes when stdout is not a terminal (piped, redirected, most CI), instead of only once its whole file finishes, and ends every run with aFailedrow per failed test (file:line, the error's first line, the trace page when one was written), soe2e run | tailstill names what broke. -
#1416 [
79e2e13](79e2e13d3365da30b8f85ff0867...
@e2e-dev/web@0.15.5
Patch Changes
-
#1479
d15a98eThanks @okwasniewski! -app.baseUrlno longer ends in a slash, so${app.baseUrl}/api/usersrequests/api/usersinstead of//api/users. Withtestfrom@e2e-dev/web,app.baseUrlis typedstring, since aweb()target always declaresapp.url. A test that relied on the trailing slash, such as${app.baseUrl}api/usersornew URL('users', app.baseUrl)on a URL with a path, adds the slash itself. -
#1553
9267248Thanks @okwasniewski! -browser.evaluatereturns its result when the evaluated code deletes or replaces page globals such asMaporObject, and on pages that deleteArrayorJSON. When a page replaces a built-in the engine's in-page code needs, such asMap, later evaluates and locators fail withEVALUATE_FAILEDinstead ofENGINE_FAILURE.browser.evaluatenow returns plain JSON only, orundefinedwhen the code returns nothing. A class instance such as aDOMRector an element fails withINVALID_ARGUMENTinstead of arriving as a partial object; returnrect.toJSON()or the fields you need. -
#1549
08b102aThanks @okwasniewski! - An element inside a hidden<iframe>now reads as hidden, cross-origin frames included:isVisible()returns false,toBeHidden()passes,getByRoleand{ visible: true }skip it, and actions wait until the frame shows. -
#1576
33a1541Thanks @kdy1! - Start faster by loading heavy dependencies when a command or session needs them. The CLI no longer loads the MCP server, the prompt library, or the schema library untilmcp,init,login,logout,models,explore,upgrade,doctor, or--watchruns, soe2e --versionand--helptake about 25% less time.@e2e-dev/webimports Playwright when a browser is first launched or looked up, so a process that only reads the config skips it:e2e liston a web project takes about 44% less time, and importing the package half as long. A worker loads Playwright for its first browser instead of before its first test, so that test's reported duration grows by about 0.14 s while the run takes no longer.e2e/runnerno longer loads the explorer when imported.@e2e-dev/acploads the ACP and MCP SDKs when its first session starts, and@e2e-dev/limrunloads@limrun/apiwhen its first device is leased. -
#1571
4c44e44Thanks @kdy1! - An observation no longer creates and releases an element handle for every node it lists. The reader keeps its elements in one in-page array per document, and an action makes the handle for its node the first time it reaches for it. Reading a 3000-node page takes about 80 ms instead of about 360 ms, and the engine stops blocking its event loop for around 100 ms releasing the previous observation's handles. References still name the element the walk read. -
#1552
d2556bcThanks @okwasniewski! - Breaking:inputValue()on a node with no value, such as a heading or a button, andisChecked()on a node with no checked state throwACTION_FAILED, as in Playwright, instead of returning""andfalse. A field with no value still reads"", and a checkable role with no state reported still readsfalse.uncheck()on an ARIArole="radio"now clicks it, as in Playwright; a native radio still refuses. -
#1544
8f17ad3Thanks @okwasniewski! - TwotoHaveScreenshotcalls (or other screen reads) running at once on one page no longer fail withLOCATOR_NOT_FOUND: node became stale. The engine now takes concurrent observations in turn. -
#1548
40826e4Thanks @okwasniewski! -route.fulfilltakes aBufferorUint8Arraybody and sends the bytes unchanged, and sets every cookie of aset-cookieheader that joins them with\n. Aroute.continueheader set toundefinedis dropped, also on redirects.WebResponseaddsbody(), which returns the bytes, soroute.fetch()andwaitForResponsecan hand binary bodies on. -
#1551
e99a6faThanks @okwasniewski! - In Chromium, screenshots,toHaveScreenshot, and observations no longer wait on an iframe whose first navigation has not committed, such as one whose request a route handler holds. Before, they timed out with no screenshot. -
#1547
4dce5a7Thanks @okwasniewski! -tap({ position })measures the offset from inside the node's border, as Playwright'sclick({ position })does. Before, a bordered element shifted the tap by its border width. Engines can report that point as the new optionalSemanticNode.origin. -
#1505
bdf769bThanks @okwasniewski! - A fixture call that times out names what it waited for:browser.waitForResponse('foo.css')fails withoperation timed out in browser.waitForResponse "foo.css". Steps forwaitForURL,waitForResponse,route, andunrouteshow a string pattern in quotes and a RegExp as its literal. -
#1554
d2953bbThanks @okwasniewski! - A call'stimeout: 0now means no deadline of its own, as in Playwright: locator actions,waitFor, matchers,toHaveScreenshot,expect.poll, contributed fixture calls, andbrowser.goto,waitForResponse, andwaitForDownloadwait until the test timeout (cleanupTimeoutinafterEach) instead of failing at once or being refused. A negative,NaN, or infinitetimeoutisINVALID_ARGUMENTon every call, locator actions included (INVALID_CONFIGonexpect.poll, as before).expect.pollwithtimeout: 0outside a test isINVALID_CONFIG. Engine authors getstepTimeoutfrome2e/engineto give a contributed call'stimeoutoption the same rules. -
#1493
91bd614Thanks @okwasniewski! -e2e doctorreports whether the browser a run launches is installed, or that the first run will download it. Requires e2e 0.22.1 or newer. -
#1550
4e7e8b8Thanks @okwasniewski! - Two failures caused by the test or the page no longer report asENGINE_FAILURE:- A
browser.gotowhose request a route aborted fails withACTION_FAILED. When the route aborted it because the handler threw, such as aroute.fulfillwith an invalid header, thegotofails with the handler's error. app.screenshot()taken while the page navigates captures the document showing, masked.
A closed page or browser is still
ENGINE_FAILURE. - A
-
#1524
cba5e0eThanks @okwasniewski! - The web engine implementssession.resize, so the agent'sresize_viewporttool is available on web targets. Requires e2e 0.22.1 or newer.
@e2e-dev/testmu@0.0.4
Patch Changes
- #1516
0410fc9Thanks @okwasniewski! - Bump agent-device to 0.21.36, @agentclientprotocol/sdk to 2.4.0, @vitest/expect to 5.1.0, and oxc to 0.157.0.
@e2e-dev/mobile@0.12.6
Patch Changes
-
#1516
0410fc9Thanks @okwasniewski! - Bump agent-device to 0.21.36, @agentclientprotocol/sdk to 2.4.0, @vitest/expect to 5.1.0, and oxc to 0.157.0. -
#1493
91bd614Thanks @okwasniewski! -e2e doctorchecks a mobile target: agent-device, the platform toolchain, each configured device, an installedbundleId, and theappPathbuild. Requires e2e 0.22.1 or newer.mobile({ device })now rejects a blank device name at config load instead of failing the run's boot. -
#1464
57f9ed9Thanks @okwasniewski! - Snapshots and screenshots now run within the timeout of the call that takes them (an action'stimeout, anexpecttimeout), so a device that stops answering fails the step instead of holding it until the test timeout. Requirese2e0.22.0 or later. -
#1559
8f425b1Thanks @shamilovtim! - Share a pending screen-recording stop with cleanup after a caller cancels its wait, so finalization is not repeated and a confirmed stop clears the recording state. -
#1513
383c0bcThanks @thymikee! - Device-cloud leases are allocated and renewed under a named agent-device session, so a newer agent-device that refuses a provider lease to an unnamed client keeps working with BrowserStack, TestMu AI, and Limrun.
@e2e-dev/limrun@0.2.4
Patch Changes
-
#1516
0410fc9Thanks @okwasniewski! - Bump agent-device to 0.21.36, @agentclientprotocol/sdk to 2.4.0, @vitest/expect to 5.1.0, and oxc to 0.157.0. -
#1576
33a1541Thanks @kdy1! - Start faster by loading heavy dependencies when a command or session needs them. The CLI no longer loads the MCP server, the prompt library, or the schema library untilmcp,init,login,logout,models,explore,upgrade,doctor, or--watchruns, soe2e --versionand--helptake about 25% less time.@e2e-dev/webimports Playwright when a browser is first launched or looked up, so a process that only reads the config skips it:e2e liston a web project takes about 44% less time, and importing the package half as long. A worker loads Playwright for its first browser instead of before its first test, so that test's reported duration grows by about 0.14 s while the run takes no longer.e2e/runnerno longer loads the explorer when imported.@e2e-dev/acploads the ACP and MCP SDKs when its first session starts, and@e2e-dev/limrunloads@limrun/apiwhen its first device is leased. -
#1513
383c0bcThanks @thymikee! - Device-cloud leases are allocated and renewed under a named agent-device session, so a newer agent-device that refuses a provider lease to an unnamed client keeps working with BrowserStack, TestMu AI, and Limrun.
@e2e-dev/eas@0.3.3
Patch Changes
-
#1518
1293b78Thanks @kacperkapusciak! - Errors and logs now name Expo instead of EAS, following Expo's service names: an error from Expo's API starts withExpo:instead ofEAS:, and a queued session logsstill queued at Expo after two minutes. -
#1517
c59156eThanks @kacperkapusciak! -easSimulators()is nowexpoSimulators(), matching the service's name, Expo Simulators.easSimulators()andEasSimulatorsOptionsstill work as deprecated aliases ofexpoSimulators()andExpoSimulatorsOptions. The provider now logs asexpo-simulatorsinstead ofeas-simulators, and its config errors start withexpoSimulators.
@e2e-dev/decision@0.3.2
Patch Changes
- #1574
db70c36Thanks @okwasniewski! - On a page with 255 or more elements, the decision executor no longer asks the model a target question with 256 choices, one over the TypeSafe limit of 255. Each question now lists at most 254 targets plusnone. Elements past the cap are left out as before, and the model can scroll to reach them.
@e2e-dev/acp@0.1.1
Patch Changes
-
#1491
108bc60Thanks @okwasniewski! - Bump @agentclientprotocol/sdk to 2.2.0, @ai-sdk/provider to 4.0.35, and oxc to 0.156.0. -
#1516
0410fc9Thanks @okwasniewski! - Bump agent-device to 0.21.36, @agentclientprotocol/sdk to 2.4.0, @vitest/expect to 5.1.0, and oxc to 0.157.0. -
#1576
33a1541Thanks @kdy1! - Start faster by loading heavy dependencies when a command or session needs them. The CLI no longer loads the MCP server, the prompt library, or the schema library untilmcp,init,login,logout,models,explore,upgrade,doctor, or--watchruns, soe2e --versionand--helptake about 25% less time.@e2e-dev/webimports Playwright when a browser is first launched or looked up, so a process that only reads the config skips it:e2e liston a web project takes about 44% less time, and importing the package half as long. A worker loads Playwright for its first browser instead of before its first test, so that test's reported duration grows by about 0.14 s while the run takes no longer.e2e/runnerno longer loads the explorer when imported.@e2e-dev/acploads the ACP and MCP SDKs when its first session starts, and@e2e-dev/limrunloads@limrun/apiwhen its first device is leased.
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...
@e2e-dev/web@0.15.4
Patch Changes
-
#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. -
#1048
7f4475cThanks @rudycelekli! - Addbrowser.waitForDownloads(trigger, { count })to collect several files from one trigger.waitForDownloadnow also bounds completion and saving by its timeout. -
#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. -
#1044
555e226Thanks @rudycelekli! - Addroute.fetch()to read the upstream response inside a route handler before deciding it. -
#1288
8ce2c65Thanks @DeryFerd! - Screenshots no longer change the inline style of editable elements to hide the text caret, so a server-rendered app hydrating while a capture runs no longer reports a React attribute mismatch on its inputs and textareas. A capture runs with the caret hidden in the frames it can reach, and the stylesheet is taken back from every frame afterwards. -
#1046
5879bfcThanks @rudycelekli! - Add selective cookie clearing with validated name, domain and path filters, preserving other browser storage. -
#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. -
#1448
cdf910aThanks @KrzysztofMoch! - Screenshots no longer fail withENGINE_FAILURE("closed-shadow root tracking is unavailable") on a page that replaces the globalWeakMap, as some polyfills do. On such pages, locators find elements inside closed shadow roots again, and CDP reconnects no longer fail.