Skip to content

Releases

e2e@0.23.0

Choose a tag to compare

@github-actions github-actions released this 05 Nov 14:33
5f25692

Minor Changes

  • #1552 d2556bc Thanks @okwasniewski! - Breaking: inputValue() on a node with no value, such as a heading or a button, and isChecked() on a node with no checked state throw ACTION_FAILED, as in Playwright, instead of returning "" and false. A field with no value still reads "", and a checkable role with no state reported still reads false. uncheck() on an ARIA role="radio" now clicks it, as in Playwright; a native radio still refuses.

Patch Changes

  • #1524 cba5e0e Thanks @okwasniewski! - The built-in agent can resize the viewport with the new resize_viewport tool, so agent.act and e2e explore can check layouts at desktop, tablet, and phone widths. The tool is offered when the target's engine implements the new optional session.resize hook. Custom executors call ctx.actions.resize({ width, height }), and the replay cache records and replays it.

  • #1479 d15a98e Thanks @okwasniewski! - app.baseUrl no longer ends in a slash, so ${app.baseUrl}/api/users requests /api/users instead of //api/users. With test from @e2e-dev/web, app.baseUrl is typed string, since a web() target always declares app.url. A test that relied on the trailing slash, such as ${app.baseUrl}api/users or new URL('users', app.baseUrl) on a URL with a path, adds the slash itself.

  • #1491 108bc60 Thanks @okwasniewski! - Bump @agentclientprotocol/sdk to 2.2.0, @ai-sdk/provider to 4.0.35, and oxc to 0.156.0.

  • #1516 0410fc9 Thanks @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 3d5f4ea Thanks @okwasniewski! - Bump @ai-sdk/provider to 4.0.36.

  • #1451 b4dd4bd Thanks @amoscicki! - The run summary's Cache line counts the steps of passing and flaky tests whose recording was not saved (step.cache.write of unconfirmed, no-change, or not-written in the attempt that passed), such as 4 missed · 1 not saved.

  • #1493 91bd614 Thanks @okwasniewski! - Add e2e doctor: checks that e2e run can 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. --json prints the doctor-1 report for a host, --check-model calls each model once, and the command exits 2 when a check failed. Engines can report their checks through the new optional doctor hook.

  • #1575 7d7d0e1 Thanks @kacperkapusciak! - e2e init and e2e --help show the new e2e logo, its six rows of bars drawn in full blocks, one row per bar. In e2e init the 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 2208056 Thanks @okwasniewski! - CONFIG_NOT_FOUND for an explicit config path (--config <path>, the MCP open_session config input, or openHost({ config: '<path>' })) now names the absolute path it checked and, for a relative path, the working directory it resolved against.

  • #1572 0c04696 Thanks @okwasniewski! - Documentation links in CLI help, e2e init output, and the MCP server listing now point to https://e2e.com/docs.

  • #1232 3f43edd Thanks @okwasniewski! - Add the engine protocol: connectEngine, serveEngine, and transports 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 now runs through the protocol in process, so the harness drives every engine the same way.

    Engine.dispose now runs only once init was called, even when init failed. A worker that never initialized no longer disposes its engine.

  • #1522 73734c6 Thanks @okwasniewski! - e2e explore digs 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 f4be1c4 Thanks @okwasniewski! - e2e explore runs longer: --max-steps goes up to 100 and --timeout up to 7200000 (2 hours).

  • #1480 723c1af Thanks @okwasniewski! - A failed test's block in the terminal and in summary.md quotes 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 opening trace.md.

  • #1499 1d671f6 Thanks @okwasniewski! - The markdown report footer (summary.md, the @e2e-dev/github pull request comment and job summary) now reads Tested by e2e <version> · ..., with e2e linking to https://e2e.com.

  • #1464 57f9ed9 Thanks @okwasniewski! - locator.waitFor, expect on a locator, and toHaveScreenshot give 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 33a1541 Thanks @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 until mcp, init, login, logout, models, explore, upgrade, doctor, or --watch runs, so e2e --version and --help take about 25% less time. @e2e-dev/web imports Playwright when a browser is first launched or looked up, so a process that only reads the config skips it: e2e list on 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/runner no longer loads the explorer when imported. @e2e-dev/acp loads the ACP and MCP SDKs when its first session starts, and @e2e-dev/limrun loads @limrun/api when its first device is leased.

  • #1434 50d8063 Thanks @DeryFerd! - Later agent steps now see a fully replayed step's summary labeled recorded in an earlier run instead of observed.

  • #1482 d94593b Thanks @okwasniewski! - The list reporter 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 a Failed row per failed test (file:line, the error's first line, the trace page when one was written), so e2e run | tail still names what broke.

  • #1416 [79e2e13](79e2e13d3365da30b8f85ff0867...

Read more

