diff --git a/.agents/skills/e2e/SKILL.md b/.agents/skills/e2e/SKILL.md index c4f29d4a..6218d343 100644 --- a/.agents/skills/e2e/SKILL.md +++ b/.agents/skills/e2e/SKILL.md @@ -1,6 +1,17 @@ --- name: e2e description: Writes, runs, and debugs end-to-end tests for web and mobile apps with e2e, the agentic test runner, which mixes agent.act goals with exact locator assertions on a Playwright browser or an iOS or Android device. Also drives a project's running app live over the e2e MCP server to look at a screen, check a UI change, take a screenshot or record a video, and try a locator; and runs bug bashes, parallel e2e explore runs with each bug proven by a repro test. Use when a project depends on e2e or has an e2e.config.ts, when asked for end-to-end, browser, mobile, or agentic UI tests, to check a change in the running app, to QA or bug bash an app or branch, or when an e2e run fails. +metadata: + openclaw: + homepage: https://e2e.com + requires: + bins: + - node + - npx + envVars: + - name: AI_GATEWAY_API_KEY + required: false + description: Model key for agent steps when the project's e2e config uses the Vercel AI Gateway; other providers read their own key. --- # e2e: agentic end-to-end tests @@ -108,8 +119,10 @@ test('a member upgrades to Pro', async ({ app, agent, screen, browser }) => { Exact values go through `screen`: a sign-in form in a setup test, a field that must receive one specific string, a count that must be one number. 4. Run only the test you are working on: - `npx e2e run tests/.e2e.ts:`, the line its `test(` opens - on, with the flags in "Rerunning a test while you fix it" below. Agent + `npx e2e run tests/.e2e.ts:` (over MCP, + `run_tests {files: ["tests/.e2e.ts:"]}`, the flags as + camelCase fields such as `retries: 0`), the line its `test(` opens on, + with the flags in "Rerunning a test while you fix it" below. Agent steps need a model in the config and that provider's authentication (a saved subscription login, an API key); a local endpoint may need none. Tests without agent steps need no model. @@ -195,7 +208,8 @@ lines you changed: - In a project without e2e, set it up when the user requests it. Otherwise ask before adding a test framework, and name any existing framework. - Live MCP tools need the project's own `e2e mcp` server registered in the - client (topic `mcp`); writing and running tests use the CLI directly. + client (topic `mcp`). Tests run with the CLI, or with the server's + `run_tests`, the same run without a shell. Keep a session open across runs while you write or fix a web test; topic `mcp` says when a run can go beside it, and what to do on `APP_ALREADY_RUNNING`. diff --git a/.agents/skills/e2e/references/agent.md b/.agents/skills/e2e/references/agent.md index ef962308..21e3d6c3 100644 --- a/.agents/skills/e2e/references/agent.md +++ b/.agents/skills/e2e/references/agent.md @@ -49,14 +49,14 @@ under `executor`. `openai.decisionModel('gpt-6-luna')` from `@ai-sdk/openai` 4.0.90 or later works too and takes the `vision: true` screenshot. Tests stay plain language with no params. The text model writes field values and upload paths. See the shipped `docs/decision-models.mdx` or -[the online guide](https://e2e.tester.army/docs/decision-models) for setup, +[the online guide](https://e2e.com/docs/decision-models) for setup, gates, and limits. -A coding agent the user already signs in to runs agent steps over ACP: +A coding agent the user already signs in to runs agent steps over the Agent Client Protocol: install `@e2e-dev/acp` and its adapter, and put `claudeCode({ model: 'sonnet' })` or `codex()` under -`executor`; no model provider is needed. See the shipped `docs/acp.mdx` or -[the online guide](https://e2e.tester.army/docs/acp). +`executor`; no model provider is needed. See the shipped `docs/subscriptions.mdx` or +[the online guide](https://e2e.com/docs/subscriptions#use-your-coding-agent). - Pass a model instance, not a string (`INVALID_CONFIG`). - An agents entry is one plain object of `model`, `judge`, `system`, @@ -154,6 +154,9 @@ The tools, one per engine action. Name the target as the screen names it native file chooser; outside it or hidden (`.env`) is `POLICY_DENIED`. - `navigate`: a URL or app-relative path. - `back`: browser history or in-app back. +- `resize_viewport`: set the viewport size (200 to 4096 CSS px) to check a + layout at phone, tablet, or desktop width. Engines with `session.resize`, + such as web. - `type_secret`: a declared secret by name; plaintext never reaches the model. Offered only when the step declares secrets and the engine can fill them. - `screenshot`: attach viewport pixels; every later result then carries one. @@ -241,6 +244,10 @@ For a debug view that pairs each action with the screen it started on, give each capture to `onAction` by `index`, which restarts at 1 in each `act` call. It runs before replayed actions too, does not wait for the screen to settle, and a failed action gets a capture but no `onAction`. +Narrow `onAction`'s event on `action` for coordinates, replay included: +`point` for `tapAt`/`hoverAt`, `from`/`to` for `dragAt`. They are in the +same space as `screen.tapAt` and `boundingBox()`, rounded and clamped to the +viewport. Mobile engines have no `hoverAt` or `dragAt`. `vision` on a judgment picks the evidence: `false` (default) the tree; `true` the tree plus a masked screenshot; `'only'` the screenshot alone, for @@ -428,7 +435,7 @@ make no model calls. `executor`; the runner still owns observations, actions, budgets, and the report, and `system` or `tools` beside `executor` is `INVALID_CONFIG`. -Reference: https://e2e.tester.army/docs/agents +Reference: https://e2e.com/docs/agents ## In CI diff --git a/.agents/skills/e2e/references/debugging.md b/.agents/skills/e2e/references/debugging.md index dd845129..35b13b3f 100644 --- a/.agents/skills/e2e/references/debugging.md +++ b/.agents/skills/e2e/references/debugging.md @@ -29,7 +29,7 @@ default. timeout, changing values at a race; - what the app logged meanwhile (`✗ network error: POST /api/save 500`, `✗ uncaught error: ...`, `⚠ console warning: ...`, `ℹ console: ...`); - `❯ app 2 errors` in the terminal says there are some, and the page's + `❯ app 2 errors` in the terminal quotes the first 3 errors, and the page's `## App log` lists up to 50 with their step, errors and warnings first, counting the rest; - where the page went (`↪ navigated to /login`, a new tab the app diff --git a/.agents/skills/e2e/references/explore.md b/.agents/skills/e2e/references/explore.md index a3b3f5c6..72d48ea7 100644 --- a/.agents/skills/e2e/references/explore.md +++ b/.agents/skills/e2e/references/explore.md @@ -72,8 +72,8 @@ configured secrets are redacted (topic `writing-tests`). | `--target ` | first configured target | The one target to explore. | | `--agent ` | `default` | Build the explorer from another configured agent (`agents.`). | | `--session ` | none | Run the setup that saves this session, then explore with it restored. | -| `--max-steps ` | 8 (1 to 12) | Exploration steps at most. | -| `--timeout ` | 600000 (180000 to 900000) | Wall clock; the last minute is for the assessment. | +| `--max-steps ` | 8 (1 to 100) | Exploration steps at most. | +| `--timeout ` | 600000 (180000 to 7200000) | Wall clock; the last minute is for the assessment. | | `--headed`, `--reporter`, `--output`, `--debug`, `--ai-trace`, `--trace [mode]`, `--video [mode]` | as `run` | Same meaning as for `e2e run`. The exploration is one attempt, so a retry mode (`on-first-retry`, `on-all-retries`) records nothing (the run's notice says to pass `--trace on`); put the goal before a bare `--trace` or `--video`. | Per-step action and model-call budgets default to 40 each; diff --git a/.agents/skills/e2e/references/mcp.md b/.agents/skills/e2e/references/mcp.md index e898e4a3..c1bec0f2 100644 --- a/.agents/skills/e2e/references/mcp.md +++ b/.agents/skills/e2e/references/mcp.md @@ -3,7 +3,8 @@ `e2e mcp` serves a project's live app to a coding agent over MCP (stdio). The coding agent drives the app the way the testing agent does, writes a test as it walks the flow, and checks its locators and runs its lines before -writing them. Running a suite stays on the CLI (topics `running` and +writing them. `run_tests` runs a test file or the whole suite as +`npx e2e run` does and returns what it printed (topics `running` and `debugging`); to fix one failing test, a session can run it and stop on the screen where it failed. @@ -58,29 +59,30 @@ sets how many sessions may be open at once (default 4, 1 through 16). ## Tools -Four tools, all on the server registered as `e2e`; everything a session can +Five tools, all on the server registered as `e2e`; everything a session can do is a catalog behind `call`. Clients show them with the server name, such as `mcp__e2e__open_session` in Claude Code; when another MCP server offers a tool with the same name, use the `e2e` server's. | Tool | Does | | --- | --- | -| `open_session` | Loads the config (`config` names another file; default the nearest `e2e.config.ts`), starts the declared app command if any, boots the engine, opens the app (its URL, or launches a device's pinned app; it installs no build, so a local device needs `app.bundleId`), and returns the session id, the catalog, and the first observation. `target` is required when the config declares several. `headed: true` shows the browser or simulator when the user wants to watch; without it the session follows the server's `--headed`, headless by default. `test` runs one test first and leaves the session on the screen where it stopped (see Fixing a failing test). Each session has its own browser or device. | +| `open_session` | Loads the config (`config` names another file; default the nearest `e2e.config.ts`), starts the declared app command if any, boots the engine, opens the app (its URL, or launches a device's pinned app; it installs no build, so a local device needs `app.bundleId`), and returns the session id, the catalog, and the first observation. Its summary names the app URL, a port assigned for `:0`, and the app command's readiness URL and `env` names; e2e starts nothing else, so a database the app uses runs outside it. The config reads the MCP server's environment, not your shell's. `target` is required when the config declares several. `headed: true` shows the browser or simulator when the user wants to watch; without it the session follows the server's `--headed`, headless by default. `test` runs one test first and leaves the session on the screen where it stopped (see Fixing a failing test). Each session has its own browser or device. | | `tools` | The catalog: one line per tool with its argument names (`?` marks optional), the first sentence of its description, and `[read-only]` where it changes nothing. `tools {tool}` shows the full description and the JSON Schema of its arguments. | | `call` | Runs one catalog tool: `call {tool: "tap", args: {target: "n42"}}`. Arguments are checked against the tool's schema first; a wrong one fails with `INVALID_ARGUMENT` naming the field. | | `close_session` | Saves a recording still running, ends the attempt, disposes the engine, stops the app processes the session started once no other session uses them. | +| `run_tests` | Runs `e2e run` in its own process and returns its output: the command, the exit code, each test, the failure blocks, the summary. `files` takes `e2e run` positionals (`tests/checkout.e2e.ts:12`, a file, a directory, a glob); without it, every test runs. The other fields are `e2e run` flags in camelCase: `config`, `target`, `grep`, `grepInvert`, `tag`, `excludeTag`, `lastFailed`, `changedSince`, `headed`, `workers`, `retries`, `repeatEach`, `maxFailures`, `actionTimeout`, `noCache`, `updateSnapshots` (while fixing a test: `retries: 0, actionTimeout: 5000`). Needs no session. One run at a time (`RUNNER_BUSY`); cancelling the call interrupts the run. Exit 1 (a test failed) is a normal result; exit 2 and above is an error result. Output past 60,000 characters keeps its end; `.e2e/report.json` has every result. | The catalog, per session: | Catalog tool | Does | | --- | --- | | `observe` | A fresh observation: one node per line as `#id role "name" ...`, plus the current path. On the web engine a link's `href` is its path on the app URL's origin, else origin and path (`mailto:` and `tel:` keep their scheme, `blob:` its inner origin and path); `?…` and `#…` mark a dropped query or fragment, `data:…` and `javascript:…` an inline payload, a trailing `…` a target cut at 256 characters. | -| `tap`, `double_tap`, `long_press`, `right_click`, `hover`, `type`, `press`, `select`, `check`, `scroll`, `scroll_to`, `drag`, `upload`, `navigate`, `back`, `dismiss_keyboard` | The grammar verbs, as the testing agent gets them: `check` takes `checked`, `drag` a `to` node, `upload` project-relative `files`; `dismiss_keyboard` comes with device engines. On an engine that declares `tapModifiers`, `tap`, `double_tap`, and `right_click` take an optional `modifiers` list (`Shift`, `Control`, `Alt`, `Meta`, `ControlOrMeta`) to hold keys for the click. Each reports what changed on screen and, after its lead, the test line that repeats it (`Test line: await screen.getByRole("button", "Save").tap();`) or `No test line:` and why; `observe` shows the whole screen. A verb the engine cannot honor is not listed and fails with `UNSUPPORTED_CAPABILITY`. | +| `tap`, `double_tap`, `long_press`, `right_click`, `hover`, `type`, `press`, `select`, `check`, `scroll`, `scroll_to`, `drag`, `upload`, `navigate`, `back`, `resize_viewport`, `dismiss_keyboard` | The grammar verbs, as the testing agent gets them: `check` takes `checked`, `drag` a `to` node, `upload` project-relative `files`; `dismiss_keyboard` comes with device engines. On an engine that declares `tapModifiers`, `tap`, `double_tap`, and `right_click` take an optional `modifiers` list (`Shift`, `Control`, `Alt`, `Meta`, `ControlOrMeta`) to hold keys for the click. Each reports what changed on screen and, after its lead, the test line that repeats it (`Test line: await screen.getByRole("button", "Save").tap();`) or `No test line:` and why; `observe` shows the whole screen. A verb the engine cannot honor is not listed and fails with `UNSUPPORTED_CAPABILITY`. | | `type_secret` | Fills a configured secret by name: a credential's password into a password field, a `secrets` entry into any editable input; the plaintext never reaches the agent, and its test line names the credential or secret (`fill(credentials.user(name).password)`, `fill(secrets.get(name))`). Listed when the config declares `credentials` or `secrets` and the engine can fill secrets. | | `locate` | Tries a semantic locator with exactly one of `role`, `text`, `label`, `placeholder`, `testId` (`name` only with `role`; `exact` optional; anything else is `INVALID_ARGUMENT`) and returns how many nodes match, which, and the `screen.*` call to write. | | `run_code` | Runs test statements (`code`, as a test body writes them) on the session's `screen` and `app` with a test's waits, exactly-one rule, and matchers. Stops at the first failure and returns each statement's pass, failure (code and message), or read value, then what changed on screen. Each statement waits at most `timeout` ms (default 5000), but `timeout` doesn't stop a regex mid-match: avoid nested quantifiers such as `(\w+\s?)*`. The code is parsed, never evaluated as JavaScript: statements start with `screen`, `app`, or `expect(locator)`; arguments are literals, regexes, arrays, objects, locators, and `credentials.user(name).username`. A secret (`credentials.user(name).password`, `secrets.get(name)`) goes only into `fill`, under `type_secret`'s checks. Engine fixtures (`browser`, `device`), `app.screenshot`, and `toHaveScreenshot` are left out. Anything else is `INVALID_ARGUMENT` quoting the refused code with its line and column, and nothing runs. Reads and matchers see `` where a secret value is. When the config declares a secret or credential, a locator found by part of a text (a regex, an `exact` other than `true`, `hasText`) is `POLICY_DENIED` before anything runs: find it by its exact text. A matcher that expects `` is `INVALID_ARGUMENT`. The statements that pass, except reads, join `test_lines` as written. | | `test_lines` | Every test line the session's actions printed and every statement `run_code` passed, in order, as a draft test body, starting with `await app.open();` for the session's own opening (after `open_session {test}`, the lines that continue that test, with no opening); an action without a line shows as a `//` comment. A line's locator matched the target alone on the live screen before the action (role and name first, test id last, narrowed to `{ visible: true }`, a container, or `.nth(i)` with a comment when twins share it); a fill names `credentials.user(name)` or `secrets.get(name)`, never a value; a navigation on the app's origin is written as its path. | -| `screenshot` | The masked pixels as an image. | +| `screenshot` | The masked pixels as an image. With `path` (a `.png` inside the project, relative to its root, not hidden or under a hidden directory), also saves a full-resolution masked capture there and returns its absolute path. | | `tap_at` | Taps a point (`x`, `y` in the latest screenshot's pixels) where you aim. An engine without a bare-point tap taps the listed control under it by id instead, and fails on a point on nothing listed. Listed when the engine declares `tap` or a bare-point tap. | | `hover_at` | Hovers a point the same way: the bare point, otherwise a listed control under it by id. Listed when the engine declares `hover` or a bare-point hover. | | `drag_at` | Drags from one point (`x`, `y`) to another (`to_x`, `to_y`) where you aim. An engine without a bare-point drag drags by id instead when the points land on two different listed controls, and fails otherwise. Listed when the engine declares `dragTo` or a bare-point drag. | @@ -178,9 +180,10 @@ Resources: `e2e://guide` and `e2e://guide/` hold this skill. call run_code {code: "await expect(screen.getByRole('listitem')).toHaveCount(1);"} passed edit + that line ``` -4. Run only that test from the shell: - `npx e2e run tests/.e2e.ts:` (SKILL.md, "Rerunning a test - while you fix it"). On a failure, fix from the terminal's failure block +4. Run only that test: + `run_tests {files: ["tests/.e2e.ts:"]}`, or + `npx e2e run tests/.e2e.ts:` from the shell (SKILL.md, + "Rerunning a test while you fix it"). On a failure, fix from the run's failure block and the trace page (topic `debugging`), then rerun it the same way. To see a screen the evidence leaves out, go straight to it instead of walking the flow again from the start: `open_session {test}` stops on the failure screen (Fixing a failing @@ -196,8 +199,8 @@ Resources: `e2e://guide` and `e2e://guide/` hold this skill. `close_session` once the test passes; an idle session closes on its own after 30 minutes and never outlives 4 hours. When the client exits, every session closes and the app commands stop. To look at another project or - config, `open_session {config: "path/to/e2e.config.ts"}`; no restart - needed. + config, `open_session {config: "path/to/e2e.config.ts"}` (absolute, or + relative to the server's working directory); no restart needed. ## Fixing a failing test @@ -225,7 +228,7 @@ session runs the test and stops where it failed: loads the config and the test files fresh, so it runs the edited test from the start and stops on the next failure, or on the final screen. 5. `close_session`, then confirm once with - `npx e2e run tests/.e2e.ts:`. + `run_tests {files: ["tests/.e2e.ts:"]}`. - `afterEach` hooks and fixture teardown wait for `close_session`; a failure there shows as a `Cleanup (afterEach)` line in its result. @@ -237,7 +240,7 @@ session runs the test and stops where it failed: as `file:line`; none fails with `NO_TESTS`. - `SESSION_TEST_UNSUPPORTED`: a test in a serial group, a test that starts from a setup test's `session`, and a test that runs as several agents - can't run alone in a session. Fix those with `npx e2e run`. + can't run alone in a session. Fix those with `run_tests`. ## Rules @@ -251,7 +254,7 @@ session runs the test and stops where it failed: - Nothing a session does is recorded as a test, and only a test it runs (`open_session {test}`) reads or writes the replay cache. A session is for looking and trying; the test is the file you write as you walk. -- On the web, a session can stay open while `e2e run` runs, unless the two +- On the web, a session can stay open while `run_tests` or `e2e run` runs, unless the two collide over the app. Read the target's `app`: - No `command` (the app runs elsewhere): both use that app. - A `url` on port `0`: the session and each run start their own copy of @@ -294,4 +297,5 @@ session runs the test and stops where it failed: comes from a package every session shares; create it in the config or a file it imports by path. `UNKNOWN_TOOL`: the name is not in this session's catalog; the message lists what is. `TEST_AMBIGUOUS` and - `SESSION_TEST_UNSUPPORTED`: see Fixing a failing test. + `SESSION_TEST_UNSUPPORTED`: see Fixing a failing test. `RUNNER_BUSY`: + `run_tests` is already running a suite; wait for its result. diff --git a/.agents/skills/e2e/references/running.md b/.agents/skills/e2e/references/running.md index 5ac3d6f4..b7933b78 100644 --- a/.agents/skills/e2e/references/running.md +++ b/.agents/skills/e2e/references/running.md @@ -14,6 +14,8 @@ npx e2e run [files...] [options] # run tests npx e2e explore [goal] [options] # explore toward a goal without a test file (topic explore) npx e2e list [files...] [options] # print what run would select +npx e2e doctor [--check-model] # can a run start: config, engine setup, models; + # --reporter json for a host, exit 2 on a failed check npx e2e init [directory] [--yes] # scaffold a project, refresh the agent skill npx e2e guide [topic] # print this skill; topics: setup, writing-tests, agent, # running, explore, debugging, mcp, bug-bash @@ -139,11 +141,15 @@ leaves the last run's files, and a `--last-failed` rerun keeps the files the report it reruns names and writes its own under each test's `rerun-/`. The report records every artifact path, a hosted service's video by URL. -- `list` (default): setup steps, one line per file and target, a `Failed +- `list` (default): setup steps, one line per file and target (when stdout + is not a terminal, each test also prints as it finishes), a `Failed Tests` section (error, code, failing line, code frame), then the summary rows `Test Files`, `Tests`, `AI`, `Cache` (when the replay cache ran), `Repeats` (with `--repeat-each`), `Errors`, `Start at`, `Duration`, - `Traces` (when a page was written), `AI trace` (with `--ai-trace`). Past a minute `Duration` + `Traces` (when a page was written), `Screenshots` (the first 10 + `app.screenshot` files, then a count), `AI trace` (with `--ai-trace`), and + last `Failed`, one entry per failed test (file and line, error's first + line, trace page when written), so `| tail` keeps it. Past a minute `Duration` repeats as minutes and seconds, setup time split out as `startup` in the same parenthetical (`682.97s (11m 23s, startup 43.00s)`). - `report.json`, for scripts rather than reading (`jq`, CI tools; a reader @@ -279,4 +285,4 @@ jobs: with `npx e2e list --changed-since origin/main`, after committing: the decision filter reads what the commits change, and a file only the working tree changes by name alone. - Reference: https://e2e.tester.army/docs/filters + Reference: https://e2e.com/docs/filters diff --git a/.agents/skills/e2e/references/setup.md b/.agents/skills/e2e/references/setup.md index 1c9d977b..1d2c4f5f 100644 --- a/.agents/skills/e2e/references/setup.md +++ b/.agents/skills/e2e/references/setup.md @@ -311,7 +311,7 @@ For an app started elsewhere, point `app.url` at it, literally or via phones through [agent-device](https://github.com/callstack/agent-device); needs Xcode with a simulator runtime or the Android SDK with an emulator (a phone needs Xcode with Developer Mode and runner signing, or adb with USB -debugging authorized); run `npx agent-device doctor` once. Name a phone in `device` by the name +debugging authorized); run `npx e2e doctor` to check it. Name a phone in `device` by the name `npx agent-device devices` lists, not its UDID or serial. On an iPhone, device settings (permissions, `clearState`, network, location, appearance, biometrics, keychain) and the clipboard are simulator-only. @@ -359,9 +359,9 @@ export default { it: for parallel MCP sessions or bug-bash explorers, declare one target per device, each naming its `device`. - `device` can be a `DeviceProvider` leasing hosted devices, one per worker - slot: `easSimulators({ buildId })` from `@e2e-dev/eas` takes the project + slot: `expoSimulators({ buildId })` from `@e2e-dev/eas` takes the project from the app config's `extra.eas.projectId` (`projectId` overrides), reads - `EXPO_TOKEN`, else the `eas login` session, needs no Xcode or Android SDK, and with `buildId` EAS installs + `EXPO_TOKEN`, else the `eas login` session, needs no Xcode or Android SDK, and with `buildId` Expo installs the app (omit `app.appPath`). A run must fit one session: `maxDurationMinutes`, absent, is the account's cap (40 on a standard plan). `videoTouches: false` on the engine for video there. diff --git a/.agents/skills/e2e/references/writing-tests.md b/.agents/skills/e2e/references/writing-tests.md index 220efcfd..e968ac7c 100644 --- a/.agents/skills/e2e/references/writing-tests.md +++ b/.agents/skills/e2e/references/writing-tests.md @@ -72,12 +72,17 @@ test.skip('later', async () => {}); test.only('focus', async () => {}); // local only: CI fails with ONLY_IN_CI test('conditional', async () => { test.skip(await onlyOneOrg(), 'nothing to switch to'); }); // throws: the body stops here, reported skipped; call it before the first step test('later', async () => { test.skip('waiting on the API'); }); // bare skip from the body +test.fail('known gap', async () => {}); // expected to fail: a test failure passes it, a pass fails it with UNEXPECTED_PASS +test('gap on web', async ({ platform }) => { test.fail(platform === 'web', 'known gap'); }); // marks, does not throw; the body runs on test.setup('sign in', { sessions: ['admin'] }, async ({ app, screen, session }) => {}); // see Sign-in sessions const wsTest = test.extend<{ ws: Ws }>({ ws: async ({ browser }, use) => { await use(await seed()); await drop(); } }); wsTest('uses the workspace', async ({ ws }) => {}); // code after use() is teardown, runs after failures too ``` -A setup test cannot skip from its body (`INVALID_ARGUMENT`). +A setup test cannot skip from its body (`INVALID_ARGUMENT`), and neither a +setup test nor a serial member can call `test.fail`. `test.fail` covers test +failures and timeouts only: an infrastructure error such as `ENGINE_FAILURE` +or a blocked agent verdict still fails the test. | Option | Default | Notes | | --- | --- | --- | @@ -85,6 +90,7 @@ A setup test cannot skip from its body (`INVALID_ARGUMENT`). | `retries` | `config.retries` | 0 to 10; a serial group's value applies to its members. | | `tags` | `[]` | Distinct, non-blank, no comma or edge whitespace (`'Login Form'` is fine); union across layers. `--tag smoke` selects, `--tag-mode all` requires every tag. | | `skip` | unset | `true` or a reason string. | +| `fail` | unset | `true` or a reason string: expected to fail, as `test.fail`. Tests only, not groups or setup tests. | | `platforms` | unset | Only targets with these platforms, e.g. `['ios']`. | | `requires` | `[]` | Engine capabilities, e.g. `['browser']`; missing ones skip the test at selection rather than failing it with `UNSUPPORTED_CAPABILITY`. | | `session` | unset | Restore state saved by a setup test. | @@ -94,7 +100,7 @@ A setup test cannot skip from its body (`INVALID_ARGUMENT`). | `serial` | `false` | Groups only. Members share app state, run in order on one worker, retry as a whole, and take the group's `trace` and `video`. | Serial members cannot set `retries`, `trace`, `video`, `session`, -`platforms`, `requires`, `skip`, or `only`, nor can a nested `describe` set +`platforms`, `requires`, `skip`, `fail`, or `only`, nor can a nested `describe` set `trace` or `video`; nesting serial groups is a `COLLECTION_ERROR`. Hooks nest: outer `beforeEach` first, inner `afterEach` first. `beforeAll` @@ -118,7 +124,8 @@ label. `browser` (`Browser`): browser targets, import `test` from `@e2e-dev/web` ### app - `baseUrl` (`string | undefined`): the target's app URL with the run's - port; `undefined` when the target declares no `app.url`. + port and no trailing slash (`${app.baseUrl}/api/users`); `undefined` when + the target declares no `app.url`. `string` with `test` from `@e2e-dev/web`. - `open(path?)`: opens the target's `app.url`, a relative path, or an absolute http(s) URL. On a device it takes no path and relaunches the pinned app. - `back()`: one history step back. @@ -127,7 +134,8 @@ label. `browser` (`Browser`): browser targets, import `test` from `@e2e-dev/web` - `clearState()`: clears cookies and storage, recreates the context, reopens the base URL. - `screenshot(label?)`: saves a redacted screenshot artifact and returns its - absolute path. It masks secure fields only (see Sign-in sessions). + absolute path; the `list` summary names the first 10 under `Screenshots`. It masks + secure fields only (see Sign-in sessions). - `startRecording({ name? })`, then `stopRecording()`: records one span and returns its videos (`path` or hosted `url`). Fails while the test's `video` records: set `{ video: 'off' }` on the test. @@ -148,7 +156,7 @@ assertion. Every query also exists on a locator, scoped to its subtree. | `getByPlaceholder(text, { exact?, visible? })` | Inputs by placeholder. | | `getByText(text, { exact?, visible? })` | Visible text. | | `getByDisplayValue(value, { exact?, visible? })` | Inputs by current value; on the web it cannot scope child queries or be a `filter({ has })` or `filter({ hasNot })` target. | -| `getByTestId(id, { visible? })` | `data-testid` on the web (or `web({ testIdAttribute })`), accessibility identifier or resource id on a device (React Native `testID`, SwiftUI `.accessibilityIdentifier`, Compose `testTag` with `testTagsAsResourceId` on Android, Flutter `Semantics(identifier:)`, .NET MAUI `AutomationId`); a string matches the whole id, a RegExp tests it; on Android the `:id/` prefix may be left off. Last resort. | +| `getByTestId(id, { visible? })` | `data-testid` on the web (or `web({ testIdAttribute })`), accessibility identifier or resource id on a device (React Native `testID`, SwiftUI `.accessibilityIdentifier`, Compose `testTag` with `testTagsAsResourceId` on Android, Flutter `Semantics(identifier:)`, .NET MAUI `AutomationId`, NativeScript `testID`); a string matches the whole id, a RegExp tests it; on Android the `:id/` prefix may be left off. Last resort. | Roles: `button`, `link`, `textbox`, `searchbox`, `combobox`, `listbox`, `option`, `checkbox`, `radio`, `radiogroup`, `switch`, `slider`, `spinbutton`, @@ -211,7 +219,7 @@ Each action resolves one node, waits up to `config.actionTimeout` (30 s, or `press(key)`, `check()`, `uncheck()`, `selectOption(label | { label } | { value } | { index })` (one option; an array is `INVALID_ARGUMENT`), `focus()`, `hover()`, `setInputFiles(paths)` -(relative to the project root), `dragTo(locator)`, `scrollIntoView()`, +(relative to the project root; `[]` clears), `dragTo(locator)`, `scrollIntoView()`, `swipe({ direction, momentum? })`. Web only, `UNSUPPORTED_CAPABILITY` on a device: `secondaryTap`, `selectOption`, `setInputFiles`, `scrollIntoView`, and `modifiers`. @@ -222,7 +230,7 @@ field and types one character per `delay`, plain string only (a `Secret` is `INVALID_ARGUMENT` and goes through `fill`). Coordinates are CSS pixels, for what the tree does not list: `tap({ position: -{ x, y } })` offsets from the node's top-left corner (with `modifiers` it is +{ x, y } })` offsets from the node's top-left corner inside its border (with `modifiers` it is `INVALID_ARGUMENT`), `screen.tapAt({ x, y })` taps a viewport point, `screen.swipe({ from, to, duration? })` swipes along a path, `screen.swipe({ direction, momentum? })` swipes the viewport. Prefer a @@ -237,9 +245,9 @@ the action timeout, then read once with no retry for a value. `isVisible()`, `nth(i)` locator per current match and `allTextContents()` every match's text, both `[]` at zero. Text is the rendered text, whitespace collapsed: on the web what `innerText` reads (`text-transform` applies, `display: none` -drops out, `
` is a space); `toHaveText` reads the same. `isChecked()` is -`false`, not an error, on a node with no checked state, so query checkable -controls by role. `waitFor({ state?: 'attached' | 'detached' | 'visible' | 'hidden', timeout? })` waits +drops out, `
` is a space); `toHaveText` reads the same. `isChecked()` on a +node that cannot be checked (a button), and `inputValue()` on one that holds +no value (a heading), throw `ACTION_FAILED`. `waitFor({ state?: 'attached' | 'detached' | 'visible' | 'hidden', timeout? })` waits within `actionTimeout`, else `LOCATOR_NOT_FOUND`. For a value that has to settle use `expect`, not a read. Reading a password field's value or attributes is `POLICY_DENIED`, as is `toHaveAttribute` on one, negated too. @@ -423,7 +431,7 @@ const projectTest = test.extend<{ project: { id: string } }>({ project: async ({ app, browser }, use) => { const cookie = (await browser.cookies()).map((c) => `${c.name}=${c.value}`).join('; '); const api = (path: string, init: RequestInit = {}) => - fetch(new URL(path, app.baseUrl), { ...init, headers: { cookie, 'content-type': 'application/json' } }); + fetch(`${app.baseUrl}${path}`, { ...init, headers: { cookie, 'content-type': 'application/json' } }); const created = await api('/api/projects', { method: 'POST', body: JSON.stringify({ name: `Project ${Date.now()}` }) }); const project = expect(await created.json()).toMatchSchema(z.object({ id: z.string() })); await use(project); @@ -483,17 +491,20 @@ the app opens itself (`target="_blank"`, `window.open`) is not followed: - `route(pattern, handler)`, `unroute(pattern)`: intercept requests, newest route first; `route.request` has `url`, `method`, `headers`, `postData`. `route.fetch()` reads upstream without deciding the route and returns - `{ url, status, headers, text(), json() }`; redirects are not followed. + `{ url, status, headers, body(), text(), json() }`; redirects are not followed. + Hand binary bodies on with `body()`, never `text()`. The handler calls exactly one of - `fulfill({ status?, headers?, contentType?, json | body | path })`, + `fulfill({ status?, headers?, contentType?, json | body | path })` (`body` + a string or bytes; several cookies as one `\n`-joined `set-cookie`), `continue({ url?, method?, headers?, postData? })` (straight to the - network), `fallback()` (the route registered before it), or `abort()`; + network; a header set to `undefined` is dropped, configured site headers + still added), `fallback()` (the route registered before it), or `abort()`; none or two fails the next step with `ACTION_FAILED`, an unsupported option with `INVALID_ARGUMENT`. - `unrouteAll()` removes every route; configured site headers stay. - `waitForResponse(pattern, { timeout? })`: resolves once the headers - arrive, with `{ url, status, headers, json(), text() }`; `text()` and - `json()` wait for the body (up to the action timeout) and reject with + arrive, with `{ url, status, headers, body(), json(), text() }`; the body + readers wait for the body (up to the action timeout) and reject with `ACTION_FAILED` when it could not be read. Start the wait before the request, including the first `browser.goto` or `app.open`. - `cookies()`, `setCookies([...])`: a target is an http(s) URL or a domain. @@ -532,7 +543,7 @@ A `route`, `unroute`, or `waitForResponse` pattern is a glob string or `browser.locator('.btn-primary')`. - Test data gets a run-unique name (`Invoice ${Date.now()}`) and `afterEach` cleanup, so replays and retries never trip over leftovers. -- APIs live in the same suite: `fetch(new URL('/api/users', app.baseUrl))` +- APIs live in the same suite: ``fetch(`${app.baseUrl}/api/users`)`` plus value matchers, in a `test.extend` fixture that reads `browser.cookies()` when the API needs the session. - No sleeps, fixed delays, or polling loops. Wait for the state, not a diff --git a/nub.lock b/nub.lock index e2e3998b..8823eb75 100644 --- a/nub.lock +++ b/nub.lock @@ -51,14 +51,14 @@ importers: specifier: ^5.20261022.1 version: 5.20261106.1 '@e2e-dev/decision': - specifier: 0.3.1 - version: 0.3.1(ai@7.0.160(zod@4.6.7))(e2e@0.22.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7))) + specifier: 0.3.2 + version: 0.3.2(ai@7.0.160(zod@4.6.7))(e2e@0.23.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7))) '@e2e-dev/github': specifier: 0.4.4 - version: 0.4.4(e2e@0.22.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7))) + version: 0.4.4(e2e@0.23.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7))) '@e2e-dev/web': - specifier: 0.15.4 - version: 0.15.4(e2e@0.22.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7))) + specifier: 0.15.5 + version: 0.15.5(e2e@0.23.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7))) '@mpsuesser/oxlint-plugin-effect': specifier: 0.6.0 version: 0.6.0 @@ -78,8 +78,8 @@ importers: specifier: 7.0.160 version: 7.0.160(zod@4.6.7) e2e: - specifier: 0.22.0 - version: 0.22.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)) + specifier: 0.23.0 + version: 0.23.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)) jpeg-js: specifier: 0.4.4 version: 0.4.4 @@ -427,14 +427,14 @@ packages: resolution: {integrity: sha512-C6ylMuAXjgqKJllp6ODIJwUltK/tm3ZmIj4V2fqENP3Y8gif2DyeJSsTcDwFrXppgEKcrBisi/BWx2tYeoeCAw==} engines: {node: '>=22'} - '@ai-sdk/provider@4.0.34': - resolution: {integrity: sha512-Ip7ZQBq/FiGpM1mmOVseTtX9PBjnzo0bLC41WTgBSBBRUBz6LhNFGbYaNUzI6hPm6ll1oNSPOAZc/q/z+3QZEQ==} - engines: {node: '>=22'} - '@ai-sdk/provider@4.0.35': resolution: {integrity: sha512-yBz6fmLS8MSCIzy7NiHEUAq56ZLD4ZA1GR6bpXBxgbwUacP1La7LuwAr/xy9jSzthem4F8Xu2OrhvU/JrE9fYA==} engines: {node: '>=22'} + '@ai-sdk/provider@4.0.36': + resolution: {integrity: sha512-GqvWZSZdBelCGughlBdOoupT258rgM3YMbaLAS9WSZJ0vlt8c9vm3My+ZT31mYhiReMCMCF2qF2axnGbILpk1A==} + engines: {node: '>=22'} + '@ai-sdk/typesafe-ai@3.0.26': resolution: {integrity: sha512-l8iSYnlro5Bp7OBFBGUIHhjH6Zt6Oi3iw+thlEk2C2iTHUXH/BNr+UmTtM7OKN5TNJFUeiAiNRPF56xaBFjbnw==} engines: {node: '>=22'} @@ -799,8 +799,8 @@ packages: '@drizzle-team/brocli@0.12.1': resolution: {integrity: sha512-yHwomvolVafvUXhy5TdiJVkuNCxXn+bKOs2aWiWEQh/5YaV97Oa/abJz3dmx7lxgIUsUlS1Jl4mEfvJPo3YsVw==} - '@e2e-dev/decision@0.3.1': - resolution: {integrity: sha512-PkgBc2EYxL922zx4EiSkGsFz9Lb4b6xnqXcVgihlpq+HvVChzVAvCTkEo3lgXwQNcsSxKQjTn+/NUPg0M4/zTQ==} + '@e2e-dev/decision@0.3.2': + resolution: {integrity: sha512-HTdsaL/ICAnceRchPngmsqbTP52U8Yll9pM6CQcyBcJr99DP//xqggph2sJ4XUBKqD0YJUQ8mlNul41dmBPp6g==} engines: {node: ^22.22.3 || >=24.8.0} peerDependencies: ai: ^7.0.134 @@ -812,12 +812,12 @@ packages: peerDependencies: e2e: '>=0.15.0 <1' - '@e2e-dev/web@0.15.4': - resolution: {integrity: sha512-j4bDSP6wV310h9LwrMVfsUHv7uAIIzK516NboLco6Ah92B32uShIHne5V3AI1lvKtLip+PWlpJ+aw848vogBwQ==} + '@e2e-dev/web@0.15.5': + resolution: {integrity: sha512-fUXrSgfii6w/q7OyX9/kEIDLpIMHpEkTH81hrR8WLnqk8li3bRyXJQBGWqtq9NoWpS2UANnhMI45n6Fv1ErCnw==} engines: {node: ^22.22.3 || >=24.8.0} hasBin: true peerDependencies: - e2e: '>=0.18.0 <1' + e2e: '>=0.22.1 <1' '@effect/platform-node-shared@4.1.2': resolution: {integrity: sha512-wSwl9A/G1hcVvF8nLI+YfB3EyOIDvWS6+lsTZBkmgDnPBL7m8YWZF+1HD+mdEsb52SUGfukip46Q3gRwSdk3QA==} @@ -1526,259 +1526,259 @@ packages: resolution: {integrity: sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==} engines: {node: '>=20.0'} - '@oxc-parser/binding-android-arm-eabi@0.155.0': - resolution: {integrity: sha512-A6xv7hDtnTm+xlZ7utn6rRQpRMJHRhVr3gjRGqlx0RUX84mNk0pAsy6YN/wWhuOTkaZhRrrzaLxf0NfbH77j2w==} + '@oxc-parser/binding-android-arm-eabi@0.157.0': + resolution: {integrity: sha512-zFtSEal1K/17LATxVs0VcT/Itt+fxUQ9Ni8HtG+pPcEqy/TenRO74XffkY2dBiy3Pd+w0FuebwCZ6PJx1z7scQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxc-parser/binding-android-arm64@0.155.0': - resolution: {integrity: sha512-T1wWwH9/JI5g7Z4kEQwDOwhToxdDhRyOTklH+uuNpJ16m3MZFmGl+l2rKc0NHQdbVRG2LTOBsNjpW3h1BWytPA==} + '@oxc-parser/binding-android-arm64@0.157.0': + resolution: {integrity: sha512-WSlkFUnjamuv+2+TXW5F1rp2I24KVEXj4S+H7J7Y8T/KLR2xXbHj8lgxbZZtjSKi3Z/aGGrlFEOy7EmCWpIUlg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxc-parser/binding-darwin-arm64@0.155.0': - resolution: {integrity: sha512-ZoRB3qJxJ8DWA41jHja+YeB0lLfjBy4T+Kr15vnN1k65X3zbJt3rPZftEwN4Ju4tmA4K/T9dWWD7Z8ewQLnrVA==} + '@oxc-parser/binding-darwin-arm64@0.157.0': + resolution: {integrity: sha512-Usk8UoURmtG2qBLwrO+il+kf6CahEJJriRQACuAwF2CqcWqGsvl9xj9JIMDxP9VTinOt/BZUuDZxcpn68QKsAA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxc-parser/binding-darwin-x64@0.155.0': - resolution: {integrity: sha512-vxtL86BtM+IgrpejA86nbTk5j0HKTIMeuaJ1fQciw6p9RfavPtIPjI7gN34owap0yG9txXBaAWpGdxokNwdqIw==} + '@oxc-parser/binding-darwin-x64@0.157.0': + resolution: {integrity: sha512-yOvjPixSD2sYJxtQXOzprXdV1xbr2RZyEnbkwFnnxz332Q4+gwkQgCGXZkFlQpc95Fk4XFITACfbFzze4XXktA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxc-parser/binding-freebsd-x64@0.155.0': - resolution: {integrity: sha512-tN6Ru5e0UVnWaIuiH8jEwnvxuxg7FvhWwSd3oe5oDhOD4ObsSr9/N6WfHLjilUWlPPj65ptwrSDH0Y7lzwTzmw==} + '@oxc-parser/binding-freebsd-x64@0.157.0': + resolution: {integrity: sha512-BLTsP8TWvmV53jgGBynwv2DR3hKtjpdpL6fXnQs2Fg5P6HsFTShFjrgQrHMSM1cA4lGmlcj7tdTx96RoJfYuuA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxc-parser/binding-linux-arm-gnueabihf@0.155.0': - resolution: {integrity: sha512-h4ozA5n6L6lwolsz9iwunEhKWnIVbmFRots5QxEix0H6nJ5ICpuDa7PuShuhfpIDFe3+Qvyscioyiv+9g+4Syg==} + '@oxc-parser/binding-linux-arm-gnueabihf@0.157.0': + resolution: {integrity: sha512-wGMDInIrhayQpNxwpXIWqa2QiKk+/6RxOi4GxPVoqmwrCdn2xj3xXyDUm3RujxQaraZjeWfh0+h9nedoivnL1w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-parser/binding-linux-arm-musleabihf@0.155.0': - resolution: {integrity: sha512-058/+LardpfuUlsKIvBGk/CYoakEVcMgqYx8GgyUZeOxFWTojYLlCc1Gb60/y21v3esDhHidgiY/Zbq9LpBhaQ==} + '@oxc-parser/binding-linux-arm-musleabihf@0.157.0': + resolution: {integrity: sha512-N6OLfOnku4otlU6eF+HLU+1fH2XAaItc+c7dE+S09SzRZHvkaltU9aGTlMhmAIee95hOqkOCVFHNzQYJ1KS+gQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-parser/binding-linux-arm64-gnu@0.155.0': - resolution: {integrity: sha512-nrOt2Y3xIAzu+lSPzH0864ieO+iCCXgoo9qFlGANE8Xh0cQ+RP8Wstfp+/wXN2YCyb98cAGzX0VruKYw7it/jw==} + '@oxc-parser/binding-linux-arm64-gnu@0.157.0': + resolution: {integrity: sha512-YfY+qZ8d9tHJEvIq+zXyCcSve/jWgTNDiDtr1W4WVMh5+4fsOjYtH2JDIXIXUkILZzPKgJYbQ08Y/mwhr1gQLQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-arm64-musl@0.155.0': - resolution: {integrity: sha512-KYAayyN5hQbJPtGKtRxlyc8XYmyntOplyXSQzTDrmbz7l/GCrzQbSswvyJFBTH1LGtsZrbXOAfN52i/Kz6kLKg==} + '@oxc-parser/binding-linux-arm64-musl@0.157.0': + resolution: {integrity: sha512-ytZeO8BKkezwkLoWH3hK0R9Jd+S1BQhcQaWiSAWhXE7Dncq1XiJKb4w5hCe4lwl2ytgoSBgB0XEABhwD2/IhJg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxc-parser/binding-linux-ppc64-gnu@0.155.0': - resolution: {integrity: sha512-CSuSY5hfjtsBnHXydOj8jiNfS1qHbdPZuPz1YL1cSgK7VmNYP+QlZIbG0BBYYBgX/vYEgZwbG9mBdW4YairZ5w==} + '@oxc-parser/binding-linux-ppc64-gnu@0.157.0': + resolution: {integrity: sha512-54w3SexApRhsw3DOAXBZ85rEMR2y29NDOUr18t69fcsnemS/N1YU+zQddHCol/HDhBPyLHg5fpxChRCSzxHwqw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-riscv64-gnu@0.155.0': - resolution: {integrity: sha512-7KCfOQm+Nz2N8trAXbQkal4TQ5756WVEmhm35y816YHvyFnEfVsICsiV5k0pEszNf/fRm4cm2i6i18SJ6/iCWg==} + '@oxc-parser/binding-linux-riscv64-gnu@0.157.0': + resolution: {integrity: sha512-byg0y1OHdjjhll0qWJQyowKdCxM/zCKysIIOqkWgCid/cR+RU5nTz/63OeAZvIb1z/VB1CyypDRdLn2Ov3r+HQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-riscv64-musl@0.155.0': - resolution: {integrity: sha512-JSlhgoK+/g1TGJI5NuADx2+6syhxnQNLCWLXyO5QLFyetomcr/vIxSdiNlmyAv963YXUzCuwAwRG6npZ5xyJ1A==} + '@oxc-parser/binding-linux-riscv64-musl@0.157.0': + resolution: {integrity: sha512-CiQrt8esQTeL17kscbsfpdx5cywItx3y95YejsihET68oYnxHjbEgj8JaqlIWmhpL2h98piqPBLhWmZbp67nQQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxc-parser/binding-linux-s390x-gnu@0.155.0': - resolution: {integrity: sha512-WFIX+dPokWp64mi434Md3U3lJaTwNxAphvGjpltoyQjGUsdXavOIRrnp9dOS34Hd75HOAwDxAI+YwWOwqmJbtg==} + '@oxc-parser/binding-linux-s390x-gnu@0.157.0': + resolution: {integrity: sha512-wSzuUshJVxcrx0c9UJYUOuUf0XHThC1+f8CEfeFbosg7FzTkjCdt89JKKU7BH8C9eTPrnJ5ir4QM0pWpVSmHnA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-x64-gnu@0.155.0': - resolution: {integrity: sha512-g6xSDC/JpbnVOz5uafMGyK3txBVRFMQTx8opv/yHXGxqV3ZMVl3bf7W8XrSnF68dmy3gM4dgReNryuE53+WkeQ==} + '@oxc-parser/binding-linux-x64-gnu@0.157.0': + resolution: {integrity: sha512-C4BY4QSVzN6R03Ner3r6EtIvLNR4VW4RAb63m+L0tiF/zD7grkBHMn1svyrOBFR4i32+GWJHu05xC4gGQYBhtA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxc-parser/binding-linux-x64-musl@0.155.0': - resolution: {integrity: sha512-6/4xlxKlZJWrQ0uwDFPc0H9+xLu7068CKhX3vIDW3SbvP/lVgnVuT5v6dyugeWskWpuxqF/WJ4WKwhxjU3pG2w==} + '@oxc-parser/binding-linux-x64-musl@0.157.0': + resolution: {integrity: sha512-kN3LdZ2xp9z+TLuzYUWPR/mz/HrKd20vMCGWyby1d8T8K5t5NPemcqfSv3y0oMwXK8OF3lW7MNJnc3uWphvwvw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxc-parser/binding-openharmony-arm64@0.155.0': - resolution: {integrity: sha512-tltklL0J0XjDxIRTBXWOBhvc2mitcmES45pIxhwDWfxRyqz7Vkeu0NekTZEIxGE4f/lXgq3vZcjjffteQOVorg==} + '@oxc-parser/binding-openharmony-arm64@0.157.0': + resolution: {integrity: sha512-cQKUrgBAFUaGcqp9Umb3GToFkvow92YeJxJuzbk8YPnButv9aY5HLyKUpxxh4WqJvP6POiNR5fUDDB5wI8Wiaw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxc-parser/binding-win32-arm64-msvc@0.155.0': - resolution: {integrity: sha512-alAb9TzjatUEsOeoncAziUnfdTDxfyswhalFZ9sC6plUgATIUx2NIZ0+bMn6aJ28AduS1OpG/OAisr/YISn4Ig==} + '@oxc-parser/binding-win32-arm64-msvc@0.157.0': + resolution: {integrity: sha512-qZsymd8L67o5bpzZ7gVO7qJUIF9Uf0/mXcoG0MDchBvdL7Q2tAF4aZBZFqc/YRd0WP3jTvqjs3CxlFhHgi48dA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxc-parser/binding-win32-ia32-msvc@0.155.0': - resolution: {integrity: sha512-yc5cbSfcGmRv/KpxDFuyk8adEBaWd/9HilWvBbQ4bFbus1V2PUh2mGB2Cfq9rqZTqLeiMT8x0skV+LKp9hOMgQ==} + '@oxc-parser/binding-win32-ia32-msvc@0.157.0': + resolution: {integrity: sha512-Ro9PcgwvRglGKI9fEYkbTKvIgh/hzWjv+yPyCTNuxp173i79YbTkkYeOvAEC9SFQPZXYr4+SuIrpCIaWN6sbUA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxc-parser/binding-win32-x64-msvc@0.155.0': - resolution: {integrity: sha512-8heq6jGq+rfpTDRDjoQiBHw0maQZf3IXkS99pdHQZPoTL5kyF5qyPS0RidUlSdnWDIqxXb5nux7GBD9cT+imUw==} + '@oxc-parser/binding-win32-x64-msvc@0.157.0': + resolution: {integrity: sha512-Ea0fqR+HLzzCt9tYhKbb6aJlM6wBXKWfuDwLhcG519B8HGtxthDzLGfbqMQdlX2Ii5gAZt/Hgxig/iApdxZSzQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@oxc-project/runtime@0.155.0': - resolution: {integrity: sha512-VbW9raczGS5ZZ1FMunUBYHe4uV/R684qlQCoMdE3n5JT1PcqQsvmFpMYkF8AD+W04fBLGAq6Tr7YsTk0jjvDBA==} + '@oxc-project/runtime@0.157.0': + resolution: {integrity: sha512-srnUknwVoji5JdmU664pA4XyjBJXmgxP8rWlnZhFovzw6XQxaICGWAuScZdlLmIHI+ZRc7WgeiC2CURF4tAszQ==} engines: {node: ^20.19.0 || >=22.12.0} '@oxc-project/types@0.153.0': resolution: {integrity: sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==} - '@oxc-project/types@0.155.0': - resolution: {integrity: sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==} - '@oxc-project/types@0.156.0': resolution: {integrity: sha512-1Duyg48TdJNdyhEB8Xn1L36bT9Pv6GUtlKjHxOys8xkaF/rQq3XJE+bAurSK/AgIz5mGFsb77cn9Pb20+WCScw==} - '@oxc-transform/binding-android-arm-eabi@0.155.0': - resolution: {integrity: sha512-PO5e/2UnD5I7UyEyp6qBwjtFCFXVyOmVo+LQvSdwxGz2W72gLAa2aAxlPuiP1blrrp9lnVGBHjuKvuYhTcO8XA==} + '@oxc-project/types@0.157.0': + resolution: {integrity: sha512-95iTox1qdt6WGWce3xwNOVayByOfLaYAq+qGPpub6NWbBh9sv0GG3+zyfh9ZBCO/jVu5A0EWI+qQI7g6fevjxg==} + + '@oxc-transform/binding-android-arm-eabi@0.157.0': + resolution: {integrity: sha512-uRHbSeooFBkwRx9DkedM9YPMAvnwPd9ds6iu+ki9yerAGgTe7dhQAgvrbxrbnhQF3L43QR2LMEkV1zobNpI2cQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxc-transform/binding-android-arm64@0.155.0': - resolution: {integrity: sha512-Kfj9jyhftDM+bvYlkxm6mJ2nVk8zxAoiab/I0Ecroh3RRTP9rgmGm7o+Z8N0DUm0Gb8LpkeYUdxLS9SfZOaQrQ==} + '@oxc-transform/binding-android-arm64@0.157.0': + resolution: {integrity: sha512-sZAV2CvG3hqJPG6O3OYF5hXfbWkb+kJQvYdfa0lC788dpQQI+zBR7RpFDpAY+3u4WpV2+v1H8SfSOdsw7aJ1ug==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxc-transform/binding-darwin-arm64@0.155.0': - resolution: {integrity: sha512-x9YvbuXHrgcZTiXAary1Gs/45Yv+N7EYT1rY4nFLOd0ygFTV6etR3U2KkA6gys3/zrM67Fygk0dC1ZsZEswTlA==} + '@oxc-transform/binding-darwin-arm64@0.157.0': + resolution: {integrity: sha512-/vxwVl483evp5RmWHoz999TL3RW3ghgOlgyd8VNGkBeFgxm2lJRKa0MKzbP7l0v6uIF6789yNe8b7B8BgaTWwA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxc-transform/binding-darwin-x64@0.155.0': - resolution: {integrity: sha512-bqqbHcEkuOUr0Nreoy/Lk7i2AxoGH2aRoS70zWzkJCu4ugxHpu1ysvqTMxcFSQYqK5AwpnJqFWhc1Nah2K2MoA==} + '@oxc-transform/binding-darwin-x64@0.157.0': + resolution: {integrity: sha512-Uoqdq4CaoMh2hyeOl5L2f8cnXOW36KZR2/MzY4E4zAkO2xKYaWHa/XWNPkFeTfnaOi9lmMIvZAYZ8R7ELxRhPg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxc-transform/binding-freebsd-x64@0.155.0': - resolution: {integrity: sha512-iIw3rWpfqRxvn+2t/6S1F2c6ur7sNSFJo9PyA9DUM+MlLwrcY1mohouUrPlEhiRRYJ6tqxjZn+5RDG1bkfHk2Q==} + '@oxc-transform/binding-freebsd-x64@0.157.0': + resolution: {integrity: sha512-QFjfMWa/oPK40lyWBCQR8/PlnpgVdPN6yOZqU5HJIzWyo0FwPd7tLpig7rtQgiBEhj+XoyxexXHUVFlwA9Oa/A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxc-transform/binding-linux-arm-gnueabihf@0.155.0': - resolution: {integrity: sha512-1uX81MobR6G4p6nnCgCqhjGhYM2nZJDOpLiS7HhfBiw38NyLSNRNZ3BYRlKLuCL/xJHWDSMzP1v7IvXuu45DAg==} + '@oxc-transform/binding-linux-arm-gnueabihf@0.157.0': + resolution: {integrity: sha512-aQHBtkX/75l8/hvBTggNLpfzPzHZ1vN/qxK9h+r0Gas5XaI4yeW9Qd/VPxGskBgtjmN3BfHXQvAFaj+R9vyBGA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-transform/binding-linux-arm-musleabihf@0.155.0': - resolution: {integrity: sha512-npw8MbFrCRpuQ3lgIQqi88wk5rvvN0OBekjYWvWSLM3w10vsC3LRqCTL9euT4PCGdn0s8Jsrz5mh80jmtRqxJg==} + '@oxc-transform/binding-linux-arm-musleabihf@0.157.0': + resolution: {integrity: sha512-dJVOATtEl0LxQuYXTsSAWRay19J5uq7bs1PBHBktEwoCdbXUa8Tm2lPZaX2QuEqC98xk7yAWMOlesv40x6m1rA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxc-transform/binding-linux-arm64-gnu@0.155.0': - resolution: {integrity: sha512-sqLbGtgvKz/d1o6hebqO9pZ3iSEyrUd6inwmuhAF/baA3SmRvxa8vUNduCUYKEvJvYF4q1hzJjyTXWHcp0tZrg==} + '@oxc-transform/binding-linux-arm64-gnu@0.157.0': + resolution: {integrity: sha512-Jdt0PpTwGWEqFkDqkRrR6yJNMevQebaQFnFZIxxnNXPVDze6mNxpEaPvJEmH0Dxzk1vQQm/I/SM08PAAb2qjpg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxc-transform/binding-linux-arm64-musl@0.155.0': - resolution: {integrity: sha512-DXnCgTIfyFNSs3Ut6dzwr1xRxx3N62+yWWioByUbb+XvBWv9xqZKniXTMMKbHxWHb40QrebEzW7ZZJncIkRZuA==} + '@oxc-transform/binding-linux-arm64-musl@0.157.0': + resolution: {integrity: sha512-qCLNQRA3KLaiCG9uXQmFbhjoetlCyfFwFdSXqbVVPCUPi1VFhuBGFltb2ZOMrxE2zMyh9RD27xzVULm+SRB1/A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxc-transform/binding-linux-ppc64-gnu@0.155.0': - resolution: {integrity: sha512-ctdkG6AO0/nvTjl8P/3BHD0GQAzac+kzZI6Bop4qYjn1i0Klmow+DFKL8NT2AYTy0vy75ah5C6P7Ta8JUwXrMQ==} + '@oxc-transform/binding-linux-ppc64-gnu@0.157.0': + resolution: {integrity: sha512-B5bEXT0mG88o2tIoKK/x2KOoXhbab5SjjBm5WfWlcpKLfr8ioYeZPPNT2gZN6FMq+pYuJA3f+i9dFIVlaqFz6w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxc-transform/binding-linux-riscv64-gnu@0.155.0': - resolution: {integrity: sha512-P4TcKFEuDG9o5unpgpph7MDi3jQMGP4UwWlzrKS5A99mUlp33B0JKp6f93bcFw9kEqJNAGTaN9iKTLNTAfarmQ==} + '@oxc-transform/binding-linux-riscv64-gnu@0.157.0': + resolution: {integrity: sha512-dDYzPGj3/SrcCwWK78FDXg5UXjJRxhVXADxIHvxiCFAeOAUGBFqBS1ykxw/VcsMueDr2QVgsYySPp+VB6fUNSg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxc-transform/binding-linux-riscv64-musl@0.155.0': - resolution: {integrity: sha512-aizvyWK/n5ba63wsc/ITfmuVsHdm1mbEe9QBUL51rRq3zu8QQBosfYuTmwFLydDp4TimQKecg/uUk30KAuxb/w==} + '@oxc-transform/binding-linux-riscv64-musl@0.157.0': + resolution: {integrity: sha512-zfplsQ80jaRXnD/l9d1w4awRanMkEiR+rlTJbxOkB+FnuypwHU3JYVJlrQLr/dph3XIrQSkvxsitY2XpyHdLpw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxc-transform/binding-linux-s390x-gnu@0.155.0': - resolution: {integrity: sha512-bDpXSaVVhhDtAzG+ezV7Mb8ibelPmEkD2HKBilX9YrPrrH2hHUAU1AfoCJwf4buH3R6TxsbBz/bJKkILUljzbA==} + '@oxc-transform/binding-linux-s390x-gnu@0.157.0': + resolution: {integrity: sha512-X7rmxwvgEQrg2qs0goelrFU5X1m5yaTNdnNBT94bK0cQB5q+E7HCxV8eX9wK3qMP8p2bae6N8+ck4gW9XGKBBQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxc-transform/binding-linux-x64-gnu@0.155.0': - resolution: {integrity: sha512-c3gk2AkScRwzy4bAcQWrfC3d9kIDxD/DlXandowYkm7ySYhcF7Kcuao4ttMTD5AI6Z+qHaS9LqtBFUXSdNBPKg==} + '@oxc-transform/binding-linux-x64-gnu@0.157.0': + resolution: {integrity: sha512-wi5EV43pRIiodHVttWD/785k78IMEyKUaSN1o9JN3Yu1GFBCXJEy9wU4J2V6//4iCeEFywdzQiMbHizG4cl0eQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxc-transform/binding-linux-x64-musl@0.155.0': - resolution: {integrity: sha512-ovOy1wIccACAdLDzDDIos/6uDr9xjCYCt1w08R2H1IqRqNiEeAlPwkKVDvo+1H5bwS8lTNj31QjuRHwB14/l9g==} + '@oxc-transform/binding-linux-x64-musl@0.157.0': + resolution: {integrity: sha512-ZK6gmsC1rGiqov3mRltKCwJiRxAhEv7l72TdfClGlLy1kH97GiPsnhLnIiCfqRwahN3W9DX98xMoijhtI/taTg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxc-transform/binding-openharmony-arm64@0.155.0': - resolution: {integrity: sha512-/MLJ/zHv9CZQuQFLYydu47iesobb46xcxDfKhqPl9294uDWEgTkSrDslaLwBn5DReDMWPcntKRqc8Ej/3sVGRg==} + '@oxc-transform/binding-openharmony-arm64@0.157.0': + resolution: {integrity: sha512-gz2syX2odmf8qzbiEVy+y+giea43tXnTavzy44/JsopYvUodDWOx4aZzu+ZrQZsbfmae1ntDv3NZWyTkbip2yQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxc-transform/binding-win32-arm64-msvc@0.155.0': - resolution: {integrity: sha512-YkMbvDXpU3C+8CCIimK2fEgrjX+2lzrb9WIHCf97azMCWPJ9ieZzMuZwxy/o/3crcQEs3SnXr+vQZIi8hbo4NA==} + '@oxc-transform/binding-win32-arm64-msvc@0.157.0': + resolution: {integrity: sha512-44/lSyHppcduYVtPpWURyUTB8IINPqmwwDFbZKxClGARBhDcPgcvcgI6X4niSUWYJTBHf7vT+OcxmWygRc17dQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxc-transform/binding-win32-ia32-msvc@0.155.0': - resolution: {integrity: sha512-LTvYdFdECJJZ4UHHNH4puVqWL371WLP6N35ChxRb6PnuN6IKXGpsqaoWXDIaS4+GQ3JoqViJIUhWbZl+Jjtfxw==} + '@oxc-transform/binding-win32-ia32-msvc@0.157.0': + resolution: {integrity: sha512-S7a7wqrwQAMTUCocS4weusiQLNY2WP9kJCGCOD1in6PRq1vQFkPt52mh1GLQCzCH+HMBEMx+wK9XotVZBRIVuA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxc-transform/binding-win32-x64-msvc@0.155.0': - resolution: {integrity: sha512-jndw3L1I1LMRpCvZJwUMwqbyDelPALyuc4g6Yq39kDvR8Hto5CA0XI6ZW+aiyRkTt/JsLSLnkJtflYdou7DeOA==} + '@oxc-transform/binding-win32-x64-msvc@0.157.0': + resolution: {integrity: sha512-lADvsdq/qHDlkdgzaaJbcwQZOEdNcjrLFW/MdJDG3AhUQSIINibJly2U9Q/yMsoUx/tAnR31gRvWWkLjHq5lxA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -3221,17 +3221,17 @@ packages: oxc-transform-react: optional: true - '@vitest/expect@5.0.5': - resolution: {integrity: sha512-mDBbYrXKpc+4TcSDwBW6adCMtPnide6Z1g8bI6gL0tY+nhdBxtGoOFW/kMrLDt6lJg3xjEUBkrY9yIPlgzpuig==} + '@vitest/expect@5.1.0': + resolution: {integrity: sha512-Okx71SHCjnfax7YLaxcJzZINi71BF2S5FezzQipheEQsiBAB0dhRBwuQ7uCJUH0/eGAT6HgAtmVVzrEZo6Qmcw==} - '@vitest/pretty-format@5.0.5': - resolution: {integrity: sha512-24sSdIlMA9DVPXnYiB9siwU0bTd887Y9jX3+vabztCSsvHwo7ipvJ/a2L3Rljw8+2rK1f5fCj3h5U9I/Jsqgbw==} + '@vitest/pretty-format@5.1.0': + resolution: {integrity: sha512-IRx5mc30CrFzyMNni6SZKQ1r53kv049Mcvvk0WbWcD6PUz/bFjG4zYv0KosQAeonPpGp5WxqYBMqdSOfJfvVWw==} - '@vitest/spy@5.0.5': - resolution: {integrity: sha512-lwJRExuH417257Q5wv9QYugN9IMJkoxcrKrYxGPQkBzl7wlNpTUxD/5yNX4ESKVUIShKPgkGchYPFMWOOk0wzw==} + '@vitest/spy@5.1.0': + resolution: {integrity: sha512-2DPO5OMHWKrBngC+fCmTQqemNF0gidRhp3lxbBmRhW+M1XJrfgPpqNqWVevXtn2f2ufD5ZaR1B6B641aAlcX5A==} - '@vitest/utils@5.0.5': - resolution: {integrity: sha512-/rBu7gzLDQI/SC79Tn98b5DwOgaHU/Gt4I9OVeP3YofzNaYtbImRCOJQmT1S6vOJg9gEIlWC+r3QxKkjuSa1nQ==} + '@vitest/utils@5.1.0': + resolution: {integrity: sha512-V+qgCwkvVw+s1t1S5TaoBHsLi5Sz/YmohCMoOu0mZ8ZQst2bKhRYARAQucWpVg8D0mv0x5MHcWXY5QdOsoiGBQ==} '@workflow/serde@4.1.0': resolution: {integrity: sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ==} @@ -3733,8 +3733,8 @@ packages: zod: optional: true - e2e@0.22.0: - resolution: {integrity: sha512-IsE6LHPuAM5bHar7jNji79FGpfpBoXBSOSx4w0ZWRBosR+PKFjqjqvJWIq52h+S3qMGp8zaBrUWnEbUoOdFV4w==} + e2e@0.23.0: + resolution: {integrity: sha512-x4wbcLDbwtmB9avyruqQX2j77i8HynAGG74vxA2SVSCJwnD7CaioyfBOxKU3L7J7K7cWIDU0LNz3yR5j29UjNQ==} engines: {node: ^22.22.3 || >=24.8.0} hasBin: true peerDependencies: @@ -4143,8 +4143,8 @@ packages: resolution: {integrity: sha512-6li2QanLsAXpIH2R6j77MzRyvOyrvdTqlKtO4CgBdHGNvN99ZZfyxszHc5o5+IZBWD5u6Hzwg83JoGXmqZNG9Q==} engines: {node: '>=18'} - oxc-parser@0.155.0: - resolution: {integrity: sha512-C/ReSf1JUFukK/zvk6jhcNibSssvas5+ktIzK7fbKVd3CedWe59C3QwHEOrEZj/4Rt9+xg0Jeis/Jv1F/KM1mw==} + oxc-parser@0.157.0: + resolution: {integrity: sha512-2MJ9tZGXUbEIhQT/O2OPLlYCgur75ES26t2Pb1sYrvDQcRjrE7GmubkALgPEB6LzOY6sM81AAHKfl5M/FgnjJg==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: '@oxc-parser/binding-wasm32-wasi': '*' @@ -4152,8 +4152,8 @@ packages: '@oxc-parser/binding-wasm32-wasi': optional: true - oxc-transform@0.155.0: - resolution: {integrity: sha512-Z1qL0TaO06hqZjx/4UXeyspxBiyfNGR8r8vBn48MlIUWWPdTry0DCgo/1AOsvVnS6KgJieok/yfdCSCHia+ojA==} + oxc-transform@0.157.0: + resolution: {integrity: sha512-2H8XPFEbZQv/uoJ863a8YHdNrWWfETcKJ/fVutW7X1ryA5UhhNqaJsV1ib9y2pHOoHfofBIMzfIBCQmzLOVnTA==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: '@oxc-transform/binding-wasm32-wasi': '*' @@ -4830,11 +4830,11 @@ snapshots: dependencies: json-schema: 0.4.0 - '@ai-sdk/provider@4.0.34': + '@ai-sdk/provider@4.0.35': dependencies: json-schema: 0.4.0 - '@ai-sdk/provider@4.0.35': + '@ai-sdk/provider@4.0.36': dependencies: json-schema: 0.4.0 @@ -5228,20 +5228,20 @@ snapshots: '@drizzle-team/brocli@0.12.1': {} - '@e2e-dev/decision@0.3.1(ai@7.0.160(zod@4.6.7))(e2e@0.22.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)))': + '@e2e-dev/decision@0.3.2(ai@7.0.160(zod@4.6.7))(e2e@0.23.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)))': dependencies: ai: 7.0.160(zod@4.6.7) - e2e: 0.22.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)) + e2e: 0.23.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)) pngjs: 7.0.0 zod: 4.6.7 - '@e2e-dev/github@0.4.4(e2e@0.22.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)))': + '@e2e-dev/github@0.4.4(e2e@0.23.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)))': dependencies: - e2e: 0.22.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)) + e2e: 0.23.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)) - '@e2e-dev/web@0.15.4(e2e@0.22.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)))': + '@e2e-dev/web@0.15.5(e2e@0.23.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)))': dependencies: - e2e: 0.22.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)) + e2e: 0.23.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)) playwright-core: 1.64.1(zod@4.6.7) transitivePeerDependencies: - bufferutil @@ -5690,126 +5690,126 @@ snapshots: '@oozcitak/util@10.0.0': {} - '@oxc-parser/binding-android-arm-eabi@0.155.0': + '@oxc-parser/binding-android-arm-eabi@0.157.0': optional: true - '@oxc-parser/binding-android-arm64@0.155.0': + '@oxc-parser/binding-android-arm64@0.157.0': optional: true - '@oxc-parser/binding-darwin-arm64@0.155.0': + '@oxc-parser/binding-darwin-arm64@0.157.0': optional: true - '@oxc-parser/binding-darwin-x64@0.155.0': + '@oxc-parser/binding-darwin-x64@0.157.0': optional: true - '@oxc-parser/binding-freebsd-x64@0.155.0': + '@oxc-parser/binding-freebsd-x64@0.157.0': optional: true - '@oxc-parser/binding-linux-arm-gnueabihf@0.155.0': + '@oxc-parser/binding-linux-arm-gnueabihf@0.157.0': optional: true - '@oxc-parser/binding-linux-arm-musleabihf@0.155.0': + '@oxc-parser/binding-linux-arm-musleabihf@0.157.0': optional: true - '@oxc-parser/binding-linux-arm64-gnu@0.155.0': + '@oxc-parser/binding-linux-arm64-gnu@0.157.0': optional: true - '@oxc-parser/binding-linux-arm64-musl@0.155.0': + '@oxc-parser/binding-linux-arm64-musl@0.157.0': optional: true - '@oxc-parser/binding-linux-ppc64-gnu@0.155.0': + '@oxc-parser/binding-linux-ppc64-gnu@0.157.0': optional: true - '@oxc-parser/binding-linux-riscv64-gnu@0.155.0': + '@oxc-parser/binding-linux-riscv64-gnu@0.157.0': optional: true - '@oxc-parser/binding-linux-riscv64-musl@0.155.0': + '@oxc-parser/binding-linux-riscv64-musl@0.157.0': optional: true - '@oxc-parser/binding-linux-s390x-gnu@0.155.0': + '@oxc-parser/binding-linux-s390x-gnu@0.157.0': optional: true - '@oxc-parser/binding-linux-x64-gnu@0.155.0': + '@oxc-parser/binding-linux-x64-gnu@0.157.0': optional: true - '@oxc-parser/binding-linux-x64-musl@0.155.0': + '@oxc-parser/binding-linux-x64-musl@0.157.0': optional: true - '@oxc-parser/binding-openharmony-arm64@0.155.0': + '@oxc-parser/binding-openharmony-arm64@0.157.0': optional: true - '@oxc-parser/binding-win32-arm64-msvc@0.155.0': + '@oxc-parser/binding-win32-arm64-msvc@0.157.0': optional: true - '@oxc-parser/binding-win32-ia32-msvc@0.155.0': + '@oxc-parser/binding-win32-ia32-msvc@0.157.0': optional: true - '@oxc-parser/binding-win32-x64-msvc@0.155.0': + '@oxc-parser/binding-win32-x64-msvc@0.157.0': optional: true - '@oxc-project/runtime@0.155.0': {} + '@oxc-project/runtime@0.157.0': {} '@oxc-project/types@0.153.0': {} - '@oxc-project/types@0.155.0': {} - '@oxc-project/types@0.156.0': {} - '@oxc-transform/binding-android-arm-eabi@0.155.0': + '@oxc-project/types@0.157.0': {} + + '@oxc-transform/binding-android-arm-eabi@0.157.0': optional: true - '@oxc-transform/binding-android-arm64@0.155.0': + '@oxc-transform/binding-android-arm64@0.157.0': optional: true - '@oxc-transform/binding-darwin-arm64@0.155.0': + '@oxc-transform/binding-darwin-arm64@0.157.0': optional: true - '@oxc-transform/binding-darwin-x64@0.155.0': + '@oxc-transform/binding-darwin-x64@0.157.0': optional: true - '@oxc-transform/binding-freebsd-x64@0.155.0': + '@oxc-transform/binding-freebsd-x64@0.157.0': optional: true - '@oxc-transform/binding-linux-arm-gnueabihf@0.155.0': + '@oxc-transform/binding-linux-arm-gnueabihf@0.157.0': optional: true - '@oxc-transform/binding-linux-arm-musleabihf@0.155.0': + '@oxc-transform/binding-linux-arm-musleabihf@0.157.0': optional: true - '@oxc-transform/binding-linux-arm64-gnu@0.155.0': + '@oxc-transform/binding-linux-arm64-gnu@0.157.0': optional: true - '@oxc-transform/binding-linux-arm64-musl@0.155.0': + '@oxc-transform/binding-linux-arm64-musl@0.157.0': optional: true - '@oxc-transform/binding-linux-ppc64-gnu@0.155.0': + '@oxc-transform/binding-linux-ppc64-gnu@0.157.0': optional: true - '@oxc-transform/binding-linux-riscv64-gnu@0.155.0': + '@oxc-transform/binding-linux-riscv64-gnu@0.157.0': optional: true - '@oxc-transform/binding-linux-riscv64-musl@0.155.0': + '@oxc-transform/binding-linux-riscv64-musl@0.157.0': optional: true - '@oxc-transform/binding-linux-s390x-gnu@0.155.0': + '@oxc-transform/binding-linux-s390x-gnu@0.157.0': optional: true - '@oxc-transform/binding-linux-x64-gnu@0.155.0': + '@oxc-transform/binding-linux-x64-gnu@0.157.0': optional: true - '@oxc-transform/binding-linux-x64-musl@0.155.0': + '@oxc-transform/binding-linux-x64-musl@0.157.0': optional: true - '@oxc-transform/binding-openharmony-arm64@0.155.0': + '@oxc-transform/binding-openharmony-arm64@0.157.0': optional: true - '@oxc-transform/binding-win32-arm64-msvc@0.155.0': + '@oxc-transform/binding-win32-arm64-msvc@0.157.0': optional: true - '@oxc-transform/binding-win32-ia32-msvc@0.155.0': + '@oxc-transform/binding-win32-ia32-msvc@0.157.0': optional: true - '@oxc-transform/binding-win32-x64-msvc@0.155.0': + '@oxc-transform/binding-win32-x64-msvc@0.157.0': optional: true '@oxfmt/binding-android-arm-eabi@0.75.0': @@ -6909,24 +6909,24 @@ snapshots: '@rolldown/pluginutils': 1.0.1 vite: 8.3.6(@types/node@24.19.2)(tsx@4.23.15) - '@vitest/expect@5.0.5': + '@vitest/expect@5.1.0': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 5.0.5 - '@vitest/utils': 5.0.5 + '@vitest/spy': 5.1.0 + '@vitest/utils': 5.1.0 chai: 6.3.0 tinyrainbow: 3.2.0 - '@vitest/pretty-format@5.0.5': + '@vitest/pretty-format@5.1.0': dependencies: tinyrainbow: 3.2.0 - '@vitest/spy@5.0.5': {} + '@vitest/spy@5.1.0': {} - '@vitest/utils@5.0.5': + '@vitest/utils@5.1.0': dependencies: - '@vitest/pretty-format': 5.0.5 + '@vitest/pretty-format': 5.1.0 convert-source-map: 2.0.0 tinyrainbow: 3.2.0 @@ -7168,22 +7168,22 @@ snapshots: react: 19.3.1 zod: 4.6.7 - e2e@0.22.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)): + e2e@0.23.0(@ai-sdk/anthropic@4.0.87(zod@4.6.7))(@ai-sdk/openai@4.0.101(zod@4.6.7))(ai@7.0.160(zod@4.6.7)): dependencies: '@ai-sdk/anthropic': 4.0.87(zod@4.6.7) '@ai-sdk/openai': 4.0.101(zod@4.6.7) - '@ai-sdk/provider': 4.0.34 + '@ai-sdk/provider': 4.0.36 '@clack/prompts': 1.8.1 '@jridgewell/remapping': 2.3.5 '@modelcontextprotocol/server': 2.4.0 - '@oxc-project/runtime': 0.155.0 - '@vitest/expect': 5.0.5 + '@oxc-project/runtime': 0.157.0 + '@vitest/expect': 5.1.0 ai: 7.0.160(zod@4.6.7) commander: 15.0.0 fast-png: 8.0.0 get-tsconfig: 4.14.3 - oxc-parser: 0.155.0 - oxc-transform: 0.155.0 + oxc-parser: 0.157.0 + oxc-transform: 0.157.0 picocolors: 1.1.1 pixelmatch: 8.0.0 zod: 4.6.7 @@ -7518,51 +7518,51 @@ snapshots: node-releases@2.0.63: {} - oxc-parser@0.155.0: + oxc-parser@0.157.0: dependencies: - '@oxc-project/types': 0.155.0 + '@oxc-project/types': 0.157.0 optionalDependencies: - '@oxc-parser/binding-android-arm-eabi': 0.155.0 - '@oxc-parser/binding-android-arm64': 0.155.0 - '@oxc-parser/binding-darwin-arm64': 0.155.0 - '@oxc-parser/binding-darwin-x64': 0.155.0 - '@oxc-parser/binding-freebsd-x64': 0.155.0 - '@oxc-parser/binding-linux-arm-gnueabihf': 0.155.0 - '@oxc-parser/binding-linux-arm-musleabihf': 0.155.0 - '@oxc-parser/binding-linux-arm64-gnu': 0.155.0 - '@oxc-parser/binding-linux-arm64-musl': 0.155.0 - '@oxc-parser/binding-linux-ppc64-gnu': 0.155.0 - '@oxc-parser/binding-linux-riscv64-gnu': 0.155.0 - '@oxc-parser/binding-linux-riscv64-musl': 0.155.0 - '@oxc-parser/binding-linux-s390x-gnu': 0.155.0 - '@oxc-parser/binding-linux-x64-gnu': 0.155.0 - '@oxc-parser/binding-linux-x64-musl': 0.155.0 - '@oxc-parser/binding-openharmony-arm64': 0.155.0 - '@oxc-parser/binding-win32-arm64-msvc': 0.155.0 - '@oxc-parser/binding-win32-ia32-msvc': 0.155.0 - '@oxc-parser/binding-win32-x64-msvc': 0.155.0 - - oxc-transform@0.155.0: + '@oxc-parser/binding-android-arm-eabi': 0.157.0 + '@oxc-parser/binding-android-arm64': 0.157.0 + '@oxc-parser/binding-darwin-arm64': 0.157.0 + '@oxc-parser/binding-darwin-x64': 0.157.0 + '@oxc-parser/binding-freebsd-x64': 0.157.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.157.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.157.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.157.0 + '@oxc-parser/binding-linux-arm64-musl': 0.157.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.157.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.157.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.157.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.157.0 + '@oxc-parser/binding-linux-x64-gnu': 0.157.0 + '@oxc-parser/binding-linux-x64-musl': 0.157.0 + '@oxc-parser/binding-openharmony-arm64': 0.157.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.157.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.157.0 + '@oxc-parser/binding-win32-x64-msvc': 0.157.0 + + oxc-transform@0.157.0: optionalDependencies: - '@oxc-transform/binding-android-arm-eabi': 0.155.0 - '@oxc-transform/binding-android-arm64': 0.155.0 - '@oxc-transform/binding-darwin-arm64': 0.155.0 - '@oxc-transform/binding-darwin-x64': 0.155.0 - '@oxc-transform/binding-freebsd-x64': 0.155.0 - '@oxc-transform/binding-linux-arm-gnueabihf': 0.155.0 - '@oxc-transform/binding-linux-arm-musleabihf': 0.155.0 - '@oxc-transform/binding-linux-arm64-gnu': 0.155.0 - '@oxc-transform/binding-linux-arm64-musl': 0.155.0 - '@oxc-transform/binding-linux-ppc64-gnu': 0.155.0 - '@oxc-transform/binding-linux-riscv64-gnu': 0.155.0 - '@oxc-transform/binding-linux-riscv64-musl': 0.155.0 - '@oxc-transform/binding-linux-s390x-gnu': 0.155.0 - '@oxc-transform/binding-linux-x64-gnu': 0.155.0 - '@oxc-transform/binding-linux-x64-musl': 0.155.0 - '@oxc-transform/binding-openharmony-arm64': 0.155.0 - '@oxc-transform/binding-win32-arm64-msvc': 0.155.0 - '@oxc-transform/binding-win32-ia32-msvc': 0.155.0 - '@oxc-transform/binding-win32-x64-msvc': 0.155.0 + '@oxc-transform/binding-android-arm-eabi': 0.157.0 + '@oxc-transform/binding-android-arm64': 0.157.0 + '@oxc-transform/binding-darwin-arm64': 0.157.0 + '@oxc-transform/binding-darwin-x64': 0.157.0 + '@oxc-transform/binding-freebsd-x64': 0.157.0 + '@oxc-transform/binding-linux-arm-gnueabihf': 0.157.0 + '@oxc-transform/binding-linux-arm-musleabihf': 0.157.0 + '@oxc-transform/binding-linux-arm64-gnu': 0.157.0 + '@oxc-transform/binding-linux-arm64-musl': 0.157.0 + '@oxc-transform/binding-linux-ppc64-gnu': 0.157.0 + '@oxc-transform/binding-linux-riscv64-gnu': 0.157.0 + '@oxc-transform/binding-linux-riscv64-musl': 0.157.0 + '@oxc-transform/binding-linux-s390x-gnu': 0.157.0 + '@oxc-transform/binding-linux-x64-gnu': 0.157.0 + '@oxc-transform/binding-linux-x64-musl': 0.157.0 + '@oxc-transform/binding-openharmony-arm64': 0.157.0 + '@oxc-transform/binding-win32-arm64-msvc': 0.157.0 + '@oxc-transform/binding-win32-ia32-msvc': 0.157.0 + '@oxc-transform/binding-win32-x64-msvc': 0.157.0 oxfmt@0.75.0: dependencies: diff --git a/package.json b/package.json index f422b7b5..76e4d908 100644 --- a/package.json +++ b/package.json @@ -73,16 +73,16 @@ "@ai-sdk/openai": "4.0.101", "@ai-sdk/typesafe-ai": "3.0.26", "@cloudflare/workers-types": "^5.20261022.1", - "@e2e-dev/decision": "0.3.1", + "@e2e-dev/decision": "0.3.2", "@e2e-dev/github": "0.4.4", - "@e2e-dev/web": "0.15.4", + "@e2e-dev/web": "0.15.5", "@mpsuesser/oxlint-plugin-effect": "0.6.0", "@oxlint/plugins": "1.90.0", "@types/node": "^24.12.4", "@types/pngjs": "6.0.5", "@yielded/effect-tsrs": "0.2.3", "ai": "7.0.160", - "e2e": "0.22.0", + "e2e": "0.23.0", "jpeg-js": "0.4.4", "lefthook": "^2.2.2", "oxfmt": "0.75.0",