@unotest/web 0.49.0 → 0.49.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,146 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.49.2] - 2026-10-12
4
+
5
+ ### Patch Changes
6
+
7
+ - 29fc1f3: A test that fails on a page whose main thread is busy no longer spends a long wait collecting its failure bundle. The runner first asks the page a question that costs it nothing, with a short budget; a page that does not answer is not read at all. Each part of the bundle that was not read now holds the reason where it would be (`screenshot-error.txt`, `page-html-error.txt`, `outline-error.txt`) instead of being missing without a word. Assertions keep their own `timeout` on such a page: the page's reads count against it, so `assertText(loc, x, {timeout: 400})` fails after about 400 ms and says the page gave no answer, instead of waiting out the action timeout. `assertNeverAppears` no longer passes on a page that stops answering: absence is proven only by reads that answered for the whole window, so it fails and says the page gave no answer.
8
+ - 5c29258: A failure bundle no longer holds an empty `console.json` when the browser console was not recorded. The console is recorded only with `UNOTEST_CONSOLE=1`; without it, the file is left out, `get_failure_console` answers `entries: null` with a message naming the variable, and the `prepare-fix` prompt says the console was not recorded instead of "no console entries captured".
9
+ - 50a9980: `env(name, fallback)` returns `fallback` when the variable is not set, a default in one line: `api = env('API_URL', 'http://localhost:3000')`. Before, it took an `if` / `else`: the DSL has no `??`, and `env('X') || 'default'` gives `true`, not the value. Without a fallback `env(name)` still returns `null` for an unset name. A secret is refused as before, with a fallback or without.
10
+ - 4df2165: `evaluate(js)` on a page whose main thread is busy, a script loop or a long task, now fails the step after the action timeout with "the page gave no answer" instead of holding the test forever. `evaluateOnLocator` already did. A script that has started still runs as long as it needs.
11
+
12
+ Inside an entered frame, the function form of `evaluate`, `evaluate('function(n) { … }', 21)`, now receives its argument. Before, it received the frame's root element.
13
+
14
+ - 5df0f20: A lambda passed to `evaluate` or `evaluateOnLocator` is now answered with what to write: the JavaScript goes in as a string, so quote the lambda — `evaluate('() => new Date().toISOString()')`. `lint` and a run say the same. Before, both said to call a helper function by name, which pointed the wrong way. For targets built on `@unotest/dsl`: the contract registry and the dispatcher take an optional `suggestForLambdaArgument(name)` hook for this answer.
15
+ - fa28983: A failed test in the CLI now prints where its failure bundle is, as an absolute path on stdout (`failure bundle: /…/.unotest/failures/<runId>/<test>`), so it opens from any working directory. The run journal keeps `bundlePath` and `screenshotPath` relative to the project root (the directory holding `.unotest/` and `unotest/`), and the agent integration guide now says so.
16
+ - eed900d: `getByRole(role, options)` now reads Playwright's state options: `checked`, `disabled`, `expanded`, `pressed`, `selected`, `level` and `includeHidden`, next to `name` and `exact`. Before, every key but `name` and `exact` was dropped without a word, so `count(getByRole('button', {name: 'Save', disabled: false}))` also counted a disabled Save button and the check went green. Any other key is now refused, at lint time (new rule `lint:role-unknown-option`, an error by default) and at run time, with the list of keys it reads.
17
+
18
+ The MCP locator input takes the same options on a `getByRole` step and refuses any other key instead of stripping it. A recorded step keeps them, and the generated test writes them out.
19
+
20
+ - 26d31d7: `lint:env-host-from-base` now finds the host variable of a `goto` inside a ternary and in a longer sum: `goto(ready ? APP_URL : '/x')` and `goto(APP_URL + '/a' + '/b')` were not checked before. A variable used only as the ternary's condition is not taken for the host.
21
+ - 29fc1f3: `unotest-web init --help` prints its usage once. It used to print it twice, while every other command printed its help once.
22
+ - 9dcc571: A test run no longer creates `unotest/jsconfig.json`. `e2e`, `lint` and MCP `run_test` used to write it into your tree when it was missing; now only `init` and `types` write it, and `init` adds `unotest/jsconfig.json` to `.gitignore`. A run still refreshes the gitignored `.unotest/types/env.d.ts` with your variable names.
23
+
24
+ Migration: a checkout without the file (a new clone, a teammate's machine) gets editor typings back with `npx @unotest/web types`. A `jsconfig.json` you already commit stays as it is; remove the new `.gitignore` line if you want to keep committing it.
25
+
26
+ - 22a848b: `locator(selector, options)` now reads its options: `hasText`, `hasNotText`, `has` and `hasNot` narrow the matches exactly as `filter()` does, and any other key is refused at lint time and at run time. Before, the second argument was dropped without a word, so `count(locator('option', {hasText: 'Beta'}))` counted every option.
27
+
28
+ New `isChecked(loc)` reads the checked state of a checkbox, radio or switch, native or ARIA role. An element with no checked state fails the step instead of reading `false`.
29
+
30
+ `check` / `uncheck` now click and wait until the element reads checked (unchecked) within the action timeout. A controlled switch the app flips a moment after the click, once the server confirms, no longer fails with "did not change its state". An element already in the target state is not clicked, as before. A switch that never flips fails, naming the state it wanted and the last one it saw. `check` / `uncheck` on an element that is not a checkbox, radio or switch is refused; use `click` for it.
31
+
32
+ A `<label>`, or anything inside one, stands for the checkbox it names, as in Playwright: `check`, `uncheck` and `isChecked` on `getByText('Remember me')` act on and read the labelled checkbox. `assertValue(label, "true")` on such a label now asserts the checkbox's checked state too, instead of comparing against its submitted value `"on"`.
33
+
34
+ - abd74f5: `locator(selector, options)` and `filter(loc, options)` now refuse options that are not an object, naming the function: `locator('option', 5)` and `filter(loc, null)` used to build a filter with no conditions and match everything, and `locator('option', null)` failed with a bare `TypeError`. `filter(loc)` with no options is unchanged. `getByRole(role, {exact})` now takes only `true` or `false`, like its state flags; `{exact: 'yes'}` used to count as `true`.
35
+ - 6a6712c: MCP locator input now refuses a regex `source` that does not compile, with "regex source does not compile" and the engine's reason, instead of failing later when the locator runs. A recorded regex is written into the generated test with `/` and line breaks escaped, so a source holding `/` can no longer close the literal and add code to the test.
36
+ - 98aeab8: `e2e --notes` and `collection --notes` print every `note()` of every test under its line, a passing test's too, as `note <label>: <value> — step "<step>"`. A failed test lists them in place of the failing step's own notes, so none prints twice. Without the flag the output is unchanged.
37
+ - 51f06c9: Notes printed under a test line (`--notes`, and the notes of a failing step) now show line breaks and terminal escape sequences escaped, as `\n` and `\x1b`. A note's value often comes from the page under test, and an escape sequence in it used to reach the terminal as an instruction, and a line break could forge a line of the report.
38
+ - 0447cec: A `__proto__` key in an object literal is now an ordinary key of that object, as in JSON, instead of setting its prototype. `getByRole('button', {__proto__: {name: 'Save'}})` was refused by the lint, but the run read `name` through the prototype and matched on it. The run now refuses `__proto__` as an unknown option too, with the lint's message.
39
+ - 92242d3: A run on a browser profile (`launch.userDataDir` or `UNOTEST_USER_DATA_DIR`) no longer prints a line about it on every run. The run journal records it instead: the `run:started` event in `steps.jsonl` carries `browserProfile`, the profile directory the run played on. Its presence means every scenario shared one browser context, with no isolation between them. Runs with a fresh context per test have no such field.
40
+ - a1e8482: Scenarios can use the ternary `cond ? a : b`, as in JS: the lowest precedence, nested to the right, and allowed wherever a value goes — a variable, a call argument, an object field, a `return`, a lambda body. Only the branch the condition picks runs, so `x == null ? '' : x.name` is a safe guard. `lint` accepts a ternary in a slot when both branches fit it. `?.` and `??` are still refused, and the parse error now points to the ternary or `if` / `else`.
41
+ - 6b9ceee: New `texts(loc)` returns the `textContent` of every element the locator matches, in page order, and `[]` when nothing matches. It is one read with no wait: the list to branch on, where `assertTexts` is the waiting check. Before, the only way to get that list was `count` plus `nth(i)` in a loop, since `textContent` on several matches is a strict-mode error.
42
+ - 65a81be: The viewer no longer paints a test marked `@expect-fail` as failed on purpose when it errored. The tile, the tree dot, the scenario header and the history strips now read the marker the runner recorded for each run, not the marker in the source today: a marked test that failed is purple, the same test erroring on a script error is red and counts as failing. The run index records that reading per run and is rebuilt once on the first start after the update. The scenario header of a one-test file now shows `expected` in the same purple as the tree, instead of `failed`.
43
+ - Updated dependencies [5df0f20]
44
+ - Updated dependencies [98aeab8]
45
+ - Updated dependencies [0447cec]
46
+ - Updated dependencies [92242d3]
47
+ - Updated dependencies [a1e8482]
48
+ - Updated dependencies [65a81be]
49
+ - @unotest/dsl@0.49.2
50
+ - @unotest/core@0.49.2
51
+ - @unotest/protocol@0.49.2
52
+ - @unotest/viewer@0.49.2
53
+ - @unotest/grounder-client@0.49.2
54
+
55
+ ## [0.49.1] - 2026-10-11
56
+
57
+ ### Patch Changes
58
+
59
+ - 4897ede: A run of one test on a box:
60
+
61
+ - A test the file does not have is refused when the run is ordered, with the file's tests listed, the same refusal the viewer and `e2e --test` give. Before, the box accepted the run, it exited without a word and the notification said "tests failed". The check needs a bundle pushed with this version, since `bundle push` now lists each scenario file's tests in the bundle. An older bundle is not checked.
62
+ - `box runs`, `box run` and notifications name such a run `file › test`, as `bundle push --follow` already did. This also applies to a file with a single test, whose runs used to show only the file. `box queue` names a waiting or running run of one test the same way. `box run --json` and `box queue --json` gain a `test` field on those runs. A run of a whole file of several tests is named as before, and a file's notification series is the same whether a run played one of its tests or all of them.
63
+
64
+ - 4897ede: Box runs of one test: the box accepts a test name only as a scenario function is spelled (letters, digits, `_`, `$`, up to 128 characters) and refuses anything else before it reaches the queue; the box and the run sidecar check it by the same rule, so a name with Cyrillic letters or `$` is played instead of lost. `box queue`, `box runs` and `box run` print run labels with control characters shown as escapes, so a name written by an older box cannot drive the terminal.
65
+ - de529ab: A `const` assigned again (`K = 2` or `K++`) now fails the run at that line with the same message `lint` gives, as JavaScript does. Before, `lint` refused it but `e2e` and `run_test` ran the assignment and passed. `let` reassigns as before, and a `const` in a loop body is declared again on every pass.
66
+ - 4897ede: Scenarios can declare variables with `let` and `const`, and pass a lambda to four array methods. `let x = …` and `const x = …` work like the bare assignment, in the function's scope, and `for (let i = 0; …)` declares the loop variable; assigning a const again is a lint error (`const-assign`). At the top of a file a `const` holding a literal is visible in every function, as helper functions are. `a.filter(x => …)`, `a.map((x, i) => …)`, `a.find(x => …)` and `a.some(x => …)` take an expression or a block with `return`; the parameters live in their own scope and the body runs element by element. A lambda anywhere else is refused (`lambda-position`) — functions are not values — and `filter` with an options object is still the locator step. The viewer shows scenarios written with the new syntax.
67
+ - 4897ede: `lint` refuses a statement at the top level of a scenario or helper file, and the DSL's refusals of everyday JavaScript say what to write instead.
68
+
69
+ - Only function definitions run at the top level of a file. A statement there (`BASE = 'x'`, `const BASE = 'x'`, a call) was dropped without a word: `lint` passed and the test failed with `Variable "BASE" is not defined`. It is now `validator:unsupported-statement`, an error at its line, with the way out: a function that returns the value.
70
+ - `let x = 1` and `const x = 1` get the same answer as `var` ("use direct assignment") instead of `unexpected WORD`.
71
+ - An arrow with parameters (`a.map(x => x * 2)`), an arrow or a function as a value, a spread, `for…of` / `for…in`, `let` in a `for` loop, `n += 1`, `o.a = 2`, `try` / `throw` / `switch`, `typeof` and `?` (ternary, `?.`, `??`) each name the DSL way, at the token where parsing stops.
72
+ - `a[0] = 2` says to build a new array with `push`. `.includes()` on an array, at run time, says what an array answers.
73
+ - `pop`, `shift`, `unshift`, `splice`, `sort`, `reverse`, `find`, `some`, `every`, `reduce`, `Object.keys`, `Math.max` / `min` / `floor` / `ceil` and `indexOf` on an array are answered with what to write instead.
74
+
75
+ **Migration:** a file with a statement at its top level now fails `lint`. That statement never ran; move it into `test_*` or into a function.
76
+
77
+ - 4897ede: Scenarios can now write into arrays and sort them. `arr[i] = v` replaces an element (nested indexes and object keys too); an index past the end fails the step instead of leaving holes, and `arr[arr.length] = v` appends. The keys `__proto__`, `constructor` and `prototype` cannot be assigned, and an index read on an object returns its own keys only, so a scenario cannot reach a shared prototype. `arr.sortBy(key?, {desc?})` sorts an array in place by an object field, or by the values themselves without a key; the sort is stable and the values must be all numbers or all strings. The linter's hint for `a.sort()` now points to `sortBy`, and its message for a non-list `assertTexts` argument names it `expected`, as the docs do.
78
+ - 4897ede: `&&` and `||` in scenarios now short-circuit as in JavaScript: the right side is not evaluated once the left one decides the result. A null guard such as `x != null && x.a == 1` no longer fails with "Property access on non-object value" when `x` is null, including inside `waitUntil`. The result stays a boolean.
79
+ - 4897ede: The expected value of `assertTexts`, `assertText` and other assertions can now be any expression of the right kind: a variable holding a list, an index read such as `labels[i]`, or a helper's result. Previously the linter accepted only an array literal for `assertTexts` and rejected `arr[i]` as a text. A value known to be the wrong kind is still refused with the argument's name; anything else is checked when the step runs.
80
+ - 4897ede: Strings answer `s.split(separator)`, which returns an array of strings as in JavaScript: `"a, b".split(", ")` gives `["a", "b"]`, the parts keep their spaces, and a separator that is not there gives the whole string as the one part. The linter's hint for `split` no longer points to a shell script.
81
+ - 4897ede: `@expect-fail` covers a test that fails, not a script that breaks: a marked test that errors (an unknown function, a typo) is reported as errored and turns the collection red, instead of counting as failed on purpose.
82
+ - 5319d32: A file of several tests whose only failure is marked `@expect-fail` now reads as failed on purpose on its own line too, under `bundle push --follow` and in the run index, instead of a red `failed` above the collection's green verdict.
83
+ - 4897ede: `// @expect-fail` now reaches the runner, not only the viewer. A marked test that fails is reported as failed on purpose in `e2e` and in a collection (`N of M failed on purpose`, `expected=N` in the summary), and every `test_*` of a file whose leading comments carry the marker is marked. A collection whose only failures are on purpose exits 0; `e2e` of such a test still exits 1. A marked test that passes now fails with a message saying the failure it expects is gone. The run index records `expectFail` on such runs.
84
+ - 4897ede: `lint` knows the functions a scenario defines, and checks a call wherever it stands.
85
+
86
+ - A function defined at the top level of a scenario file is a helper of that file: the run always called it, and `lint` now does not report it as `validator:unknown-function`. Helpers in `unotest/e2e/_helpers/` work as before.
87
+ - A call inside an options object or a helper's argument (`apiCall('POST', '/pages', {html: page_hmtl()})`) is checked like any other call, so a misspelt name there is an error at its line instead of a failure at run time.
88
+
89
+ **Migration:** a scenario with an unknown or misspelt function inside an object argument used to pass `lint` and now fails it. That call would have failed the run.
90
+
91
+ - 4897ede: A collection whose `prepare` failed on a box is no longer just `failed (exit 94)` under `bundle push --follow`: the line says the prepare failed and the suite did not run, and where its output is. The run itself is now written (a failed collection with no scenario), so `box run <id>` finds it and gives the same reason instead of "no such run".
92
+ - ab0fb14: `bundle push --follow` now reads tests marked `@expect-fail` the way a local run does: a marked test that fails prints `✓ <test> — failed on purpose (@expect-fail)`, and a marked test that passes prints `✗ <test> — passed, but it is marked @expect-fail`. Previously a control collection on a box streamed its expected failures as ordinary ones. The line that ends a failed scenario in `--follow` also uses the local run's words: `✗ login — failed` instead of `✗ login (failed)`. In a local run, a test of a multi-test file that failed on purpose now carries the same `(@expect-fail)` suffix as a single test. Run lines from a box carry a new optional `expectFail` field; older clients ignore it.
93
+ - 4897ede: `env push` / `env set`: a box that refuses a name of the run's identity (`UNOTEST_RUN_ID` and the rest) no longer gets the advice about `APP_BASE_URL`. The box's refusal now says which kind of name it reserved, under the same `reserved` code, so older CLIs still show the box's own words. A refusal code this CLI does not know is shown as the box worded it, with exit 1, instead of "not a box's answer".
94
+ - 4897ede: `lint` names a scenario the way `e2e` does.
95
+
96
+ - `lint values/string-escapes` checks `unotest/e2e/values/string-escapes.js`, as `e2e values/string-escapes` runs it. It used to fail with `ENOENT` and exit 1.
97
+ - A folder, which failed with `EISDIR`, checks every `.js` under it — as a path or as a feature folder name (`lint values`).
98
+ - A file path works as before; typed from inside the suite package (`cd unotest && lint e2e/values/numbers.js`) it means what it says there.
99
+ - A name that is not there exits 2 and prints where it was looked for, with the closest names, the same message `e2e` gives.
100
+
101
+ - 4897ede: A run paused on a failure (`e2e --debug`, an agent's `run_test`) with nobody attached is now aborted after 30 minutes without a client command, and frees the queue — the timeout existed but was restarted by the run reading its own state every few seconds, so it never ran out. Any debug command restarts it; reading the run's state does not. `UNOTEST_PAUSE_TTL_MS` sets the timeout, and the expiry line says how long it waited.
102
+ - 4897ede: The DSL reference shipped with the package now links `readJson` to the "App constants in scenarios" section on docs.unotest.com instead of naming a page the package does not contain.
103
+ - 4897ede: `skip(reason)` can be called anywhere in a test's body, including inside a step or an `if` block, so a test can skip itself on data an earlier step read. The rest of the test does not run, registered teardown blocks still play, and the run reports skipped with the reason. `lint:skip-outside-test` now reports only a `skip()` in a helper, a flow or at the top level of a file.
104
+ - 4897ede: The step a test skipped itself in now shows as skipped in the viewer, not as passed; the steps before it stay passed. The run journal marks that statement and its step block with an optional `skipped: true` next to `ok: true`, so readers that do not know the field see the same events as before.
105
+ - 4897ede: `getImageSize(loc)` reads an image's natural size without `evaluateOnLocator`.
106
+
107
+ - It returns `{width, height}` of the `<img>` file, or `null` when the image is broken or has no `src`. An image still loading is waited for up to the action timeout, so a good image is not read as broken.
108
+ - An element that is not an `<img>` fails with a `LocatorError` naming its tag; an inline `<svg>` is pointed to `boundingBox`. An image that never finishes loading fails with a `TimeoutError`; for a `loading="lazy"` one the message says to `scrollIntoView()` it first.
109
+ - It works inside iframes, cross-origin ones included.
110
+ - The `lint:evaluate-discouraged` hint now names `getImageSize` for images, and `count` / `assertCount` over `.filter({...})` for counting elements by text or by a child.
111
+ - The DSL reference shows how to count by a condition: `.filter({...})` for text or a child, a CSS `locator(...)` for the element's own class or attribute.
112
+
113
+ - 4897ede: Viewer tree:
114
+
115
+ - A collection file that does not parse no longer hides the others. The Collections section lists the valid collections and shows the broken file as its own row, with the parse error. Before, the whole section read "no collections match". Runs of the valid collections are not affected by a broken file next to them.
116
+ - The section footers show only keys that do something. `R` now runs the selected scenario headless, the same as "Run again", and is shown only where the viewer may run. `⌘K` focuses the filter in every section. Hints that had no handler are removed: arrows, `N` new collection, `O` open .zip, `⌃C` abort, `⌥` reveal secret.
117
+
118
+ - 4897ede: A run no longer hangs after a failed step on a page that stopped answering. After a failure the runner reads the page for the failure bundle (screenshot, HTML, semantic DOM, outline), and a page whose main thread is busy, such as a script in an endless loop, never answered those reads, in WebKit and Chromium alike. Each read now gets 15 seconds. The first that runs out ends the reading: the test stays red with its own error, the output adds `the page gave no answer within 15s after the failed step`, and the run's `failure/screenshot-error.txt` holds the same reason. Closing the browser context has the same limit.
119
+
120
+ Killing `unotest-web` outright (`kill -9`) now stops the run it started too, with its browser. Before, only SIGTERM, SIGINT and SIGHUP reached it, and the run went on with nobody left to stop it.
121
+
122
+ - Updated dependencies [4897ede]
123
+ - Updated dependencies [4897ede]
124
+ - Updated dependencies [de529ab]
125
+ - Updated dependencies [4897ede]
126
+ - Updated dependencies [4897ede]
127
+ - Updated dependencies [4897ede]
128
+ - Updated dependencies [4897ede]
129
+ - Updated dependencies [4897ede]
130
+ - Updated dependencies [4897ede]
131
+ - Updated dependencies [4897ede]
132
+ - Updated dependencies [4897ede]
133
+ - Updated dependencies [4897ede]
134
+ - Updated dependencies [ab0fb14]
135
+ - Updated dependencies [4897ede]
136
+ - Updated dependencies [4897ede]
137
+ - Updated dependencies [4897ede]
138
+ - @unotest/protocol@0.49.1
139
+ - @unotest/core@0.49.1
140
+ - @unotest/dsl@0.49.1
141
+ - @unotest/viewer@0.49.1
142
+ - @unotest/grounder-client@0.49.1
143
+
3
144
  ## [0.49.0] - 2026-10-09
4
145
 
5
146
  ### Minor Changes
@@ -1724,7 +1865,7 @@ picker on` fetches this project's own access and writes the three grounder
1724
1865
 
1725
1866
  That screen named one command:
1726
1867
 
1727
- npx @unotest/web bundle push --run --env ENVIRONMENT
1868
+ npx @unotest/web bundle push --run --env ENVIRONMENT
1728
1869
 
1729
1870
  In a project that has just been created, the command refuses with `no box
1730
1871
  address` before it does anything: the project holds neither the box's address
@@ -1733,8 +1874,8 @@ address` before it does anything: the project holds neither the box's address
1733
1874
 
1734
1875
  The screen now names both steps, in the order they have to happen:
1735
1876
 
1736
- npx @unotest/web box access larch
1737
- npx @unotest/web bundle push --run --env ENVIRONMENT
1877
+ npx @unotest/web box access larch
1878
+ npx @unotest/web bundle push --run --env ENVIRONMENT
1738
1879
 
1739
1880
  The box's own name is filled in when its licence carries one. `box access`
1740
1881
  with no name refuses, and its refusal offers to create a box — to somebody who
package/README.md CHANGED
@@ -29,15 +29,16 @@ overwrites your edits.
29
29
 
30
30
  It also wires editor typings (`unotest/jsconfig.json` + generated `.d.ts`
31
31
  files), so scenarios get autocomplete, hover docs and signature help in
32
- VS Code / WebStorm instead of red squiggles. On an existing project this
33
- self-installs on the first `lint` / `e2e` run after upgrading; refresh by
34
- hand with `npx @unotest/web types`. Details: the "Editor setup" section of
32
+ VS Code / WebStorm instead of red squiggles. On an existing project or a
33
+ fresh checkout, `npx @unotest/web types` writes them; a test run does not.
34
+ Details: the "Editor setup" section of
35
35
  `node_modules/@unotest/web/guides/dsl-reference.md`.
36
36
 
37
37
  Testing a browser extension? `launch` in `unotest.config` starts the browser
38
38
  with a profile (`userDataDir`) and extra arguments (`args`, e.g.
39
39
  `--load-extension=./ext`; Chromium only). On a profile every scenario shares
40
- one browser context — no isolation between them, and the run log says so.
40
+ one browser context — no isolation between them, and the run journal records
41
+ the profile.
41
42
  `profile: 'per-test'` instead gives every test a new browser on a new,
42
43
  empty profile: a suite of N files runs on N profiles.
43
44
 
@@ -52,6 +52,14 @@ const asksForHelp = args.some((a) => a === "--help" || a === "-h");
52
52
  // under src/. In published packages dist/ exists (built by prepublishOnly);
53
53
  // in a fresh clone we fall back to running TS sources via tsx so that
54
54
  // `unotest-web --help` works without an explicit `pnpm build` first.
55
+ const INIT_DIST = "dist/runner/init.js";
56
+
57
+ /** The cli dispatcher's route. It stops when this wrapper is gone, through
58
+ * an IPC channel (see the spawn below); the other entries are not told. */
59
+ function cliRoute(forwardArgs) {
60
+ return { dist: "dist/runner/cli.js", src: "src/runner/cli.ts", forwardArgs, followsParent: true };
61
+ }
62
+
55
63
  function dispatch(sub) {
56
64
  // A question is not a command. Every `--help` goes to the cli dispatcher
57
65
  // with the arguments untouched, whatever the route for that subcommand
@@ -60,19 +68,20 @@ function dispatch(sub) {
60
68
  // drops the flag and runs the command — `viewer --help` started a viewer
61
69
  // and scaffolded `unotest/` into the current directory.
62
70
  if (asksForHelp) {
63
- return { dist: "dist/runner/cli.js", src: "src/runner/cli.ts", forwardArgs: args };
71
+ return cliRoute(args);
64
72
  }
65
73
  switch (sub) {
66
74
  case "mcp":
67
75
  return { dist: "dist/mcp/server.js", src: "src/mcp/server.ts", forwardArgs: [] };
68
76
  case "e2e":
69
- return { dist: "dist/runner/cli.js", src: "src/runner/cli.ts", forwardArgs: args };
77
+ return cliRoute(args);
70
78
  case "init":
71
- return {
72
- dist: "dist/runner/init.js",
73
- src: "src/runner/init.ts",
74
- forwardArgs: args.slice(1),
75
- };
79
+ // Built: imported and called in this process (see below). Without
80
+ // dist/ the cli dispatches it under tsx — init.ts runs nothing on
81
+ // import, so it is never an entry of its own.
82
+ return existsSync(resolve(root, INIT_DIST))
83
+ ? { dist: INIT_DIST, src: "src/runner/init.ts", forwardArgs: args.slice(1) }
84
+ : cliRoute(args);
76
85
  case "install-chromium":
77
86
  return {
78
87
  dist: "dist/runner/install-chromium.js",
@@ -88,9 +97,9 @@ function dispatch(sub) {
88
97
  case "lint":
89
98
  // Forwarded whole, like e2e: `--env <name>` and explicit file
90
99
  // arguments belong to the command, not to the dispatcher.
91
- return { dist: "dist/runner/cli.js", src: "src/runner/cli.ts", forwardArgs: args };
100
+ return cliRoute(args);
92
101
  case "viewer":
93
- return { dist: "dist/runner/cli.js", src: "src/runner/cli.ts", forwardArgs: ["viewer"] };
102
+ return cliRoute(["viewer"]);
94
103
  case "prepare-fix":
95
104
  return {
96
105
  dist: "dist/runner/prepare-fix.js",
@@ -100,26 +109,24 @@ function dispatch(sub) {
100
109
  case "--help":
101
110
  case "-h":
102
111
  case "--version":
103
- return { dist: "dist/runner/cli.js", src: "src/runner/cli.ts", forwardArgs: args };
112
+ return cliRoute(args);
104
113
  default:
105
114
  if (sub === undefined) {
106
115
  return { dist: "dist/mcp/server.js", src: "src/mcp/server.ts", forwardArgs: [] };
107
116
  }
108
- return { dist: "dist/runner/cli.js", src: "src/runner/cli.ts", forwardArgs: args };
117
+ return cliRoute(args);
109
118
  }
110
119
  }
111
120
 
112
- const { dist, src, forwardArgs } = dispatch(sub);
121
+ const { dist, src, forwardArgs, followsParent = false } = dispatch(sub);
113
122
  const distPath = resolve(root, dist);
114
123
 
115
124
  // Init is interactive (browser prompt) — running it via spawn through
116
125
  // npx loses the prompt suffix mid-flush on some shells (Claude Code's
117
126
  // REPL, nvm shim variants). Direct import keeps stdio attached to the
118
127
  // real TTY without a spawn hop. We import the compiled module and call
119
- // `runInit` directly so we can await its promise — the module's own
120
- // self-invoke `if (invokedDirectly)` block fires only when bin spawns
121
- // a child, which we explicitly skip here.
122
- if (sub === "init" && !asksForHelp && existsSync(distPath)) {
128
+ // `runInit` directly so we can await its promise.
129
+ if (dist === INIT_DIST) {
123
130
  const initModule = await import(pathToFileURL(distPath).href);
124
131
  try {
125
132
  const { exitCode } = await initModule.runInit(forwardArgs);
@@ -138,9 +145,13 @@ if (sub === "init" && !asksForHelp && existsSync(distPath)) {
138
145
  // when dist/ is absent (fresh clone without `pnpm build`).
139
146
  let cmd = process.execPath;
140
147
  let cmdArgs;
148
+ // Only a cli started directly can hold the channel: under tsx it would be
149
+ // tsx's, not the cli's.
150
+ let linkParent = false;
141
151
  if (existsSync(distPath)) {
142
152
  // Published / built path — run compiled JS directly.
143
153
  cmdArgs = [distPath, ...forwardArgs];
154
+ linkParent = followsParent;
144
155
  } else {
145
156
  const srcPath = resolve(root, src);
146
157
  const haveSrc = existsSync(srcPath);
@@ -170,7 +181,13 @@ if (existsSync(distPath)) {
170
181
  cmdArgs = [tsxCliPath, entryForTsx, ...forwardArgs];
171
182
  }
172
183
 
173
- const child = spawn(cmd, cmdArgs, { stdio: "inherit" });
184
+ // The cli gets an IPC channel beside the inherited stdio — fd 3, so stdin
185
+ // and stdout stay the caller's. `kill -9` on this wrapper forwards nothing;
186
+ // the channel closing is how the cli learns its parent is gone, and it
187
+ // stops then as it would on the SIGTERM forwarded below (#378).
188
+ const child = spawn(cmd, cmdArgs, {
189
+ stdio: linkParent ? ["inherit", "inherit", "inherit", "ipc"] : "inherit",
190
+ });
174
191
 
175
192
  // Pass termination on to the child. This dispatcher is a thin wrapper: kill
176
193
  // IT and the real process — the viewer server, a running scenario — has to
@@ -116,19 +116,19 @@ declare const FailureBundleConfigSchema: z.ZodObject<{
116
116
  type FailureBundleConfig = z.infer<typeof FailureBundleConfigSchema>;
117
117
  declare const DialogPolicySchema: z.ZodEnum<["accept", "dismiss", "manual"]>;
118
118
  type DialogPolicy = z.infer<typeof DialogPolicySchema>;
119
- declare const LinterRuleIdSchema: z.ZodEnum<["lint:deep-css", "lint:xpath", "lint:obfuscated-class", "lint:pause-explicit", "lint:disambig-by-index", "lint:evaluate-discouraged", "lint:scenario-in-root", "lint:mustache-in-dsl", "lint:goto-concat", "lint:regex-invalid", "lint:echo-assert", "lint:api-call-file-body", "lint:lint-ok-missing-reason", "lint:flow-returns-value", "lint:legacy-layout", "lint:external-variable-undeclared", "lint:env-host-from-base", "lint:one-test-per-file", "lint:shadows-dsl-function", "lint:skip-outside-test", "lint:set-test-timeout-outside-test", "lint:filter-unknown-option", "validator:unknown-function", "validator:arity", "validator:arg-kind", "validator:step-coverage", "validator:step-shape", "validator:meta-shape", "validator:function-shape", "validator:for-shape", "validator:if-shape", "validator:var-shape", "validator:unsupported-statement", "validator:unsupported-expression", "validator:string-concat", "validator:semantic-loss", "validator:list-arg", "validator:wrapped-format"]>;
119
+ declare const LinterRuleIdSchema: z.ZodEnum<["lint:deep-css", "lint:xpath", "lint:obfuscated-class", "lint:pause-explicit", "lint:disambig-by-index", "lint:evaluate-discouraged", "lint:scenario-in-root", "lint:mustache-in-dsl", "lint:goto-concat", "lint:regex-invalid", "lint:echo-assert", "lint:api-call-file-body", "lint:lint-ok-missing-reason", "lint:flow-returns-value", "lint:legacy-layout", "lint:external-variable-undeclared", "lint:env-host-from-base", "lint:one-test-per-file", "lint:shadows-dsl-function", "lint:skip-outside-test", "lint:set-test-timeout-outside-test", "lint:filter-unknown-option", "lint:role-unknown-option", "validator:unknown-function", "validator:arity", "validator:arg-kind", "validator:step-coverage", "validator:step-shape", "validator:meta-shape", "validator:function-shape", "validator:for-shape", "validator:if-shape", "validator:var-shape", "validator:unsupported-statement", "validator:unsupported-expression", "validator:string-concat", "validator:semantic-loss", "validator:list-arg", "validator:wrapped-format"]>;
120
120
  type LinterRuleId = z.infer<typeof LinterRuleIdSchema>;
121
121
  declare const LinterSeveritySchema: z.ZodEnum<["off", "warn", "error"]>;
122
122
  type LinterSeverity = z.infer<typeof LinterSeveritySchema>;
123
123
  declare const LinterConfigSchema: z.ZodObject<{
124
124
  enabled: z.ZodBoolean;
125
- rules: z.ZodRecord<z.ZodEnum<["lint:deep-css", "lint:xpath", "lint:obfuscated-class", "lint:pause-explicit", "lint:disambig-by-index", "lint:evaluate-discouraged", "lint:scenario-in-root", "lint:mustache-in-dsl", "lint:goto-concat", "lint:regex-invalid", "lint:echo-assert", "lint:api-call-file-body", "lint:lint-ok-missing-reason", "lint:flow-returns-value", "lint:legacy-layout", "lint:external-variable-undeclared", "lint:env-host-from-base", "lint:one-test-per-file", "lint:shadows-dsl-function", "lint:skip-outside-test", "lint:set-test-timeout-outside-test", "lint:filter-unknown-option", "validator:unknown-function", "validator:arity", "validator:arg-kind", "validator:step-coverage", "validator:step-shape", "validator:meta-shape", "validator:function-shape", "validator:for-shape", "validator:if-shape", "validator:var-shape", "validator:unsupported-statement", "validator:unsupported-expression", "validator:string-concat", "validator:semantic-loss", "validator:list-arg", "validator:wrapped-format"]>, z.ZodEnum<["off", "warn", "error"]>>;
125
+ rules: z.ZodRecord<z.ZodEnum<["lint:deep-css", "lint:xpath", "lint:obfuscated-class", "lint:pause-explicit", "lint:disambig-by-index", "lint:evaluate-discouraged", "lint:scenario-in-root", "lint:mustache-in-dsl", "lint:goto-concat", "lint:regex-invalid", "lint:echo-assert", "lint:api-call-file-body", "lint:lint-ok-missing-reason", "lint:flow-returns-value", "lint:legacy-layout", "lint:external-variable-undeclared", "lint:env-host-from-base", "lint:one-test-per-file", "lint:shadows-dsl-function", "lint:skip-outside-test", "lint:set-test-timeout-outside-test", "lint:filter-unknown-option", "lint:role-unknown-option", "validator:unknown-function", "validator:arity", "validator:arg-kind", "validator:step-coverage", "validator:step-shape", "validator:meta-shape", "validator:function-shape", "validator:for-shape", "validator:if-shape", "validator:var-shape", "validator:unsupported-statement", "validator:unsupported-expression", "validator:string-concat", "validator:semantic-loss", "validator:list-arg", "validator:wrapped-format"]>, z.ZodEnum<["off", "warn", "error"]>>;
126
126
  }, "strict", z.ZodTypeAny, {
127
127
  enabled: boolean;
128
- rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
128
+ rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "lint:role-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
129
129
  }, {
130
130
  enabled: boolean;
131
- rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
131
+ rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "lint:role-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
132
132
  }>;
133
133
  type LinterConfig = z.infer<typeof LinterConfigSchema>;
134
134
  declare const QueueConfigSchema: z.ZodObject<{
@@ -620,13 +620,13 @@ declare const UnotestConfigSchema: z.ZodEffects<z.ZodObject<{
620
620
  }>;
621
621
  linter: z.ZodObject<{
622
622
  enabled: z.ZodBoolean;
623
- rules: z.ZodRecord<z.ZodEnum<["lint:deep-css", "lint:xpath", "lint:obfuscated-class", "lint:pause-explicit", "lint:disambig-by-index", "lint:evaluate-discouraged", "lint:scenario-in-root", "lint:mustache-in-dsl", "lint:goto-concat", "lint:regex-invalid", "lint:echo-assert", "lint:api-call-file-body", "lint:lint-ok-missing-reason", "lint:flow-returns-value", "lint:legacy-layout", "lint:external-variable-undeclared", "lint:env-host-from-base", "lint:one-test-per-file", "lint:shadows-dsl-function", "lint:skip-outside-test", "lint:set-test-timeout-outside-test", "lint:filter-unknown-option", "validator:unknown-function", "validator:arity", "validator:arg-kind", "validator:step-coverage", "validator:step-shape", "validator:meta-shape", "validator:function-shape", "validator:for-shape", "validator:if-shape", "validator:var-shape", "validator:unsupported-statement", "validator:unsupported-expression", "validator:string-concat", "validator:semantic-loss", "validator:list-arg", "validator:wrapped-format"]>, z.ZodEnum<["off", "warn", "error"]>>;
623
+ rules: z.ZodRecord<z.ZodEnum<["lint:deep-css", "lint:xpath", "lint:obfuscated-class", "lint:pause-explicit", "lint:disambig-by-index", "lint:evaluate-discouraged", "lint:scenario-in-root", "lint:mustache-in-dsl", "lint:goto-concat", "lint:regex-invalid", "lint:echo-assert", "lint:api-call-file-body", "lint:lint-ok-missing-reason", "lint:flow-returns-value", "lint:legacy-layout", "lint:external-variable-undeclared", "lint:env-host-from-base", "lint:one-test-per-file", "lint:shadows-dsl-function", "lint:skip-outside-test", "lint:set-test-timeout-outside-test", "lint:filter-unknown-option", "lint:role-unknown-option", "validator:unknown-function", "validator:arity", "validator:arg-kind", "validator:step-coverage", "validator:step-shape", "validator:meta-shape", "validator:function-shape", "validator:for-shape", "validator:if-shape", "validator:var-shape", "validator:unsupported-statement", "validator:unsupported-expression", "validator:string-concat", "validator:semantic-loss", "validator:list-arg", "validator:wrapped-format"]>, z.ZodEnum<["off", "warn", "error"]>>;
624
624
  }, "strict", z.ZodTypeAny, {
625
625
  enabled: boolean;
626
- rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
626
+ rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "lint:role-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
627
627
  }, {
628
628
  enabled: boolean;
629
- rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
629
+ rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "lint:role-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
630
630
  }>;
631
631
  mcp: z.ZodObject<{
632
632
  transport: z.ZodLiteral<"stdio">;
@@ -755,7 +755,7 @@ declare const UnotestConfigSchema: z.ZodEffects<z.ZodObject<{
755
755
  defaultNavigationTimeoutMs: number;
756
756
  linter: {
757
757
  enabled: boolean;
758
- rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
758
+ rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "lint:role-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
759
759
  };
760
760
  mcp: {
761
761
  transport: "stdio";
@@ -835,7 +835,7 @@ declare const UnotestConfigSchema: z.ZodEffects<z.ZodObject<{
835
835
  defaultNavigationTimeoutMs: number;
836
836
  linter: {
837
837
  enabled: boolean;
838
- rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
838
+ rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "lint:role-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
839
839
  };
840
840
  mcp: {
841
841
  transport: "stdio";
@@ -920,7 +920,7 @@ declare const UnotestConfigSchema: z.ZodEffects<z.ZodObject<{
920
920
  defaultNavigationTimeoutMs: number;
921
921
  linter: {
922
922
  enabled: boolean;
923
- rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
923
+ rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "lint:role-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
924
924
  };
925
925
  mcp: {
926
926
  transport: "stdio";
@@ -1000,7 +1000,7 @@ declare const UnotestConfigSchema: z.ZodEffects<z.ZodObject<{
1000
1000
  defaultNavigationTimeoutMs: number;
1001
1001
  linter: {
1002
1002
  enabled: boolean;
1003
- rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
1003
+ rules: Partial<Record<"lint:deep-css" | "lint:xpath" | "lint:obfuscated-class" | "lint:pause-explicit" | "lint:disambig-by-index" | "lint:evaluate-discouraged" | "lint:scenario-in-root" | "lint:mustache-in-dsl" | "lint:goto-concat" | "lint:regex-invalid" | "lint:echo-assert" | "lint:api-call-file-body" | "lint:lint-ok-missing-reason" | "lint:flow-returns-value" | "lint:legacy-layout" | "lint:external-variable-undeclared" | "lint:env-host-from-base" | "lint:one-test-per-file" | "lint:shadows-dsl-function" | "lint:skip-outside-test" | "lint:set-test-timeout-outside-test" | "lint:filter-unknown-option" | "lint:role-unknown-option" | "validator:unknown-function" | "validator:arity" | "validator:arg-kind" | "validator:step-coverage" | "validator:step-shape" | "validator:meta-shape" | "validator:function-shape" | "validator:for-shape" | "validator:if-shape" | "validator:var-shape" | "validator:unsupported-statement" | "validator:unsupported-expression" | "validator:string-concat" | "validator:semantic-loss" | "validator:list-arg" | "validator:wrapped-format", "off" | "warn" | "error">>;
1004
1004
  };
1005
1005
  mcp: {
1006
1006
  transport: "stdio";
@@ -1 +1 @@
1
- var _0x19cd0a=_0x65ae;(function(_0xdbced1,_0x23f9d8){var _0x171c5b={_0x429bff:0x190,_0x31effb:0x191,_0x13ccee:0x189,_0x5c0a71:0x184,_0x429d0d:0x174,_0x1d763c:0x169,_0x4705d4:0x135},_0x3715db=_0x65ae,_0x1f5c29=_0xdbced1();while(!![]){try{var _0x4d5665=parseInt(_0x3715db(_0x171c5b._0x429bff))/0x1+parseInt(_0x3715db(_0x171c5b._0x31effb))/0x2*(-parseInt(_0x3715db(0x166))/0x3)+parseInt(_0x3715db(0x17c))/0x4+-parseInt(_0x3715db(_0x171c5b._0x13ccee))/0x5*(-parseInt(_0x3715db(_0x171c5b._0x5c0a71))/0x6)+-parseInt(_0x3715db(0x197))/0x7+-parseInt(_0x3715db(_0x171c5b._0x429d0d))/0x8*(parseInt(_0x3715db(_0x171c5b._0x1d763c))/0x9)+parseInt(_0x3715db(_0x171c5b._0x4705d4))/0xa;if(_0x4d5665===_0x23f9d8)break;else _0x1f5c29['push'](_0x1f5c29['shift']());}catch(_0x361008){_0x1f5c29['push'](_0x1f5c29['shift']());}}}(_0x2333,0xea7f8));var __defProp=Object[_0x19cd0a(0x15f)],__name=(_0x13e14e,_0x57db14)=>__defProp(_0x13e14e,_0x19cd0a(0x187),{'value':_0x57db14,'configurable':!![]});import{z as _0xe0606c}from'zod';import{z}from'zod';import{levenshteinDistance}from'@unotest/core';function _0x65ae(_0x80fc18,_0x237347){_0x80fc18=_0x80fc18-0x135;var _0x2333dc=_0x2333();var _0x65ae8c=_0x2333dc[_0x80fc18];if(_0x65ae['YcneSr']===undefined){var _0x53c653=function(_0x4b3652){var _0x145cdd='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0xe0606c='',_0x492223='';for(var _0x13e14e=0x0,_0x57db14,_0x64d817,_0x3b8242=0x0;_0x64d817=_0x4b3652['charAt'](_0x3b8242++);~_0x64d817&&(_0x57db14=_0x13e14e%0x4?_0x57db14*0x40+_0x64d817:_0x64d817,_0x13e14e++%0x4)?_0xe0606c+=String['fromCharCode'](0xff&_0x57db14>>(-0x2*_0x13e14e&0x6)):0x0){_0x64d817=_0x145cdd['indexOf'](_0x64d817);}for(var _0x5a6973=0x0,_0x450775=_0xe0606c['length'];_0x5a6973<_0x450775;_0x5a6973++){_0x492223+='%'+('00'+_0xe0606c['charCodeAt'](_0x5a6973)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x492223);};_0x65ae['tIvdFm']=_0x53c653,_0x65ae['ohnIWg']={},_0x65ae['YcneSr']=!![];}var _0x3367cc=_0x2333dc[0x0],_0x151d05=_0x80fc18+_0x3367cc,_0x51d820=_0x65ae['ohnIWg'][_0x151d05];return!_0x51d820?(_0x65ae8c=_0x65ae['tIvdFm'](_0x65ae8c),_0x65ae['ohnIWg'][_0x151d05]=_0x65ae8c):_0x65ae8c=_0x51d820,_0x65ae8c;}var MAX_EDITS=0x2;function closestKey(_0x64d817,_0x3b8242){var _0x165bb9={_0x5c62f2:0x16b,_0x957827:0x15e},_0x2a1dfb=_0x19cd0a;let _0x5a6973;for(const _0x450775 of _0x3b8242){const _0x55c3c7=levenshteinDistance(_0x64d817[_0x2a1dfb(_0x165bb9._0x5c62f2)](),_0x450775['toLowerCase']());if(_0x55c3c7>MAX_EDITS)continue;if(_0x5a6973===void 0x0||_0x55c3c7<_0x5a6973['distance'])_0x5a6973={'key':_0x450775,'distance':_0x55c3c7};}return _0x5a6973?.[_0x2a1dfb(_0x165bb9._0x957827)];}__name(closestKey,_0x19cd0a(0x164));function unknownKeyMessage(_0x1b850b,_0x40610c){var _0x211669={_0x33aa79:0x19a},_0x7db88e=_0x19cd0a;return _0x1b850b[_0x7db88e(_0x211669._0x33aa79)](_0x4914f7=>{var _0x33a10f=_0x7db88e;const _0x503d53=closestKey(_0x4914f7,_0x40610c);return _0x503d53===void 0x0?'unknown\x20key\x20\x22'+_0x4914f7+'\x22\x20—\x20not\x20a\x20config\x20key;\x20check\x20your\x20@unotest/web\x20version\x20if\x20it\x20comes\x20from\x20a\x20newer\x20release':_0x33a10f(0x185)+_0x4914f7+_0x33a10f(0x148)+_0x503d53+'\x22?';})[_0x7db88e(0x18e)](';\x20');}__name(unknownKeyMessage,'unknownKeyMessage');function strictObject(_0x3387d5){var _0x4225d8={_0x14de1e:0x138,_0x227bdd:0x1a1},_0x1e4120=_0x19cd0a;const _0x1623d0=Object[_0x1e4120(_0x4225d8._0x14de1e)](_0x3387d5);return z['object'](_0x3387d5,{'errorMap':__name((_0x11206d,_0xe298f1)=>_0x11206d['code']===z[_0x1e4120(0x177)][_0x1e4120(0x162)]?{'message':unknownKeyMessage(_0x11206d[_0x1e4120(0x138)],_0x1623d0)}:{'message':_0xe298f1['defaultError']},_0x1e4120(_0x4225d8._0x227bdd))})[_0x1e4120(0x186)]();}__name(strictObject,_0x19cd0a(0x149));import{BUNDLED_BROWSER_CHANNEL}from'@unotest/protocol';import{z as _0x492223}from'zod';import{UnotestError}from'@unotest/core';var LaunchConfigSchema=_0x492223[_0x19cd0a(0x158)]({'userDataDir':_0x492223[_0x19cd0a(0x15c)]()[_0x19cd0a(0x176)](0x1)[_0x19cd0a(0x1a0)](),'profile':_0x492223[_0x19cd0a(0x1a2)](_0x19cd0a(0x15d))[_0x19cd0a(0x1a0)](),'args':_0x492223[_0x19cd0a(0x199)](_0x492223[_0x19cd0a(0x15c)]()['min'](0x1))[_0x19cd0a(0x1a0)]()})[_0x19cd0a(0x186)](),BrowserSchema=_0xe0606c[_0x19cd0a(0x18f)]([_0x19cd0a(0x136),_0x19cd0a(0x165),_0x19cd0a(0x157)]),SYSTEM_BROWSER_CHANNELS=[_0x19cd0a(0x144),_0x19cd0a(0x17a),_0x19cd0a(0x16a),_0x19cd0a(0x136)],BROWSER_CHANNEL_WORDS=[...SYSTEM_BROWSER_CHANNELS,BUNDLED_BROWSER_CHANNEL],BrowserChannelSchema=_0xe0606c['union']([_0xe0606c[_0x19cd0a(0x18f)](SYSTEM_BROWSER_CHANNELS),_0xe0606c[_0x19cd0a(0x1a2)](BUNDLED_BROWSER_CHANNEL)[_0x19cd0a(0x188)](()=>null),_0xe0606c[_0x19cd0a(0x19f)]()])[_0x19cd0a(0x1a0)](),ViewportSchema=strictObject({'width':_0xe0606c[_0x19cd0a(0x142)]()[_0x19cd0a(0x182)]()['positive']()[_0x19cd0a(0x1a0)](),'height':_0xe0606c[_0x19cd0a(0x142)]()['int']()[_0x19cd0a(0x14f)]()[_0x19cd0a(0x1a0)](),'deviceScaleFactor':_0xe0606c['number']()[_0x19cd0a(0x14f)]()['optional']()}),ConfigViewportSchema=ViewportSchema['nullable']();function viewportDeviceConflict(_0x1792d7,_0x2b10d4,_0x5a134f=_0x19cd0a(0x180)){var _0x54a83f={_0x3c5356:0x1a3,_0x5a60df:0x139},_0x130145=_0x19cd0a;if(_0x1792d7!==null||_0x2b10d4===void 0x0)return void 0x0;return _0x5a134f+_0x130145(_0x54a83f._0x3c5356)+_0x2b10d4+_0x130145(_0x54a83f._0x5a60df);}function _0x2333(){var _0x41b60b=['BMfTzq','DhjHBNnMB3jT','nJK5mZi2meLPv1PHuq','DMfSAwrHDg9YoNvUA25VD24TzNvUy3rPB24','BgLUDdP4Cgf0Aa','BgLUDdPVBMuTDgvZDc1WzxiTzMLSzq','BgLUDdPZzxqTDgvZDc10Aw1LB3v0lw91DhnPzguTDgvZDa','AM9PBG','zw51Bq','odKZmdC2rwHSrxv2','mtu4mdzIELH6qwi','zM9YrwfJAa','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlxn0yxrLBwvUDa','BgLUDdPNB3rVlwnVBMnHDa','iIdIGjqGzxHWzwn0zwqGysbcq1aGndCGDgfNihn1y2GGyxmGiMvZluvtiG','AxnbCNjHEq','mtmXmdyWndrtq0zAzNu','BwfUDwfS','yxjYyxK','BwfW','z2v0q2fUB25Py2fStg9JywXLCW','xs51CMWG','Dw5VDgvZDc9LmMuVx2HLBhbLCNm','BgLUDdPZAgfKB3DZlwrZBc1MDw5JDgLVBG','BNvSBa','B3b0Aw9UywW','zxjYB3jnyxa','BgL0zxjHBa','igTLzxbZihrOzsbYzwfSigjYB3DZzxiGD2LUzg93lcbHBMqGzgv2AwnLici','BgLUDdPLDMfSDwf0zs1KAxnJB3vYywDLza','CMvMAw5L','mteYnde3mdbUv0DguvO','y2HYB21PDw0','BgLUDdPMAwX0zxiTDw5RBM93BI1VChrPB24','A2v5CW','iIbZzxrZigL0CYbVD24GC2L6zsbHBMqGC2nHBguG4OcuigrYB3aGB25Lig9MihrOzw0U','rgf0zvrPBwvgB3jTyxq','C3rKAw8','DMfSAwrHDg9YoNn0CMLUzY1JB25Jyxq','DMfSAwrHDg9YoMzVCI1ZAgfWzq','y3jHC2G','DMfSAwrHDg9YoMfYAxr5','BgLUDdPWyxvZzs1LEhbSAwnPDa','DMfSAwrHDg9YoNnLBwfUDgLJlwXVC3m','BNvTyMvY','zgvMyxvSDa','y2HYB21L','BgvUz3rO','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlwv4ChjLC3nPB24','AxnuAw1LwM9Uzq','iIdIGjqGzgLKihLVDsbTzwfUici','C3rYAwn0t2jQzwn0','Dw5PB24','AgfZ','DMfSAwrHDg9YoNn0zxaTC2HHCgu','BgLUDdPKAxnHBwjPzY1IEs1PBMrLEa','BgLUDdPKzwvWlwnZCW','Cg9ZAxrPDMu','BgLUDdPLEhrLCM5HBc12yxjPywjSzs11BMrLy2XHCMvK','D2fYBG','DMfSAwrHDg9YoNDYyxbWzwqTzM9YBwf0','y3vZDg9T','BgLUDdPLy2HVlwfZC2vYDa','DxjS','ywnJzxb0','D2vIA2L0','B2jQzwn0','DMLLD3bVCNq','zw4Tvvm','zgLZBwLZCW','C3rYAw5N','CgvYlxrLC3q','A2v5','zgvMAw5LuhjVCgvYDhK','BgLUDdPSAw50lw9Rlw1PC3nPBMCTCMvHC29U','zxjYB3i','Dw5YzwnVz25PEMvKx2TLExm','DMfSAwrHDg9YoMz1BMn0Aw9UlxnOyxbL','y2XVC2vZDeTLEq','zMLYzwzVEa','mJm3CvLevwDX','BgLUDdPVyMz1C2nHDgvKlwnSyxnZ','DMfSAwrHDg9YoNn0zxaTy292zxjHz2u','mZq4ndq0uLrjy1zT','y2HYB21LlwjLDge','Dg9mB3DLCKnHC2u','AxnmB2nHBgu','BgLUDdPMBg93lxjLDhvYBNmTDMfSDwu','BgLUDdPLBNyTAg9ZDc1MCM9TlwjHC2u','zNvSBa','DMfSAwrHDg9YoMLMlxnOyxbL','BMv0D29YAW','B2zM','yM9VBgvHBG','mJqWruvgyNfb','ywrKsxnZDwu','BwLU','wM9KsxnZDwvdB2rL','Dw5RBM93BIb0Aw1LihPVBMuGiG','BgLUDdPZA2LWlw91DhnPzguTDgvZDa','BxnLzgDL','CMvKywn0zwq','ndGXmdG2meTgCxHxsW','igLZigfSCMvHzhKGyw5VDgHLCIbZzxj2zxiNCYdIGjqGzwfJAcbZzxj2zxiGBMvLzhmGAxrZig93BIbYzwfKAw5LC3mGvvjmlG','iIdIGjqGzxHWzwn0zwqGyw4GsufoqsbUyw1Lihn1y2GGyxmGiKv1CM9Wzs9nywrYAwqI','C3vWzxjszwzPBMu','DMLLD3bVCNq6ig51BgW','BgLUDdPSzwDHy3KTBgf5B3v0','Aw50','BgLUDdPTDxn0ywnOzs1PBI1KC2W','nKDhCePota','Dw5RBM93BIbRzxKGiG','C3rYAwn0'];_0x2333=function(){return _0x41b60b;};return _0x2333();}__name(viewportDeviceConflict,'viewportDeviceConflict');var RetryReasonSchema=_0xe0606c['enum'](['transient',_0x19cd0a(0x171),_0x19cd0a(0x13e)]),RetryConfigSchema=strictObject({'count':_0xe0606c[_0x19cd0a(0x142)]()['int']()[_0x19cd0a(0x176)](0x0)['max'](0xa),'on':_0xe0606c[_0x19cd0a(0x199)](RetryReasonSchema)}),FailureBundleConfigSchema=strictObject({'tier1':_0xe0606c[_0x19cd0a(0x1a2)](!![])[_0x19cd0a(0x143)](!![]),'tier2':_0xe0606c['boolean'](),'tier3':strictObject({'network':_0xe0606c[_0x19cd0a(0x173)](),'video':_0xe0606c['boolean']()}),'retention':strictObject({'runs':_0xe0606c[_0x19cd0a(0x142)]()[_0x19cd0a(0x182)]()[_0x19cd0a(0x14f)](),'days':_0xe0606c[_0x19cd0a(0x142)]()[_0x19cd0a(0x182)]()[_0x19cd0a(0x14f)]()}),'storageDir':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x176)](0x1),'pageHtml':_0xe0606c['enum'](['redacted',_0x19cd0a(0x16f)])}),DialogPolicySchema=_0xe0606c[_0x19cd0a(0x18f)]([_0x19cd0a(0x156),_0x19cd0a(0x15b),_0x19cd0a(0x198)]),LinterRuleIdSchema=_0xe0606c[_0x19cd0a(0x18f)]([_0x19cd0a(0x14e),_0x19cd0a(0x18b),_0x19cd0a(0x167),_0x19cd0a(0x140),_0x19cd0a(0x14d),_0x19cd0a(0x1a4),'lint:scenario-in-root',_0x19cd0a(0x183),_0x19cd0a(0x194),'lint:regex-invalid',_0x19cd0a(0x154),'lint:api-call-file-body',_0x19cd0a(0x160),_0x19cd0a(0x16d),_0x19cd0a(0x181),_0x19cd0a(0x150),_0x19cd0a(0x16e),_0x19cd0a(0x18c),_0x19cd0a(0x19e),_0x19cd0a(0x179),_0x19cd0a(0x18d),_0x19cd0a(0x137),_0x19cd0a(0x18a),_0x19cd0a(0x13f),'validator:arg-kind',_0x19cd0a(0x168),_0x19cd0a(0x14c),'validator:meta-shape',_0x19cd0a(0x163),_0x19cd0a(0x13d),_0x19cd0a(0x170),'validator:var-shape',_0x19cd0a(0x193),_0x19cd0a(0x146),_0x19cd0a(0x13c),_0x19cd0a(0x141),'validator:list-arg',_0x19cd0a(0x152)]),LinterSeveritySchema=_0xe0606c[_0x19cd0a(0x18f)](['off','warn',_0x19cd0a(0x161)]),LinterConfigSchema=strictObject({'enabled':_0xe0606c[_0x19cd0a(0x173)](),'rules':_0xe0606c['record'](LinterRuleIdSchema,LinterSeveritySchema)}),QueueConfigSchema=strictObject({'enabled':_0xe0606c[_0x19cd0a(0x173)]()[_0x19cd0a(0x143)](!![]),'concurrency':_0xe0606c['number']()[_0x19cd0a(0x182)]()[_0x19cd0a(0x14f)]()[_0x19cd0a(0x143)](0x1)}),ScheduleSchema=strictObject({'collection':_0xe0606c[_0x19cd0a(0x15c)]()['min'](0x1),'cron':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x176)](0x1),'env':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x176)](0x1)['optional'](),'prepare':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x176)](0x1)[_0x19cd0a(0x1a0)]()}),McpConfigSchema=strictObject({'transport':_0xe0606c['literal'](_0x19cd0a(0x13b))}),SandboxConfigSchema=strictObject({'shellCwd':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x1a0)](),'shellTimeoutMs':_0xe0606c[_0x19cd0a(0x142)]()['int']()['positive']()[_0x19cd0a(0x1a0)](),'exportSecrets':_0xe0606c[_0x19cd0a(0x199)](_0xe0606c['string']())[_0x19cd0a(0x1a0)](),'database':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x1a0)](),'apiBaseUrl':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x155)]()[_0x19cd0a(0x1a0)](),'uploadDir':_0xe0606c[_0x19cd0a(0x15c)]()['optional'](),'readRoots':_0xe0606c[_0x19cd0a(0x199)](_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x176)](0x1))[_0x19cd0a(0x1a0)]()}),WebServerConfigSchema=strictObject({'command':_0xe0606c['string']()[_0x19cd0a(0x176)](0x1),'url':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x155)](),'reuseExistingServer':_0xe0606c[_0x19cd0a(0x173)]()[_0x19cd0a(0x143)](!![]),'timeoutMs':_0xe0606c[_0x19cd0a(0x142)]()[_0x19cd0a(0x182)]()[_0x19cd0a(0x14f)]()[_0x19cd0a(0x143)](0xea60)}),WebServersConfigSchema=_0xe0606c[_0x19cd0a(0x14a)]([WebServerConfigSchema,_0xe0606c[_0x19cd0a(0x199)](WebServerConfigSchema)[_0x19cd0a(0x176)](0x1)])[_0x19cd0a(0x188)](_0x45d9df=>Array[_0x19cd0a(0x196)](_0x45d9df)?_0x45d9df:[_0x45d9df])[_0x19cd0a(0x17f)]((_0x27043e,_0x42bb04)=>{var _0x3bbb79={_0x2d6454:0x14b,_0x331e9a:0x175,_0x16ab51:0x177,_0x468a6f:0x155},_0x49c68a=_0x19cd0a;const _0x3f70b6=new Set();_0x27043e[_0x49c68a(0x192)]((_0x2a7caf,_0xe4ea15)=>{var _0x473d35=_0x49c68a;_0x3f70b6[_0x473d35(_0x3bbb79._0x2d6454)](_0x2a7caf[_0x473d35(0x155)])&&_0x42bb04[_0x473d35(_0x3bbb79._0x331e9a)]({'code':_0xe0606c[_0x473d35(_0x3bbb79._0x16ab51)][_0x473d35(0x153)],'path':[_0xe4ea15,_0x473d35(0x155)],'message':'webServer['+_0xe4ea15+_0x473d35(0x19c)+_0x2a7caf[_0x473d35(_0x3bbb79._0x468a6f)]+_0x473d35(0x17d)}),_0x3f70b6['add'](_0x2a7caf['url']);});}),EnvConfigSchema=strictObject({'shared':_0xe0606c[_0x19cd0a(0x199)](_0xe0606c[_0x19cd0a(0x15c)]())[_0x19cd0a(0x143)]([])}),UnotestConfigSchema=strictObject({'baseUrl':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x155)]()['optional'](),'webServer':WebServersConfigSchema[_0x19cd0a(0x1a0)](),'generate':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x176)](0x1)[_0x19cd0a(0x1a0)](),'browsers':_0xe0606c[_0x19cd0a(0x199)](BrowserSchema)[_0x19cd0a(0x176)](0x1),'channel':BrowserChannelSchema,'viewport':ConfigViewportSchema['optional'](),'device':_0xe0606c['string']()[_0x19cd0a(0x176)](0x1)[_0x19cd0a(0x1a0)](),'timezone':_0xe0606c['string']()[_0x19cd0a(0x1a5)](isTimeZone,_0x926a62=>({'message':_0x19cd0a(0x178)+_0x926a62+_0x19cd0a(0x17e)}))[_0x19cd0a(0x1a0)](),'locale':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x1a5)](isLocale,_0xc9f061=>({'message':'invalid\x20locale\x20\x22'+_0xc9f061+_0x19cd0a(0x195)}))[_0x19cd0a(0x1a0)](),'maxContexts':_0xe0606c[_0x19cd0a(0x142)]()['int']()[_0x19cd0a(0x14f)]()[_0x19cd0a(0x1a0)](),'launch':LaunchConfigSchema[_0x19cd0a(0x1a0)](),'retry':RetryConfigSchema,'failureBundle':FailureBundleConfigSchema,'dialogPolicy':DialogPolicySchema,'storageState':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x1a0)](),'testDir':_0xe0606c[_0x19cd0a(0x15c)]()[_0x19cd0a(0x176)](0x1),'helpersDir':_0xe0606c['string']()[_0x19cd0a(0x176)](0x1),'defaultTimeoutMs':_0xe0606c[_0x19cd0a(0x142)]()[_0x19cd0a(0x182)]()[_0x19cd0a(0x14f)](),'defaultNavigationTimeoutMs':_0xe0606c[_0x19cd0a(0x142)]()[_0x19cd0a(0x182)]()[_0x19cd0a(0x14f)](),'teardownTimeoutMs':_0xe0606c[_0x19cd0a(0x142)]()[_0x19cd0a(0x182)]()[_0x19cd0a(0x14f)]()[_0x19cd0a(0x1a0)](),'testTimeoutMs':_0xe0606c[_0x19cd0a(0x142)]()[_0x19cd0a(0x182)]()[_0x19cd0a(0x14f)]()[_0x19cd0a(0x1a0)](),'env':EnvConfigSchema,'linter':LinterConfigSchema,'mcp':McpConfigSchema,'queue':QueueConfigSchema,'schedules':_0xe0606c[_0x19cd0a(0x199)](ScheduleSchema)[_0x19cd0a(0x143)]([]),'sandbox':SandboxConfigSchema})['superRefine']((_0x15d6ea,_0x42adf8)=>{var _0x10bb67={_0xef2c33:0x177},_0x381d3d=_0x19cd0a;const _0x22164e=viewportDeviceConflict(_0x15d6ea[_0x381d3d(0x159)],_0x15d6ea['device']);_0x22164e!==void 0x0&&_0x42adf8[_0x381d3d(0x175)]({'code':_0xe0606c[_0x381d3d(_0x10bb67._0xef2c33)][_0x381d3d(0x153)],'path':[_0x381d3d(0x159)],'message':_0x22164e});});function isTimeZone(_0x40063c){var _0xe0d05d={_0x30d144:0x13a,_0x4b6c43:0x15a,_0x219c10:0x145},_0x2823b0=_0x19cd0a;try{return new Intl[(_0x2823b0(_0xe0d05d._0x30d144))](_0x2823b0(_0xe0d05d._0x4b6c43),{'timeZone':_0x40063c}),_0x40063c[_0x2823b0(_0xe0d05d._0x219c10)]>0x0;}catch{return![];}}__name(isTimeZone,_0x19cd0a(0x147));function isLocale(_0x39bc67){var _0x121591={_0x14cd11:0x19b},_0x1bd91e=_0x19cd0a;try{return Intl[_0x1bd91e(_0x121591._0x14cd11)](_0x39bc67)[_0x1bd91e(0x145)]===0x1;}catch{return![];}}__name(isLocale,_0x19cd0a(0x16c));var DEFAULT_CONFIG={'browsers':[_0x19cd0a(0x136)],'retry':{'count':0x0,'on':['transient']},'failureBundle':{'tier1':!![],'tier2':!![],'tier3':{'network':![],'video':![]},'retention':{'runs':0x14,'days':0x7},'storageDir':'.unotest/failures','pageHtml':_0x19cd0a(0x17b)},'dialogPolicy':'accept','testDir':'unotest/e2e','helpersDir':_0x19cd0a(0x19d),'defaultTimeoutMs':0xbb8,'defaultNavigationTimeoutMs':0x7530,'linter':{'enabled':!![],'rules':{'lint:deep-css':'warn','lint:xpath':_0x19cd0a(0x151),'lint:obfuscated-class':'warn','lint:pause-explicit':'warn','lint:disambig-by-index':_0x19cd0a(0x172),'lint:evaluate-discouraged':_0x19cd0a(0x151),'lint:scenario-in-root':_0x19cd0a(0x161),'lint:mustache-in-dsl':'error','lint:goto-concat':'warn','lint:regex-invalid':_0x19cd0a(0x161),'lint:echo-assert':_0x19cd0a(0x151),'lint:lint-ok-missing-reason':_0x19cd0a(0x151),'lint:flow-returns-value':'warn','lint:legacy-layout':'warn','lint:external-variable-undeclared':_0x19cd0a(0x161),'lint:env-host-from-base':'error','lint:one-test-per-file':_0x19cd0a(0x151),'lint:shadows-dsl-function':_0x19cd0a(0x151),'lint:skip-outside-test':_0x19cd0a(0x161),'lint:set-test-timeout-outside-test':_0x19cd0a(0x161),'lint:filter-unknown-option':_0x19cd0a(0x161),'validator:unknown-function':'error'}},'env':{'shared':[]},'mcp':{'transport':_0x19cd0a(0x13b)},'queue':{'enabled':!![],'concurrency':0x1},'schedules':[],'sandbox':{}};export{BROWSER_CHANNEL_WORDS,BrowserChannelSchema,BrowserSchema,DEFAULT_CONFIG,DialogPolicySchema,EnvConfigSchema,FailureBundleConfigSchema,LinterConfigSchema,LinterRuleIdSchema,LinterSeveritySchema,McpConfigSchema,QueueConfigSchema,RetryConfigSchema,RetryReasonSchema,SYSTEM_BROWSER_CHANNELS,SandboxConfigSchema,ScheduleSchema,UnotestConfigSchema,ViewportSchema,WebServerConfigSchema,WebServersConfigSchema,viewportDeviceConflict};
1
+ var _0x4b2829=_0x181a;(function(_0x282d14,_0x3fe266){var _0x3e1421={_0x80dd09:0x133,_0x4cddfe:0x130,_0x752b99:0x121,_0x468bea:0x134,_0x4a3353:0x150},_0x2eaac5=_0x181a,_0x41e487=_0x282d14();while(!![]){try{var _0x1c02ac=parseInt(_0x2eaac5(_0x3e1421._0x80dd09))/0x1*(-parseInt(_0x2eaac5(0x13b))/0x2)+parseInt(_0x2eaac5(0x11e))/0x3+parseInt(_0x2eaac5(_0x3e1421._0x4cddfe))/0x4*(-parseInt(_0x2eaac5(0x14c))/0x5)+-parseInt(_0x2eaac5(0x117))/0x6*(parseInt(_0x2eaac5(_0x3e1421._0x752b99))/0x7)+-parseInt(_0x2eaac5(0x143))/0x8+parseInt(_0x2eaac5(_0x3e1421._0x468bea))/0x9+parseInt(_0x2eaac5(_0x3e1421._0x4a3353))/0xa;if(_0x1c02ac===_0x3fe266)break;else _0x41e487['push'](_0x41e487['shift']());}catch(_0x59f838){_0x41e487['push'](_0x41e487['shift']());}}}(_0x1737,0x7cdd8));var __defProp=Object[_0x4b2829(0x16b)],__name=(_0x3b52db,_0x46ae7d)=>__defProp(_0x3b52db,_0x4b2829(0x12a),{'value':_0x46ae7d,'configurable':!![]});import{z as _0x3a0701}from'zod';import{z}from'zod';import{levenshteinDistance}from'@unotest/core';var MAX_EDITS=0x2;function closestKey(_0x353e51,_0x1d3c5a){var _0x4b920e={_0x1f8338:0x124,_0x4ddd9c:0x14b},_0x1f2edf=_0x4b2829;let _0x46dc63;for(const _0x2a4370 of _0x1d3c5a){const _0x5c9ba1=levenshteinDistance(_0x353e51['toLowerCase'](),_0x2a4370['toLowerCase']());if(_0x5c9ba1>MAX_EDITS)continue;if(_0x46dc63===void 0x0||_0x5c9ba1<_0x46dc63[_0x1f2edf(_0x4b920e._0x1f8338)])_0x46dc63={'key':_0x2a4370,'distance':_0x5c9ba1};}return _0x46dc63?.[_0x1f2edf(_0x4b920e._0x4ddd9c)];}__name(closestKey,_0x4b2829(0x12b));function unknownKeyMessage(_0xa27254,_0x594b9a){var _0x77a463={_0x175e3f:0x120},_0x51c03f={_0x4de527:0x10c},_0x3f9221=_0x4b2829;return _0xa27254[_0x3f9221(0x11d)](_0x3d10b8=>{var _0x71c61=_0x3f9221;const _0x20e06e=closestKey(_0x3d10b8,_0x594b9a);return _0x20e06e===void 0x0?'unknown\x20key\x20\x22'+_0x3d10b8+_0x71c61(0x15f):_0x71c61(_0x51c03f._0x4de527)+_0x3d10b8+_0x71c61(0x168)+_0x20e06e+'\x22?';})[_0x3f9221(_0x77a463._0x175e3f)](';\x20');}__name(unknownKeyMessage,_0x4b2829(0x160));function strictObject(_0x57437e){var _0x59ca41={_0x14114c:0x11c},_0x24637b=_0x4b2829;const _0x1ddfac=Object[_0x24637b(0x127)](_0x57437e);return z['object'](_0x57437e,{'errorMap':__name((_0x482870,_0x3171b3)=>_0x482870['code']===z[_0x24637b(0x13f)][_0x24637b(0x166)]?{'message':unknownKeyMessage(_0x482870['keys'],_0x1ddfac)}:{'message':_0x3171b3[_0x24637b(0x162)]},'errorMap')})[_0x24637b(_0x59ca41._0x14114c)]();}__name(strictObject,_0x4b2829(0xfe));import{BUNDLED_BROWSER_CHANNEL}from'@unotest/protocol';function _0x181a(_0x601664,_0x1d53ae){_0x601664=_0x601664-0xfe;var _0x17374e=_0x1737();var _0x181acd=_0x17374e[_0x601664];if(_0x181a['hSriEP']===undefined){var _0x21db07=function(_0x4788fc){var _0x32150a='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0x3a0701='',_0x30fe35='';for(var _0x3b52db=0x0,_0x46ae7d,_0x353e51,_0x1d3c5a=0x0;_0x353e51=_0x4788fc['charAt'](_0x1d3c5a++);~_0x353e51&&(_0x46ae7d=_0x3b52db%0x4?_0x46ae7d*0x40+_0x353e51:_0x353e51,_0x3b52db++%0x4)?_0x3a0701+=String['fromCharCode'](0xff&_0x46ae7d>>(-0x2*_0x3b52db&0x6)):0x0){_0x353e51=_0x32150a['indexOf'](_0x353e51);}for(var _0x46dc63=0x0,_0x2a4370=_0x3a0701['length'];_0x46dc63<_0x2a4370;_0x46dc63++){_0x30fe35+='%'+('00'+_0x3a0701['charCodeAt'](_0x46dc63)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x30fe35);};_0x181a['TkzsMM']=_0x21db07,_0x181a['dXnifj']={},_0x181a['hSriEP']=!![];}var _0x2d2957=_0x17374e[0x0],_0x2cd111=_0x601664+_0x2d2957,_0x1ad96d=_0x181a['dXnifj'][_0x2cd111];return!_0x1ad96d?(_0x181acd=_0x181a['TkzsMM'](_0x181acd),_0x181a['dXnifj'][_0x2cd111]=_0x181acd):_0x181acd=_0x1ad96d,_0x181acd;}import{z as _0x30fe35}from'zod';function _0x1737(){var _0x31a7f0=['igLZigfSCMvHzhKGyw5VDgHLCIbZzxj2zxiNCYdIGjqGzwfJAcbZzxj2zxiGBMvLzhmGAxrZig93BIbYzwfKAw5LC3mGvvjmlG','BgLUDdPSzwDHy3KTBgf5B3v0','C3rYAw5N','zM9YrwfJAa','Dw5RBM93BIbRzxKGiG','BgLUDdPZy2vUyxjPBY1PBI1YB290','CMvKywn0zwq','DxjS','C3rKAw8','Cg9ZAxrPDMu','BgLUDdPVyMz1C2nHDgvKlwnSyxnZ','yxjYyxK','BgLUDdPNB3rVlwnVBMnHDa','BNvSBa','BgLUDdPZzxqTDgvZDc10Aw1LB3v0lw91DhnPzguTDgvZDa','ntiYndm4ELjly1nn','DMfSAwrHDg9YoM1LDgeTC2HHCgu','BNvTyMvY','BgLUDdPYzwDLEc1PBNzHBgLK','y2HYB21L','C3rYAwn0','BwfW','mtqZnZKWowPjDufcra','zgLZBwLZCW','AM9PBG','nZDxvvv4sxq','yM9VBgvHBG','DMfSAwrHDg9YoMLMlxnOyxbL','zgLZDgfUy2u','DMfSAwrHDg9YoNnLBwfUDgLJlwXVC3m','zMLYzwzVEa','A2v5CW','lNvUB3rLC3qVzMfPBhvYzxm','D2fYBG','BMfTzq','y2XVC2vZDeTLEq','BgLUDdPLBNyTAg9ZDc1MCM9TlwjHC2u','D2vIu2vYDMvYwW','zw4Tvvm','DhjHBNnPzw50','mZK3ntCYD2PQCNPr','Dw5VDgvZDc9LmMu','DMfSAwrHDg9YoNn0zxaTC2HHCgu','ody3ndnJwhjWwLm','nZi5mdm2qvHuywLL','CgvYlxrLC3q','ywrK','y3jHC2G','DMfSAwrHDg9YoNn0CMLUzY1JB25Jyxq','zxjYB3i','y2HYB21LlwjLDge','mtrTq2XbrNC','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlwv4ChjLC3nPB24','BgLUDdP4Cgf0Aa','zw51Bq','wM9KsxnZDwvdB2rL','B3b0Aw9UywW','Bwf4','DhjHBNnMB3jT','mtK3mJmYmg5Tq2Drva','zgvMyxvSDa','BwfUDwfS','AxnbCNjHEq','DMLLD3bVCNq','Dw5RBM93BIb0Aw1LihPVBMuGiG','CMvJB3jK','DMfSAwrHDg9YoNDYyxbWzwqTzM9YBwf0','A2v5','nuz2yNDotG','BgLUDdPTDxn0ywnOzs1PBI1KC2W','y2HYB21PDw0','BgLUDdPWyxvZzs1LEhbSAwnPDa','mtG2mJa3odblyxzcwfe','BgLUDdPSAw50lw9Rlw1PC3nPBMCTCMvHC29U','BgLUDdPKAxnHBwjPzY1IEs1PBMrLEa','y3vZDg9T','BgvUz3rO','zNvSBa','BgLUDdPYB2XLlxvUA25VD24TB3b0Aw9U','DMfSAwrHDg9YoMfYzY1RAw5K','C3vWzxjszwzPBMu','DMfSAwrHDg9YoMzVCI1ZAgfWzq','AxnuAw1LwM9Uzq','z2v0q2fUB25Py2fStg9JywXLCW','ywnJzxb0','rgf0zvrPBwvgB3jTyxq','BMv0D29YAW','iIdIGjqGBM90igeGy29UzMLNigTLEtSGy2HLy2SGEw91CIbaDw5VDgvZDc93zwiGDMvYC2LVBIbPzIbPDcbJB21LCYbMCM9TigeGBMv3zxiGCMvSzwfZzq','Dw5RBM93BKTLEu1LC3nHz2u','AgfZ','zgvMyxvSDevYCM9Y','BgLUDdPKzwvWlwnZCW','BgL0zxjHBa','BxnLzgDL','Dw5YzwnVz25PEMvKx2TLExm','igTLzxbZihrOzsbYzwfSigjYB3DZzxiGD2LUzg93lcbHBMqGzgv2AwnLici','iIdIGjqGzgLKihLVDsbTzwfUici','BgLUDdPMBg93lxjLDhvYBNmTDMfSDwu','DMfSAwrHDg9YoMXPC3qTyxjN','zgvMAw5LuhjVCgvYDhK','BNvSBgfIBgu','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlxn0yxrLBwvUDa','Aw50','BgLUDdPZA2LWlw91DhnPzguTDgvZDa','B2zM','DMLLD3bVCNq6ig51BgW','BwLU','Dw5PB24','C3rYAwn0t2jQzwn0','DMfSAwrHDg9YoMfYAxr5','zgv2AwnL','DMfSAwrHDg9YoMz1BMn0Aw9UlxnOyxbL','D2vIA2L0','iIbZzxrZigL0CYbVD24GC2L6zsbHBMqGC2nHBguG4OcuigrYB3aGB25Lig9MihrOzw0U','AxnmB2nHBgu','CMvMAw5L','DMfSAwrHDg9YoNn0zxaTy292zxjHz2u','BgLUDdPHCgKTy2fSBc1MAwXLlwjVzhK'];_0x1737=function(){return _0x31a7f0;};return _0x1737();}import{UnotestError}from'@unotest/core';var LaunchConfigSchema=_0x30fe35['object']({'userDataDir':_0x30fe35[_0x4b2829(0x10a)]()[_0x4b2829(0x172)](0x1)['optional'](),'profile':_0x30fe35[_0x4b2829(0x164)](_0x4b2829(0x135))[_0x4b2829(0x140)](),'args':_0x30fe35[_0x4b2829(0x113)](_0x30fe35[_0x4b2829(0x10a)]()[_0x4b2829(0x172)](0x1))[_0x4b2829(0x140)]()})['strict'](),BrowserSchema=_0x3a0701[_0x4b2829(0x13e)]([_0x4b2829(0x14e),_0x4b2829(0x126),_0x4b2829(0x102)]),SYSTEM_BROWSER_CHANNELS=[_0x4b2829(0x11b),_0x4b2829(0x165),_0x4b2829(0x13a),'chromium'],BROWSER_CHANNEL_WORDS=[...SYSTEM_BROWSER_CHANNELS,BUNDLED_BROWSER_CHANNEL],BrowserChannelSchema=_0x3a0701['union']([_0x3a0701['enum'](SYSTEM_BROWSER_CHANNELS),_0x3a0701[_0x4b2829(0x164)](BUNDLED_BROWSER_CHANNEL)['transform'](()=>null),_0x3a0701[_0x4b2829(0x115)]()])['optional'](),ViewportSchema=strictObject({'width':_0x3a0701['number']()['int']()[_0x4b2829(0x111)]()[_0x4b2829(0x140)](),'height':_0x3a0701[_0x4b2829(0x119)]()['int']()['positive']()[_0x4b2829(0x140)](),'deviceScaleFactor':_0x3a0701['number']()[_0x4b2829(0x111)]()[_0x4b2829(0x140)]()}),ConfigViewportSchema=ViewportSchema[_0x4b2829(0x16c)]();function viewportDeviceConflict(_0x2539dd,_0x2ed50c,_0x476cdc=_0x4b2829(0x171)){var _0x31661f={_0x1688b0:0x167,_0x331759:0x103},_0x2ae083=_0x4b2829;if(_0x2539dd!==null||_0x2ed50c===void 0x0)return void 0x0;return _0x476cdc+_0x2ae083(_0x31661f._0x1688b0)+_0x2ed50c+_0x2ae083(_0x31661f._0x331759);}__name(viewportDeviceConflict,'viewportDeviceConflict');var RetryReasonSchema=_0x3a0701[_0x4b2829(0x13e)]([_0x4b2829(0x12f),_0x4b2829(0x15e),_0x4b2829(0x137)]),RetryConfigSchema=strictObject({'count':_0x3a0701[_0x4b2829(0x119)]()[_0x4b2829(0x16e)]()['min'](0x0)[_0x4b2829(0x141)](0xa),'on':_0x3a0701[_0x4b2829(0x113)](RetryReasonSchema)}),FailureBundleConfigSchema=strictObject({'tier1':_0x3a0701[_0x4b2829(0x164)](!![])[_0x4b2829(0x144)](!![]),'tier2':_0x3a0701['boolean'](),'tier3':strictObject({'network':_0x3a0701['boolean'](),'video':_0x3a0701[_0x4b2829(0x122)]()}),'retention':strictObject({'runs':_0x3a0701['number']()[_0x4b2829(0x16e)]()[_0x4b2829(0x111)](),'days':_0x3a0701['number']()[_0x4b2829(0x16e)]()[_0x4b2829(0x111)]()}),'storageDir':_0x3a0701['string']()[_0x4b2829(0x172)](0x1),'pageHtml':_0x3a0701[_0x4b2829(0x13e)]([_0x4b2829(0x10e),_0x4b2829(0x155)])}),DialogPolicySchema=_0x3a0701[_0x4b2829(0x13e)]([_0x4b2829(0x15c),_0x4b2829(0x11f),_0x4b2829(0x145)]),LinterRuleIdSchema=_0x3a0701[_0x4b2829(0x13e)]([_0x4b2829(0x163),_0x4b2829(0x13d),_0x4b2829(0x112),_0x4b2829(0x14f),_0x4b2829(0x152),'lint:evaluate-discouraged',_0x4b2829(0x10d),_0x4b2829(0x14d),_0x4b2829(0x114),_0x4b2829(0x11a),'lint:echo-assert',_0x4b2829(0x107),_0x4b2829(0x151),_0x4b2829(0x169),_0x4b2829(0x109),'lint:external-variable-undeclared',_0x4b2829(0x12c),'lint:one-test-per-file','lint:shadows-dsl-function',_0x4b2829(0x16f),_0x4b2829(0x116),'lint:filter-unknown-option',_0x4b2829(0x156),'validator:unknown-function',_0x4b2829(0xff),_0x4b2829(0x157),_0x4b2829(0x106),_0x4b2829(0x132),_0x4b2829(0x118),_0x4b2829(0x101),_0x4b2829(0x159),_0x4b2829(0x123),'validator:var-shape',_0x4b2829(0x16d),_0x4b2829(0x13c),_0x4b2829(0x138),_0x4b2829(0x125),_0x4b2829(0x16a),_0x4b2829(0x14a)]),LinterSeveritySchema=_0x3a0701[_0x4b2829(0x13e)](['off',_0x4b2829(0x129),_0x4b2829(0x139)]),LinterConfigSchema=strictObject({'enabled':_0x3a0701['boolean'](),'rules':_0x3a0701[_0x4b2829(0x149)](LinterRuleIdSchema,LinterSeveritySchema)}),QueueConfigSchema=strictObject({'enabled':_0x3a0701[_0x4b2829(0x122)]()[_0x4b2829(0x144)](!![]),'concurrency':_0x3a0701['number']()[_0x4b2829(0x16e)]()[_0x4b2829(0x111)]()[_0x4b2829(0x144)](0x1)}),ScheduleSchema=strictObject({'collection':_0x3a0701[_0x4b2829(0x10a)]()['min'](0x1),'cron':_0x3a0701[_0x4b2829(0x10a)]()[_0x4b2829(0x172)](0x1),'env':_0x3a0701['string']()[_0x4b2829(0x172)](0x1)['optional'](),'prepare':_0x3a0701[_0x4b2829(0x10a)]()[_0x4b2829(0x172)](0x1)[_0x4b2829(0x140)]()}),McpConfigSchema=strictObject({'transport':_0x3a0701['literal'](_0x4b2829(0x110))}),SandboxConfigSchema=strictObject({'shellCwd':_0x3a0701['string']()['optional'](),'shellTimeoutMs':_0x3a0701['number']()['int']()[_0x4b2829(0x111)]()['optional'](),'exportSecrets':_0x3a0701['array'](_0x3a0701['string']())['optional'](),'database':_0x3a0701['string']()[_0x4b2829(0x140)](),'apiBaseUrl':_0x3a0701['string']()[_0x4b2829(0x10f)]()[_0x4b2829(0x140)](),'uploadDir':_0x3a0701['string']()[_0x4b2829(0x140)](),'readRoots':_0x3a0701[_0x4b2829(0x113)](_0x3a0701[_0x4b2829(0x10a)]()[_0x4b2829(0x172)](0x1))[_0x4b2829(0x140)]()}),WebServerConfigSchema=strictObject({'command':_0x3a0701[_0x4b2829(0x10a)]()[_0x4b2829(0x172)](0x1),'url':_0x3a0701[_0x4b2829(0x10a)]()[_0x4b2829(0x10f)](),'reuseExistingServer':_0x3a0701[_0x4b2829(0x122)]()[_0x4b2829(0x144)](!![]),'timeoutMs':_0x3a0701['number']()[_0x4b2829(0x16e)]()[_0x4b2829(0x111)]()[_0x4b2829(0x144)](0xea60)}),WebServersConfigSchema=_0x3a0701[_0x4b2829(0x173)]([WebServerConfigSchema,_0x3a0701[_0x4b2829(0x113)](WebServerConfigSchema)[_0x4b2829(0x172)](0x1)])[_0x4b2829(0x142)](_0x260f05=>Array[_0x4b2829(0x146)](_0x260f05)?_0x260f05:[_0x260f05])['superRefine']((_0x2c84b2,_0x263d55)=>{var _0x2449d5={_0x19ea64:0x10b},_0x2f1afb={_0x50f79c:0x161,_0x430889:0x13f,_0xf2de18:0x10f,_0x17b590:0x10f},_0x380746=_0x4b2829;const _0x42cf7f=new Set();_0x2c84b2[_0x380746(_0x2449d5._0x19ea64)]((_0x35af51,_0x4fdecf)=>{var _0x50cacc=_0x380746;_0x42cf7f[_0x50cacc(_0x2f1afb._0x50f79c)](_0x35af51[_0x50cacc(0x10f)])&&_0x263d55['addIssue']({'code':_0x3a0701[_0x50cacc(_0x2f1afb._0x430889)][_0x50cacc(0x153)],'path':[_0x4fdecf,_0x50cacc(_0x2f1afb._0xf2de18)],'message':_0x50cacc(0x12d)+_0x4fdecf+'].url\x20'+_0x35af51[_0x50cacc(_0x2f1afb._0x17b590)]+_0x50cacc(0x108)}),_0x42cf7f[_0x50cacc(0x136)](_0x35af51[_0x50cacc(0x10f)]);});}),EnvConfigSchema=strictObject({'shared':_0x3a0701[_0x4b2829(0x113)](_0x3a0701['string']())[_0x4b2829(0x144)]([])}),UnotestConfigSchema=strictObject({'baseUrl':_0x3a0701['string']()['url']()[_0x4b2829(0x140)](),'webServer':WebServersConfigSchema[_0x4b2829(0x140)](),'generate':_0x3a0701[_0x4b2829(0x10a)]()[_0x4b2829(0x172)](0x1)[_0x4b2829(0x140)](),'browsers':_0x3a0701[_0x4b2829(0x113)](BrowserSchema)['min'](0x1),'channel':BrowserChannelSchema,'viewport':ConfigViewportSchema[_0x4b2829(0x140)](),'device':_0x3a0701[_0x4b2829(0x10a)]()[_0x4b2829(0x172)](0x1)[_0x4b2829(0x140)](),'timezone':_0x3a0701[_0x4b2829(0x10a)]()[_0x4b2829(0x105)](isTimeZone,_0x33e6e2=>({'message':_0x4b2829(0x148)+_0x33e6e2+'\x22\x20—\x20expected\x20an\x20IANA\x20name\x20such\x20as\x20\x22Europe/Madrid\x22'}))[_0x4b2829(0x140)](),'locale':_0x3a0701[_0x4b2829(0x10a)]()[_0x4b2829(0x105)](isLocale,_0x5dfb28=>({'message':'invalid\x20locale\x20\x22'+_0x5dfb28+'\x22\x20—\x20expected\x20a\x20BCP\x2047\x20tag\x20such\x20as\x20\x22es-ES\x22'}))[_0x4b2829(0x140)](),'maxContexts':_0x3a0701[_0x4b2829(0x119)]()[_0x4b2829(0x16e)]()['positive']()['optional'](),'launch':LaunchConfigSchema[_0x4b2829(0x140)](),'retry':RetryConfigSchema,'failureBundle':FailureBundleConfigSchema,'dialogPolicy':DialogPolicySchema,'storageState':_0x3a0701[_0x4b2829(0x10a)]()[_0x4b2829(0x140)](),'testDir':_0x3a0701['string']()[_0x4b2829(0x172)](0x1),'helpersDir':_0x3a0701[_0x4b2829(0x10a)]()[_0x4b2829(0x172)](0x1),'defaultTimeoutMs':_0x3a0701['number']()[_0x4b2829(0x16e)]()[_0x4b2829(0x111)](),'defaultNavigationTimeoutMs':_0x3a0701[_0x4b2829(0x119)]()['int']()[_0x4b2829(0x111)](),'teardownTimeoutMs':_0x3a0701[_0x4b2829(0x119)]()[_0x4b2829(0x16e)]()[_0x4b2829(0x111)]()['optional'](),'testTimeoutMs':_0x3a0701['number']()[_0x4b2829(0x16e)]()['positive']()['optional'](),'env':EnvConfigSchema,'linter':LinterConfigSchema,'mcp':McpConfigSchema,'queue':QueueConfigSchema,'schedules':_0x3a0701[_0x4b2829(0x113)](ScheduleSchema)[_0x4b2829(0x144)]([]),'sandbox':SandboxConfigSchema})[_0x4b2829(0x158)]((_0x20a25a,_0x53f946)=>{var _0x2700ff={_0x2d94b0:0x147,_0x320ebd:0x100,_0x37c6ed:0x13f,_0x549a0d:0x147},_0x577dc0=_0x4b2829;const _0x5b8163=viewportDeviceConflict(_0x20a25a[_0x577dc0(_0x2700ff._0x2d94b0)],_0x20a25a[_0x577dc0(_0x2700ff._0x320ebd)]);_0x5b8163!==void 0x0&&_0x53f946['addIssue']({'code':_0x3a0701[_0x577dc0(_0x2700ff._0x37c6ed)][_0x577dc0(0x153)],'path':[_0x577dc0(_0x2700ff._0x549a0d)],'message':_0x5b8163});});function isTimeZone(_0x450fd3){var _0x2b787c={_0x57e30e:0x154},_0x4a35f4=_0x4b2829;try{return new Intl[(_0x4a35f4(0x15d))](_0x4a35f4(0x12e),{'timeZone':_0x450fd3}),_0x450fd3[_0x4a35f4(_0x2b787c._0x57e30e)]>0x0;}catch{return![];}}__name(isTimeZone,_0x4b2829(0x15a));function isLocale(_0x4b4fa0){var _0x3e9517={_0x4b48a9:0x15b},_0x133045=_0x4b2829;try{return Intl[_0x133045(_0x3e9517._0x4b48a9)](_0x4b4fa0)[_0x133045(0x154)]===0x1;}catch{return![];}}__name(isLocale,_0x4b2829(0x104));var DEFAULT_CONFIG={'browsers':[_0x4b2829(0x14e)],'retry':{'count':0x0,'on':[_0x4b2829(0x12f)]},'failureBundle':{'tier1':!![],'tier2':!![],'tier3':{'network':![],'video':![]},'retention':{'runs':0x14,'days':0x7},'storageDir':_0x4b2829(0x128),'pageHtml':'redacted'},'dialogPolicy':_0x4b2829(0x15c),'testDir':_0x4b2829(0x131),'helpersDir':'unotest/e2e/_helpers','defaultTimeoutMs':0xbb8,'defaultNavigationTimeoutMs':0x7530,'linter':{'enabled':!![],'rules':{'lint:deep-css':_0x4b2829(0x129),'lint:xpath':_0x4b2829(0x129),'lint:obfuscated-class':'warn','lint:pause-explicit':'warn','lint:disambig-by-index':_0x4b2829(0x170),'lint:evaluate-discouraged':_0x4b2829(0x129),'lint:scenario-in-root':_0x4b2829(0x139),'lint:mustache-in-dsl':_0x4b2829(0x139),'lint:goto-concat':'warn','lint:regex-invalid':_0x4b2829(0x139),'lint:echo-assert':'warn','lint:lint-ok-missing-reason':_0x4b2829(0x129),'lint:flow-returns-value':_0x4b2829(0x129),'lint:legacy-layout':_0x4b2829(0x129),'lint:external-variable-undeclared':_0x4b2829(0x139),'lint:env-host-from-base':_0x4b2829(0x139),'lint:one-test-per-file':_0x4b2829(0x129),'lint:shadows-dsl-function':_0x4b2829(0x129),'lint:skip-outside-test':_0x4b2829(0x139),'lint:set-test-timeout-outside-test':'error','lint:filter-unknown-option':'error','lint:role-unknown-option':'error','validator:unknown-function':_0x4b2829(0x139)}},'env':{'shared':[]},'mcp':{'transport':'stdio'},'queue':{'enabled':!![],'concurrency':0x1},'schedules':[],'sandbox':{}};export{BROWSER_CHANNEL_WORDS,BrowserChannelSchema,BrowserSchema,DEFAULT_CONFIG,DialogPolicySchema,EnvConfigSchema,FailureBundleConfigSchema,LinterConfigSchema,LinterRuleIdSchema,LinterSeveritySchema,McpConfigSchema,QueueConfigSchema,RetryConfigSchema,RetryReasonSchema,SYSTEM_BROWSER_CHANNELS,SandboxConfigSchema,ScheduleSchema,UnotestConfigSchema,ViewportSchema,WebServerConfigSchema,WebServersConfigSchema,viewportDeviceConflict};
@@ -1,5 +1,5 @@
1
- import { B as BoundingBox, E as ElementHint, S as ScreenshotOptions, L as LocatorValue, C as CaptureFrame, a as CaptureRect, P as PageConsole, N as NetworkEntry, W as WebDriver, b as LaunchOptions, c as ContextOptions, D as DriverContext, A as AttachOptions } from '../interfaces-CTMGjJIs.js';
2
- export { d as ActionTimeout, e as CheckOptions, f as ClickOptions, g as CookieOptions, h as DriverPage, F as FillOptions, G as GotoOptions, H as HoverOptions, i as NavigationOptions, j as PressOptions, R as ReloadOptions, k as SelectOptions, V as Viewport, l as ViewportSize, m as WaitOptions, n as WaitState } from '../interfaces-CTMGjJIs.js';
1
+ import { B as BoundingBox, I as ImageSize, E as ElementHint, S as ScreenshotOptions, L as LocatorValue, C as CaptureFrame, a as CaptureRect, P as PageConsole, N as NetworkEntry, W as WebDriver, b as LaunchOptions, c as ContextOptions, D as DriverContext, A as AttachOptions } from '../interfaces-mlRtu8mL.js';
2
+ export { d as ActionTimeout, e as CheckOptions, f as ClickOptions, g as CookieOptions, h as DriverPage, F as FillOptions, G as GotoOptions, H as HoverOptions, i as NavigationOptions, j as PressOptions, R as ReloadOptions, k as SelectOptions, V as Viewport, l as ViewportSize, m as WaitOptions, n as WaitState } from '../interfaces-mlRtu8mL.js';
3
3
  import '@unotest/protocol';
4
4
  import '../config/schema.js';
5
5
  import 'zod';
@@ -34,6 +34,9 @@ interface FakeBehavior {
34
34
  boundingBoxByDefault?: BoundingBox | null;
35
35
  /** Default isDisabled() response. Default: false. */
36
36
  isDisabledByDefault?: boolean;
37
+ /** Default imageSize() response — null = broken / no src. Default: a
38
+ * 100×100 image. */
39
+ imageSizeByDefault?: ImageSize | null;
37
40
  /** Per-property computedStyle(loc, property) response. Default: "". */
38
41
  computedStyleByProperty?: Record<string, string>;
39
42
  /** runningAnimations(loc) response, one per call in order; the last
@@ -64,6 +67,9 @@ interface FakeBehavior {
64
67
  * when unspecified) for tests that exercise a format fallback. Default:
65
68
  * the literal "fake-png"; tests that read dimensions seed a real PNG header. */
66
69
  screenshotBytes?: Buffer | ((type: ScreenshotOptions["type"]) => Buffer);
70
+ /** What a context's close() waits on — a promise that never settles is
71
+ * a browser that never lets the context go. Absent: closes at once. */
72
+ contextCloseResult?: Promise<void>;
67
73
  /** Where masks lie in a capture (`boxesInCapture`). Default: none. */
68
74
  captureBoxes?: (locs: readonly LocatorValue[], frame: CaptureFrame) => CaptureRect[];
69
75
  /** What page.evaluate() resolves to — e.g. an OutlineTree for a capture