@e2e-dev/web@0.15.5

Choose a tag to compare

@github-actions github-actions released this 05 Nov 14:33
5f25692

Patch Changes

  • #1479 d15a98e Thanks @okwasniewski! - app.baseUrl no longer ends in a slash, so ${app.baseUrl}/api/users requests /api/users instead of //api/users. With test from @e2e-dev/web, app.baseUrl is typed string, since a web() target always declares app.url. A test that relied on the trailing slash, such as ${app.baseUrl}api/users or new URL('users', app.baseUrl) on a URL with a path, adds the slash itself.

  • #1553 9267248 Thanks @okwasniewski! - browser.evaluate returns its result when the evaluated code deletes or replaces page globals such as Map or Object, and on pages that delete Array or JSON. When a page replaces a built-in the engine's in-page code needs, such as Map, later evaluates and locators fail with EVALUATE_FAILED instead of ENGINE_FAILURE.

    browser.evaluate now returns plain JSON only, or undefined when the code returns nothing. A class instance such as a DOMRect or an element fails with INVALID_ARGUMENT instead of arriving as a partial object; return rect.toJSON() or the fields you need.

  • #1549 08b102a Thanks @okwasniewski! - An element inside a hidden <iframe> now reads as hidden, cross-origin frames included: isVisible() returns false, toBeHidden() passes, getByRole and { visible: true } skip it, and actions wait until the frame shows.

  • #1576 33a1541 Thanks @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 until mcp, init, login, logout, models, explore, upgrade, doctor, or --watch runs, so e2e --version and --help take about 25% less time. @e2e-dev/web imports Playwright when a browser is first launched or looked up, so a process that only reads the config skips it: e2e list on 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/runner no longer loads the explorer when imported. @e2e-dev/acp loads the ACP and MCP SDKs when its first session starts, and @e2e-dev/limrun loads @limrun/api when its first device is leased.

  • #1571 4c44e44 Thanks @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 d2556bc Thanks @okwasniewski! - Breaking: inputValue() on a node with no value, such as a heading or a button, and isChecked() on a node with no checked state throw ACTION_FAILED, as in Playwright, instead of returning "" and false. A field with no value still reads "", and a checkable role with no state reported still reads false. uncheck() on an ARIA role="radio" now clicks it, as in Playwright; a native radio still refuses.

  • #1544 8f17ad3 Thanks @okwasniewski! - Two toHaveScreenshot calls (or other screen reads) running at once on one page no longer fail with LOCATOR_NOT_FOUND: node became stale. The engine now takes concurrent observations in turn.

  • #1548 40826e4 Thanks @okwasniewski! - route.fulfill takes a Buffer or Uint8Array body and sends the bytes unchanged, and sets every cookie of a set-cookie header that joins them with \n. A route.continue header set to undefined is dropped, also on redirects. WebResponse adds body(), which returns the bytes, so route.fetch() and waitForResponse can hand binary bodies on.

  • #1551 e99a6fa Thanks @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 4dce5a7 Thanks @okwasniewski! - tap({ position }) measures the offset from inside the node's border, as Playwright's click({ position }) does. Before, a bordered element shifted the tap by its border width. Engines can report that point as the new optional SemanticNode.origin.

  • #1505 bdf769b Thanks @okwasniewski! - A fixture call that times out names what it waited for: browser.waitForResponse('foo.css') fails with operation timed out in browser.waitForResponse "foo.css". Steps for waitForURL, waitForResponse, route, and unroute show a string pattern in quotes and a RegExp as its literal.

  • #1554 d2953bb Thanks @okwasniewski! - A call's timeout: 0 now means no deadline of its own, as in Playwright: locator actions, waitFor, matchers, toHaveScreenshot, expect.poll, contributed fixture calls, and browser.goto, waitForResponse, and waitForDownload wait until the test timeout (cleanupTimeout in afterEach) instead of failing at once or being refused. A negative, NaN, or infinite timeout is INVALID_ARGUMENT on every call, locator actions included (INVALID_CONFIG on expect.poll, as before). expect.poll with timeout: 0 outside a test is INVALID_CONFIG. Engine authors get stepTimeout from e2e/engine to give a contributed call's timeout option the same rules.

  • #1493 91bd614 Thanks @okwasniewski! - e2e doctor reports whether the browser a run launches is installed, or that the first run will download it. Requires e2e 0.22.1 or newer.

  • #1550 4e7e8b8 Thanks @okwasniewski! - Two failures caused by the test or the page no longer report as ENGINE_FAILURE:

    • A browser.goto whose request a route aborted fails with ACTION_FAILED. When the route aborted it because the handler threw, such as a route.fulfill with an invalid header, the goto fails 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.

  • #1524 cba5e0e Thanks @okwasniewski! - The web engine implements session.resize, so the agent's resize_viewport tool is available on web targets. Requires e2e 0.22.1 or newer.

@e2e-dev/testmu@0.0.4

Choose a tag to compare

@github-actions github-actions released this 05 Nov 14:33
5f25692

Patch Changes

  • #1516 0410fc9 Thanks @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

Choose a tag to compare

@github-actions github-actions released this 05 Nov 14:33
5f25692

Patch Changes

  • #1516 0410fc9 Thanks @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 91bd614 Thanks @okwasniewski! - e2e doctor checks a mobile target: agent-device, the platform toolchain, each configured device, an installed bundleId, and the appPath build. 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 57f9ed9 Thanks @okwasniewski! - Snapshots and screenshots now run within the timeout of the call that takes them (an action's timeout, an expect timeout), so a device that stops answering fails the step instead of holding it until the test timeout. Requires e2e 0.22.0 or later.

  • #1559 8f425b1 Thanks @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 383c0bc Thanks @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

Choose a tag to compare

@github-actions github-actions released this 05 Nov 14:33
5f25692

Patch Changes

  • #1516 0410fc9 Thanks @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 33a1541 Thanks @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 until mcp, init, login, logout, models, explore, upgrade, doctor, or --watch runs, so e2e --version and --help take about 25% less time. @e2e-dev/web imports Playwright when a browser is first launched or looked up, so a process that only reads the config skips it: e2e list on 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/runner no longer loads the explorer when imported. @e2e-dev/acp loads the ACP and MCP SDKs when its first session starts, and @e2e-dev/limrun loads @limrun/api when its first device is leased.

  • #1513 383c0bc Thanks @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

Choose a tag to compare

@github-actions github-actions released this 05 Nov 14:33
5f25692

Patch Changes

  • #1518 1293b78 Thanks @kacperkapusciak! - Errors and logs now name Expo instead of EAS, following Expo's service names: an error from Expo's API starts with Expo: instead of EAS:, and a queued session logs still queued at Expo after two minutes.

  • #1517 c59156e Thanks @kacperkapusciak! - easSimulators() is now expoSimulators(), matching the service's name, Expo Simulators. easSimulators() and EasSimulatorsOptions still work as deprecated aliases of expoSimulators() and ExpoSimulatorsOptions. The provider now logs as expo-simulators instead of eas-simulators, and its config errors start with expoSimulators.

@e2e-dev/decision@0.3.2

Choose a tag to compare

@github-actions github-actions released this 05 Nov 14:33
5f25692

Patch Changes

  • #1574 db70c36 Thanks @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 plus none. Elements past the cap are left out as before, and the model can scroll to reach them.

@e2e-dev/acp@0.1.1

Choose a tag to compare

@github-actions github-actions released this 05 Nov 14:33
5f25692

Patch Changes

  • #1491 108bc60 Thanks @okwasniewski! - Bump @agentclientprotocol/sdk to 2.2.0, @ai-sdk/provider to 4.0.35, and oxc to 0.156.0.

  • #1516 0410fc9 Thanks @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 33a1541 Thanks @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 until mcp, init, login, logout, models, explore, upgrade, doctor, or --watch runs, so e2e --version and --help take about 25% less time. @e2e-dev/web imports Playwright when a browser is first launched or looked up, so a process that only reads the config skips it: e2e list on 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/runner no longer loads the explorer when imported. @e2e-dev/acp loads the ACP and MCP SDKs when its first session starts, and @e2e-dev/limrun loads @limrun/api when its first device is leased.

e2e@0.22.0

Choose a tag to compare

@github-actions github-actions released this 30 Oct 16:28
cad17c3

Minor Changes

  • #1437 94e6e76 Thanks @okwasniewski! - Breaking: a secret fill no longer turns off screenshots for the model. agent.assert(..., { vision: 'only' }), vision: true, the screenshot and point tools, e2e mcp, and e2e explore findings 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.pixelsTainted is removed, and a new step's visionDegraded is never PIXEL_TAINTED.

Patch Changes

  • #1282 7518ae5 Thanks @MarcosCamara01! - Add drag_at to the agent's pixel tools, in agent.act and e2e mcp, and dragAt(from, to) to ExecutorActions: a drag from one screenshot point to another, for a shape on a canvas or a pin on a map. Like tap_at, the bare points go to the engine's dragTo pointer kind, where the model aimed; an engine without it drags by id when the points land on two different listed controls, like drag. The replay cache records both points and replays each the way it replays a tap_at point.

  • #1447 82d5095 Thanks @21prnv! - A replay no longer fails its end check on an alert that shows an ISO 8601 timestamp, such as Saved at 2026-10-24T15:41:27.955Z, when the time differs from the recording.

  • #1381 d2ffb31 Thanks @okwasniewski! - app.startRecording() and app.stopRecording() record one span of the screen, such as a single transition, on the web and on devices. stopRecording returns the videos: a file path, or a url when a hosted browser or device keeps the recording. A start fails while the test's video records, 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 startVideo and stopVideo may now be called more than once per attempt, never overlapping.

  • #1387 4461e9d Thanks @bheemreddy-samsara! - Add onBeforeAction to agent.act, a hook that runs before each action, so a test can capture the screen an action started on.

  • #1379 9e53c40 Thanks @okwasniewski! - A mobile target without device skips 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 at prepare naming the holding sessions instead of failing on the first one.

  • #1382 3a8d6f1 Thanks @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 34287cf Thanks @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 bfae325 Thanks @samanyudas! - e2e run and e2e explore refuse 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 5aec484 Thanks @TheTuso! - An e2e command whose config or test file leaves a timer or socket open exits two seconds after it finishes, instead of staying open.

  • #1354 6901a01 Thanks @samanyudas! - toHaveCount and the list forms of toHaveText and toContainText read a locator under a missing frame as zero matches, so toHaveCount(0) passes after an iframe closes instead of failing with LOCATOR_NOT_FOUND.

  • #1401 ce249b6 Thanks @kacperkapusciak! - e2e explore in a project with no config runs the e2e init wizard first instead of failing with CONFIG_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 the e2e explore command as typed. Without a terminal, as in CI or under a coding agent, nothing changes: no files are written and the error stays.

  • #1334 6c8e71f Thanks @21prnv! - locator.filter() takes hasNot, which drops matches whose subtree resolves a locator, as in Playwright. Third-party engines must handle the new hasNot field of a filter expression.

  • #960 ffed34e Thanks @enekesabel! - Export the built-in agent's action tools, verdict tool, and rules from e2e/agent: createGrammarTools, createVerdictTool, BASE_RULES, and VERDICT_RULES, plus isRuntimeHardStop and the ScreenOutput type, for a custom tool loop or executor that keeps the built-in actions and verdicts.

  • #1389 6b04d18 Thanks @kacperkapusciak! - e2e init --example with-angular starts 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 e087ed2 Thanks @samanyudas! - e2e init --help no longer says it leaves existing files untouched. It says an existing config and test files stay as they are, while package.json and .gitignore get only what they are missing.

  • #1338 0d3e403 Thanks @kacperkapusciak! - e2e init lets you select both the web and mobile engines. The engine question is now a multiselect, and --engine takes a comma-separated list (--engine web,mobile). With both, the config gets a target for each, and the examples go in tests/web.e2e.ts and tests/mobile.e2e.ts, each test with requires so the other target skips it. Selecting no engine replaces the None option.

  • #1463 7372b0a Thanks @okwasniewski! - agent.assert and agent.waitFor take params, like agent.act. The judge reads {name} with its value, a unique() value included. A Secret reaches 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 6b41857 Thanks @kacperkapusciak! - e2e mcp sessions have a run_code tool. Pass it test statements as a test body writes them, such as await screen.getByLabel('Email').fill('ada@example.com'), and the session runs them on its screen and app with a...

Read more

@e2e-dev/web@0.15.4

Choose a tag to compare

@github-actions github-actions released this 30 Oct 16:28
cad17c3

Patch Changes

  • #1334 6c8e71f Thanks @21prnv! - locator.filter() takes hasNot, which drops matches whose subtree resolves a locator, as in Playwright. Third-party engines must handle the new hasNot field of a filter expression.

  • #1048 7f4475c Thanks @rudycelekli! - Add browser.waitForDownloads(trigger, { count }) to collect several files from one trigger. waitForDownload now also bounds completion and saving by its timeout.

  • #1037 a481fd3 Thanks @rudycelekli! - locator.filter() takes hasNotText, which drops matches whose text contains a string or matches a RegExp, as in Playwright. Third-party engines must handle the new hasNotText field of a filter expression.

  • #1044 555e226 Thanks @rudycelekli! - Add route.fetch() to read the upstream response inside a route handler before deciding it.

  • #1288 8ce2c65 Thanks @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 5879bfc Thanks @rudycelekli! - Add selective cookie clearing with validated name, domain and path filters, preserving other browser storage.

  • #958 85e92f9 Thanks @kuishou68! - upload and setInputFiles accept a button that opens a file chooser, such as one over a hidden file input. The agent's upload tool says so, so the model can pick the button it sees.

  • #1429 3a841bb Thanks @KrzysztofMoch! - A web() target takes app.permissions with '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 cdf910a Thanks @KrzysztofMoch! - Screenshots no longer fail with ENGINE_FAILURE ("closed-shadow root tracking is unavailable") on a page that replaces the global WeakMap, as some polyfills do. On such pages, locators find elements inside closed shadow roots again, and CDP reconnects no longer fail.