@unotest/web 0.30.0 → 0.31.0

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.
@@ -604,11 +604,23 @@ the old browser context, then `run_test` again.
604
604
  | `wait_for_url` | `value` (the pattern) | `options` |
605
605
  | `enter_frame` | `locator` | |
606
606
  | `exit_frame` | | |
607
+ | `screenshot` | | `name`, `fullPage`, `locator`, `outline`, `evidenceOnly` |
607
608
 
608
609
  When recording (`explorationId` present): `description` + `section`
609
610
  are required. Ad-hoc (no `explorationId`): no description/section,
610
611
  no recording.
611
612
 
613
+ `screenshot` is the **evidence** step: it files a PNG under the session
614
+ (`.unotest/explorations/<explorationId>/screenshots/<NNN>-<name>.png`,
615
+ `adhoc/` without a session), replies with `{path, width, height}` and
616
+ the image itself, and becomes `screenshot(name)` in the saved test.
617
+ `name` defaults to the section slug; `locator` captures one element
618
+ (the saved test degrades that to a page capture); `outline: true` adds
619
+ the page outline to the reply; `evidenceOnly: true` keeps the file but
620
+ records no step. `explore_stop` lists every file in `artifacts`. Take
621
+ one wherever a human would want to check a green run after the fact —
622
+ do not write throwaway scenarios just to get a picture.
623
+
612
624
  ## Failure modes you will hit
613
625
 
614
626
  - **`StaleRefError`** — ref no longer in the DOM. Re-`get_page_snapshot`
@@ -735,11 +735,23 @@ the old browser context, then `run_test` again.
735
735
  | `wait_for_url` | `value` (the pattern) | `options` |
736
736
  | `enter_frame` | `locator` | |
737
737
  | `exit_frame` | | |
738
+ | `screenshot` | | `name`, `fullPage`, `locator`, `outline`, `evidenceOnly` |
738
739
 
739
740
  When recording (`explorationId` present): `description` + `section`
740
741
  are required. Ad-hoc (no `explorationId`): no description/section,
741
742
  no recording.
742
743
 
744
+ `screenshot` is the **evidence** step: it files a PNG under the session
745
+ (`.unotest/explorations/<explorationId>/screenshots/<NNN>-<name>.png`,
746
+ `adhoc/` without a session), replies with `{path, width, height}` and
747
+ the image itself, and becomes `screenshot(name)` in the saved test.
748
+ `name` defaults to the section slug; `locator` captures one element
749
+ (the saved test degrades that to a page capture); `outline: true` adds
750
+ the page outline to the reply; `evidenceOnly: true` keeps the file but
751
+ records no step. `explore_stop` lists every file in `artifacts`. Take
752
+ one wherever a human would want to check a green run after the fact —
753
+ do not write throwaway scenarios just to get a picture.
754
+
743
755
  ## Failure modes you will hit
744
756
 
745
757
  - **`StaleRefError`** — a ref from an earlier lookup is no longer in
package/CHANGELOG.md CHANGED
@@ -1,5 +1,271 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.31.0] - 2026-09-04
4
+
5
+ ### Minor Changes
6
+
7
+ - b8e105b: New DSL function `note(label, value)`: attach a labelled value to the
8
+ current step — the question a data-driven case asked, the answer it got
9
+ — kept in the run journal and shown in the viewer under the step, during
10
+ and after the run. Any value: a string as it is, anything else as JSON;
11
+ cut at 4 KB (marked `truncated`), secrets masked. `log(...)` now also
12
+ lands in the journal under the step that wrote it (the stdout line
13
+ stays), and `assertJudge` verdicts carry the position of their statement,
14
+ so the viewer can show a verdict under its step and the whole verdict on
15
+ a failed step's error card. Each of these events records the DSL call's
16
+ `file` / `line` / `col` and the nearest entry-file statement
17
+ (`entryLine` / `entryCol`) — a note from inside a helper is attributed to
18
+ the entry step that called the helper. Without a run journal
19
+ (exploration, an ad-hoc runtime) `note` goes to the logger; nothing
20
+ fails.
21
+ - 56784b3: `ExecutionWalker.run` takes a trailing `entryArgs` list and binds it by
22
+ position onto the entry function's parameters (missing ones `null`) in
23
+ the root scope before the body runs — what `explore_run_flow` needs to
24
+ replay a parameterised `flow_*` helper live.
25
+ - 56784b3: `explore_run_flow` replays parameterised flows: pass `args` (positional
26
+ JSON values, `"{{NAME}}"` for a variable) and the helper's parameters are
27
+ bound for the live replay — `flow_login(username, password)` no longer
28
+ fails with `Variable "username" is not defined`. `explore_start` lists
29
+ each flow's `params`; a wrong argument count is refused with the
30
+ signature. The recording keeps variable NAMES, so the saved test reads
31
+ `flow_login(LOGIN, PASSWORD);` — `flow_call` is now a regular action
32
+ plugin rendering the call with its arguments.
33
+ - 307582f: New `explore_step` action `screenshot` — the evidence step of an
34
+ exploration. It files a PNG under the session
35
+ (`.unotest/explorations/<explorationId>/screenshots/<NNN>-<name>.png`,
36
+ `adhoc/` without a session), replies with the absolute `path`, `width`
37
+ and `height`, and returns the image itself as an MCP image block (a JPEG
38
+ copy when the PNG is over 1 MiB; path only when both are). `name`
39
+ defaults to the section slug, `fullPage` captures the whole page,
40
+ `locator` captures one element, `outline: true` adds the page outline
41
+ to the reply, `evidenceOnly: true` keeps the file but records no step.
42
+ A recorded screenshot becomes `screenshot(name)` in the saved test; an
43
+ element capture degrades to a page capture with a comment and a
44
+ non-blocking `DEGRADED_STEP` warning. `explore_stop` now lists the
45
+ session's files in `artifacts`. Driver: `DriverPage.screenshotElement`.
46
+ - 6b61884: New linter rule `lint:external-variable-undeclared` (default `error`): a
47
+ bare `UPPER_SNAKE` identifier that no layer file declares — `unotest/.env`,
48
+ `unotest/.secrets`, or the `.env.<name>` / `.secrets.<name>` overlay of
49
+ the environment `lint --env <name>` / `UNOTEST_ENV` selects — is reported
50
+ with the files searched, instead of failing at that statement at run time
51
+ after the browser is up. A name bound in the file (assigned, a parameter,
52
+ a loop counter) is never flagged. The shell is not a declaration: a value
53
+ CI exports still needs its name in `unotest/.env` (`NAME=` with no value
54
+ declares it; the shell's value wins at run time, as before). As an error
55
+ it is not silenced by `// lint-ok:`; downgrade it in `linter.rules` if a
56
+ project needs that.
57
+
58
+ `run_test` (MCP) and `e2e` run the same check before the browser starts,
59
+ against what the run will actually resolve — files and the ambient shell
60
+ — so a suite that lives on a shell variable keeps running; a name that
61
+ would have failed in the scenario anyway now fails up front (`run_test`
62
+ answers `lint_failed`; `e2e` prints it and proceeds, like every pre-run
63
+ diagnostic).
64
+
65
+ The linter also descends into operator, array and property-access
66
+ operands now, so a regex or `{{mustache}}` literal inside `a + b` is
67
+ diagnosed the same as one on its own.
68
+
69
+ - eddb1db: New linter rule `lint:one-test-per-file`: a second (third, …) top-level
70
+ `function test_*` in one scenario file is reported at its declaration.
71
+ A file is the unit a collection runs and the viewer shows — the Steps
72
+ tree projects a run onto the first `test_*`, so the others executed with
73
+ nowhere to be seen. Fold the cases into one test with tagged steps
74
+ (`step("…", {tag: id}, () => { … })`, `step.soft` when a case must not
75
+ stop the run) or move shared journeys into `flow_*` helpers under
76
+ `unotest/e2e/_helpers/`; `flow_*` functions in a scenario file are not
77
+ counted.
78
+
79
+ **Migration window:** the rule is a **warning** in 0.31 — visible in
80
+ `lint`, the editor and `run_test`'s warnings, silenced per line with
81
+ `// lint-ok: <reason>`, never blocking. A later minor release flips the
82
+ default to `error` (which the pre-run gate of `run_test` refuses); split
83
+ files that hold several `test_*` before then.
84
+
85
+ - b0a00cb: New DSL function `readJsonLine(path, filter) → object`: read a JSONL file
86
+ that already exists and return the first line matching the key filter —
87
+ no polling. `waitForJsonLine` was the only structured input into a
88
+ scenario, and for a fixture or a finished export its 20s timeout only
89
+ masked a wrong path. `readJsonLine` takes the same filter (strict equality
90
+ per key, dot paths for nesting, unparsable lines skipped) and fails at
91
+ once: `file not found: <path>` when the file is missing, `no line matches
92
+ {…} in <path>` with parse stats and the closest line when nothing matches.
93
+ Data-driven tests read their cases with it and name evidence after them
94
+ (`screenshot(q.id)`).
95
+ - 100ab9d: Data-driven steps: `step("label", {tag: q.id}, () => { … })` names the
96
+ case an iteration is on, and `step.soft("label", [{tag}], () => { … })`
97
+ records a failure inside instead of stopping the run — the rest of that
98
+ body is skipped, the next case runs, and the test still ends **failed**
99
+ with every soft failure listed (`3 soft step(s) failed: Question [q17]:
100
+ …`, one line per case in the CLI output; `run_test` answers
101
+ `next.softFailures`; `inspect_runtime`'s `lastFailure` carries `stepTag`
102
+ and `soft`). The failure bundle shows the page at the moment of the
103
+ **first** soft failure, with `soft: true` and `stepTag` in
104
+ `failure.json`; later soft failures live in the journal. `step.soft` is
105
+ allowed inside `test_*` only; nesting is free, and the outer step is a
106
+ group, not an assertion — a soft failure inside does not change its
107
+ outcome. The run journal gains `step-block:started` / `step-block:finished`
108
+ envelopes per block (label, tag, soft, outcome, whole-block duration).
109
+ Editor typings declare the new forms.
110
+ - ad7c918: The run journal records every loop pass (`loop:iteration`, with the loop
111
+ statement's position and the pass index), which the viewer's new Trace
112
+ view uses to show a loop as one group per iteration. Also: when an error
113
+ unwinds through enclosing statements, `lastFailure` (the failure bundle's
114
+ position, `inspect_runtime`, the CLI's `in step "…" [tag]` line) now
115
+ names the innermost statement that raised it — the assert inside the
116
+ tagged step — instead of the outermost loop that re-threw it.
117
+
118
+ ### Patch Changes
119
+
120
+ - 9ae6d59: A bundle no longer declares the runner's own `UNOTEST_*` settings
121
+ (`UNOTEST_HEADED`, `UNOTEST_LOG_LEVEL`, …) from the suite's `.env`, so a box
122
+ stops warning on every push that an environment "neither sets nor holds"
123
+ names `env push` never sends. Both sides now share one rule
124
+ (`isRunnerSetting` in `@unotest/protocol`): those variables configure the
125
+ machine a run happens on, not the suite. A per-suite value such as the
126
+ navigation timeout travels with the bundle through `unotest.config.mjs`
127
+ (`defaultNavigationTimeoutMs`), not through `.env`.
128
+ - 917380d: `unotest.config.*` is merged with the defaults recursively. A partially
129
+ written section — `linter: { rules: { 'lint:deep-css': 'off' } }`,
130
+ `failureBundle: { tier3: { video: true } }`, `viewport: { width: 1920 }`
131
+ — now keeps the rest of that section's defaults instead of failing with
132
+ "config validation failed" (nested sections require all of their fields
133
+ at validation time, so a top-level replace made every partial section
134
+ invalid). Arrays and scalars still replace as a whole: `browsers:
135
+ ['firefox']` means firefox only. The setup manual's example config,
136
+ which was exactly such a partial `linter`, loads as written; its
137
+ `timeouts` block — never a config field — is corrected to
138
+ `defaultTimeoutMs` / `defaultNavigationTimeoutMs`.
139
+ - e048334: The viewer's editor flags an undeclared external variable
140
+ (`lint:external-variable-undeclared`), the way `unotest-web lint` and the
141
+ pre-run lint already do: a bare `UPPER_SNAKE` identifier that no
142
+ `unotest/.env` / `.secrets` file of the active environment declares is an
143
+ error in the editor, naming the files searched. Protocol:
144
+ `DslValidateContext` gains `externalNames` / `externalSources`; the
145
+ viewer supplies them from the active target + environment's layer files
146
+ (the same files the variables panel shows) and `@unotest/web`'s language
147
+ service turns them into the linter's lookup.
148
+ - dcf4c9e: Viewer editor: lint markers appear as soon as a file opens (or the page
149
+ reloads), not only after the first keystroke — the editor validates the
150
+ source it mounted with instead of waiting for a change event that a
151
+ reopened tab never fires.
152
+ - 6646584: Docs: `hover` now lists its options (`force`, `position`, `timeout`) in
153
+ the DSL reference, the editor signature and the generated typings — it
154
+ used to read as if it took none, while `position` is exactly what a
155
+ hover-revealed menu at one edge of a tall element needs. The agent
156
+ integration guide gains "Watching a collection run": the collection's
157
+ `steps.jsonl` journal (path, the four `collection-run:*` events, how to
158
+ tail it) as the progress source for a run started in the background,
159
+ where the CLI's per-scenario lines only arrive when the process ends.
160
+ - 630d6ce: `unotest-web lint` now receives its arguments: the bin dispatcher forwarded
161
+ only the command name, so `lint --env <name>` linted the base environment
162
+ and an explicit file argument was ignored (every file was linted instead).
163
+ `UNOTEST_ENV=<name>` worked all along, which is why the gap went unnoticed.
164
+ - f3bd3cc: `lint` works on a project that has not migrated to the 0.28 layout yet.
165
+ A `unotest.config.*` still at the project root used to stop `lint` with
166
+ the same refusal `e2e` gives — right for a command that would RUN on
167
+ defaults, wrong for one that only grades: nobody lints a suite during
168
+ the very migration that touches every file. `lint` now builds its
169
+ context on the default settings (rule severities, helpers dir), reads
170
+ `unotest/.env`, `.secrets` and `_helpers/` as usual, and reports the
171
+ layout once as the new `lint:legacy-layout` warning (default `warn`,
172
+ configurable like any rule) with the migration on one line. The exit
173
+ code is unaffected by it. `e2e`, `collection` and `bundle push` refuse
174
+ exactly as before.
175
+ - 224d016: The MCP server says when it is running a stale build. `run_test`'s
176
+ pre-spawn lint, flow discovery (`explore_start`), `explore_run_flow`,
177
+ `generate_dsl_from_exploration` and `save_exploration_as_test` parse and
178
+ render DSL in the server's own process, on the modules it loaded at
179
+ start — after a rebuild a new DSL feature came back as a false parse
180
+ error until the server was restarted, while the runner child was already
181
+ on the new build. Those replies now carry `serverStale: true` and a
182
+ `serverStaleWarning` ("restart the MCP server") once the code on disk is
183
+ newer than the server's start; nothing changes while it is fresh.
184
+ - 02757c3: `serverStale` now also rides on `explore_step` / `explore_steps` (locator
185
+ resolution and recording run in the server's process), `find_element`
186
+ and `ground_element` replies — the same flag `run_test` and the
187
+ exploration tools already carry once the build on disk is newer than the
188
+ running MCP server.
189
+ - dcf4c9e: `goto` with a relative path resolves against the runtime's own base URL
190
+ instead of the browser context's. In a CLI run the two coincide; in an
191
+ exploration recording against an `env` override, `explore_run_flow`
192
+ replayed `goto('/_guard/')` on the MCP session's shared context — created
193
+ with the server's base — and landed on the wrong host. The replay now
194
+ follows the session's `baseUrl` (and its variables, as before).
195
+ - f3bd3cc: `screenshot(name)` accepts any string value, not only a literal. The
196
+ runtime always slugified whatever it received, but the validator (and
197
+ therefore `lint` and `run_test`) rejected `screenshot(q.id)` and
198
+ `screenshot(textJoin(['q-', id]))` — a data-driven test had to name every
199
+ capture the same. The `name` slot is now string-like, as in `fill`; a
200
+ non-string argument is still an `arg-kind` error.
201
+ - dcf4c9e: A section label reopened after another section is called out instead of
202
+ silently splitting a step: `explore_step` / `explore_steps` reply with
203
+ `sectionHint` the moment it happens, and the generated draft carries a
204
+ non-blocking `SPLIT_SECTION` warning naming the reopened entries. The
205
+ recorded order of actions is never changed; `autoRun` and `save` are not
206
+ held back by it.
207
+ - 9ae6d59: A scenario that finished in the same instant the viewer looked at it is no
208
+ longer recorded as `interrupted` with a finish an hour before its start.
209
+ The runner ends a run by appending `run:finished` and then backdating the
210
+ heartbeat; the viewer read those two files in the opposite order, so a
211
+ steps snapshot taken a few milliseconds early could meet the backdated
212
+ heartbeat, and the provisional verdict stuck in the run index while the
213
+ collection reported the scenario passed. The heartbeat is read first now.
214
+ A viewer restart (which rebuilds the index from disk) already corrected
215
+ such records; runs indexed live are right the first time.
216
+ - 13a2d51: Viewer, Home tab: the tile of a scenario that is running now breathes
217
+ through colour and shadow only — the scale pulse is gone. It moved the
218
+ tile's box every frame, so an automation driver never saw the tile as
219
+ stable and a click on it waited out its timeout. A tile that never ran
220
+ no longer carries `data-age="fresh"`: it has no age, so the attribute is
221
+ absent.
222
+ - 91fb562: Viewer, Home tab: clicking a scenario tile opens the scenario's LAST RUN —
223
+ the run whose verdict the tile's colour is showing — instead of the test
224
+ file. A tile that has never run still opens the test (there is no run to
225
+ open), and so does every tile in schedule mode, where the schedule is
226
+ edited from the test. The legend now reads "hover for history · click to
227
+ open the last run".
228
+ - dcf4c9e: Viewer, Home tab: the tile field no longer refits itself in a loop. The
229
+ header and legend take the grid's width; when the legend wrapped at one
230
+ width and not at the next, the field's height changed, the fit followed,
231
+ the width changed back — at 60 fps every tile's box moved every frame,
232
+ and an automation click on ANY tile ("element is not stable") waited out
233
+ its timeout unless forced. Header and legend now never wrap (they grow
234
+ past the grid instead), so the fit converges and tiles stay put. A run
235
+ opened from a tile is titled by its scenario, like one opened from the
236
+ Runs tree, instead of by its run id.
237
+ - dcf4c9e: Recording no longer bakes relative time or counters into a locator. An
238
+ accessible name such as `Run smoke — passed, 7m ago`, `just now`,
239
+ `yesterday`, `5 passed`, `7 runs` or a trailing badge (`Inbox · 3`,
240
+ `Errors: 12`) now counts as volatile: the recorder emits the stable prefix
241
+ (`{name: "Run smoke — passed", exact: true}`, then `/^Run smoke — passed\b/`)
242
+ instead of the literal, and the draft carries the `DYNAMIC_TEXT` warning
243
+ with that prefix. Bare numbers elsewhere stay stable (`Page 2`, `Q4 2026`,
244
+ `v2`, `2FA`).
245
+ - Updated dependencies [b8e105b]
246
+ - Updated dependencies [b8e105b]
247
+ - Updated dependencies [b8e105b]
248
+ - Updated dependencies [9ae6d59]
249
+ - Updated dependencies [56784b3]
250
+ - Updated dependencies [e048334]
251
+ - Updated dependencies [dcf4c9e]
252
+ - Updated dependencies [100ab9d]
253
+ - Updated dependencies [100ab9d]
254
+ - Updated dependencies [100ab9d]
255
+ - Updated dependencies [100ab9d]
256
+ - Updated dependencies [ad7c918]
257
+ - Updated dependencies [ad7c918]
258
+ - Updated dependencies [ad7c918]
259
+ - Updated dependencies [9ae6d59]
260
+ - Updated dependencies [13a2d51]
261
+ - Updated dependencies [91fb562]
262
+ - Updated dependencies [dcf4c9e]
263
+ - @unotest/core@0.31.0
264
+ - @unotest/protocol@0.31.0
265
+ - @unotest/viewer@0.31.0
266
+ - @unotest/dsl@0.31.0
267
+ - @unotest/grounder-client@0.31.0
268
+
3
269
  ## [0.30.0] - 2026-09-03
4
270
 
5
271
  ### Minor Changes
@@ -75,7 +75,9 @@ function dispatch(sub) {
75
75
  forwardArgs: args.slice(1),
76
76
  };
77
77
  case "lint":
78
- return { dist: "dist/runner/cli.js", src: "src/runner/cli.ts", forwardArgs: ["lint"] };
78
+ // Forwarded whole, like e2e: `--env <name>` and explicit file
79
+ // arguments belong to the command, not to the dispatcher.
80
+ return { dist: "dist/runner/cli.js", src: "src/runner/cli.ts", forwardArgs: args };
79
81
  case "viewer":
80
82
  return { dist: "dist/runner/cli.js", src: "src/runner/cli.ts", forwardArgs: ["viewer"] };
81
83
  case "prepare-fix":
@@ -90,19 +90,19 @@ declare const FailureBundleConfigSchema: z.ZodObject<{
90
90
  type FailureBundleConfig = z.infer<typeof FailureBundleConfigSchema>;
91
91
  declare const DialogPolicySchema: z.ZodEnum<["accept", "dismiss", "manual"]>;
92
92
  type DialogPolicy = z.infer<typeof DialogPolicySchema>;
93
- 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", "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"]>;
93
+ 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:one-test-per-file", "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"]>;
94
94
  type LinterRuleId = z.infer<typeof LinterRuleIdSchema>;
95
95
  declare const LinterSeveritySchema: z.ZodEnum<["off", "warn", "error"]>;
96
96
  type LinterSeverity = z.infer<typeof LinterSeveritySchema>;
97
97
  declare const LinterConfigSchema: z.ZodObject<{
98
98
  enabled: z.ZodBoolean;
99
- 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", "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"]>>;
99
+ 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:one-test-per-file", "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"]>>;
100
100
  }, "strip", z.ZodTypeAny, {
101
101
  enabled: boolean;
102
- 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" | "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">>;
102
+ 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:one-test-per-file" | "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">>;
103
103
  }, {
104
104
  enabled: boolean;
105
- 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" | "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">>;
105
+ 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:one-test-per-file" | "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">>;
106
106
  }>;
107
107
  type LinterConfig = z.infer<typeof LinterConfigSchema>;
108
108
  declare const QueueConfigSchema: z.ZodObject<{
@@ -355,13 +355,13 @@ declare const UnotestConfigSchema: z.ZodObject<{
355
355
  defaultNavigationTimeoutMs: z.ZodNumber;
356
356
  linter: z.ZodObject<{
357
357
  enabled: z.ZodBoolean;
358
- 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", "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"]>>;
358
+ 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:one-test-per-file", "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"]>>;
359
359
  }, "strip", z.ZodTypeAny, {
360
360
  enabled: boolean;
361
- 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" | "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">>;
361
+ 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:one-test-per-file" | "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">>;
362
362
  }, {
363
363
  enabled: boolean;
364
- 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" | "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">>;
364
+ 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:one-test-per-file" | "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">>;
365
365
  }>;
366
366
  mcp: z.ZodObject<{
367
367
  transport: z.ZodLiteral<"stdio">;
@@ -483,7 +483,7 @@ declare const UnotestConfigSchema: z.ZodObject<{
483
483
  defaultNavigationTimeoutMs: number;
484
484
  linter: {
485
485
  enabled: boolean;
486
- 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" | "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">>;
486
+ 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:one-test-per-file" | "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">>;
487
487
  };
488
488
  mcp: {
489
489
  transport: "stdio";
@@ -545,7 +545,7 @@ declare const UnotestConfigSchema: z.ZodObject<{
545
545
  defaultNavigationTimeoutMs: number;
546
546
  linter: {
547
547
  enabled: boolean;
548
- 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" | "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">>;
548
+ 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:one-test-per-file" | "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">>;
549
549
  };
550
550
  mcp: {
551
551
  transport: "stdio";
@@ -1 +1 @@
1
- var _0xb70be3=_0x1568;(function(_0x487679,_0xf30c69){var _0x564764={_0x39328b:0x102,_0x59616f:0xff,_0x6e10ff:0x119,_0x18b7c8:0xfc,_0x46e2f8:0x12a,_0x4f5fca:0x130},_0x580d82=_0x1568,_0x340ec3=_0x487679();while(!![]){try{var _0x164607=-parseInt(_0x580d82(_0x564764._0x39328b))/0x1*(parseInt(_0x580d82(0x11e))/0x2)+parseInt(_0x580d82(0xfb))/0x3*(parseInt(_0x580d82(_0x564764._0x59616f))/0x4)+-parseInt(_0x580d82(0x117))/0x5*(parseInt(_0x580d82(_0x564764._0x6e10ff))/0x6)+parseInt(_0x580d82(0x101))/0x7+parseInt(_0x580d82(_0x564764._0x18b7c8))/0x8*(parseInt(_0x580d82(_0x564764._0x46e2f8))/0x9)+parseInt(_0x580d82(0x10e))/0xa*(parseInt(_0x580d82(0xfe))/0xb)+-parseInt(_0x580d82(_0x564764._0x4f5fca))/0xc;if(_0x164607===_0xf30c69)break;else _0x340ec3['push'](_0x340ec3['shift']());}catch(_0x1b9f91){_0x340ec3['push'](_0x340ec3['shift']());}}}(_0x2f16,0x91f77));function _0x1568(_0x3c32df,_0x2877ec){_0x3c32df=_0x3c32df-0xf9;var _0x2f165e=_0x2f16();var _0x15683a=_0x2f165e[_0x3c32df];if(_0x1568['eflopM']===undefined){var _0x3aed1d=function(_0x643f24){var _0x48d278='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0x34c2ef='',_0x1f31b5='';for(var _0x314cb3=0x0,_0x1d5fff,_0x4b0a9f,_0x5cc54a=0x0;_0x4b0a9f=_0x643f24['charAt'](_0x5cc54a++);~_0x4b0a9f&&(_0x1d5fff=_0x314cb3%0x4?_0x1d5fff*0x40+_0x4b0a9f:_0x4b0a9f,_0x314cb3++%0x4)?_0x34c2ef+=String['fromCharCode'](0xff&_0x1d5fff>>(-0x2*_0x314cb3&0x6)):0x0){_0x4b0a9f=_0x48d278['indexOf'](_0x4b0a9f);}for(var _0x54127f=0x0,_0x47953b=_0x34c2ef['length'];_0x54127f<_0x47953b;_0x54127f++){_0x1f31b5+='%'+('00'+_0x34c2ef['charCodeAt'](_0x54127f)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x1f31b5);};_0x1568['fyZHBF']=_0x3aed1d,_0x1568['JbVAVC']={},_0x1568['eflopM']=!![];}var _0x4abcf7=_0x2f165e[0x0],_0x50138f=_0x3c32df+_0x4abcf7,_0x39a36a=_0x1568['JbVAVC'][_0x50138f];return!_0x39a36a?(_0x15683a=_0x1568['fyZHBF'](_0x15683a),_0x1568['JbVAVC'][_0x50138f]=_0x15683a):_0x15683a=_0x39a36a,_0x15683a;}import{z}from'zod';var BrowserSchema=z['enum']([_0xb70be3(0x12e),_0xb70be3(0x120),_0xb70be3(0x125)]),BrowserChannelSchema=z[_0xb70be3(0x132)]([z[_0xb70be3(0x113)](_0xb70be3(0x109)),z['literal'](_0xb70be3(0x129)),z[_0xb70be3(0x113)]('chrome-beta'),z[_0xb70be3(0xfd)]()])['optional'](),ViewportSchema=z[_0xb70be3(0x12d)]({'width':z[_0xb70be3(0x112)]()[_0xb70be3(0x121)]()['positive'](),'height':z[_0xb70be3(0x112)]()[_0xb70be3(0x121)]()[_0xb70be3(0x11d)]()}),RetryReasonSchema=z[_0xb70be3(0x105)]([_0xb70be3(0x11c),_0xb70be3(0x134),'crash']),RetryConfigSchema=z[_0xb70be3(0x12d)]({'count':z[_0xb70be3(0x112)]()['int']()[_0xb70be3(0x103)](0x0)[_0xb70be3(0x133)](0xa),'on':z[_0xb70be3(0x138)](RetryReasonSchema)}),FailureBundleConfigSchema=z['object']({'tier1':z[_0xb70be3(0x113)](!![])[_0xb70be3(0x128)](!![]),'tier2':z[_0xb70be3(0x124)](),'tier3':z[_0xb70be3(0x12d)]({'network':z[_0xb70be3(0x124)](),'video':z[_0xb70be3(0x124)]()}),'retention':z[_0xb70be3(0x12d)]({'runs':z[_0xb70be3(0x112)]()['int']()[_0xb70be3(0x11d)](),'days':z[_0xb70be3(0x112)]()[_0xb70be3(0x121)]()[_0xb70be3(0x11d)]()}),'storageDir':z[_0xb70be3(0x11f)]()[_0xb70be3(0x103)](0x1)}),DialogPolicySchema=z['enum']([_0xb70be3(0x12f),_0xb70be3(0xf9),_0xb70be3(0x126)]),LinterRuleIdSchema=z[_0xb70be3(0x105)]([_0xb70be3(0x108),_0xb70be3(0x10b),_0xb70be3(0x12c),'lint:pause-explicit',_0xb70be3(0x111),_0xb70be3(0x10f),_0xb70be3(0x10a),'lint:mustache-in-dsl',_0xb70be3(0x114),'lint:regex-invalid',_0xb70be3(0x136),_0xb70be3(0x123),_0xb70be3(0x10c),_0xb70be3(0x11a),_0xb70be3(0x135),'validator:arity',_0xb70be3(0xfa),'validator:step-coverage','validator:step-shape','validator:meta-shape','validator:function-shape',_0xb70be3(0x131),'validator:if-shape',_0xb70be3(0x12b),_0xb70be3(0x137),_0xb70be3(0x115),'validator:string-concat','validator:semantic-loss',_0xb70be3(0x127),_0xb70be3(0x107)]),LinterSeveritySchema=z['enum']([_0xb70be3(0x118),'warn',_0xb70be3(0x122)]),LinterConfigSchema=z[_0xb70be3(0x12d)]({'enabled':z[_0xb70be3(0x124)](),'rules':z[_0xb70be3(0x116)](LinterRuleIdSchema,LinterSeveritySchema)}),QueueConfigSchema=z[_0xb70be3(0x12d)]({'enabled':z[_0xb70be3(0x124)]()[_0xb70be3(0x128)](!![]),'concurrency':z[_0xb70be3(0x112)]()[_0xb70be3(0x121)]()[_0xb70be3(0x11d)]()[_0xb70be3(0x128)](0x1)}),ScheduleSchema=z['object']({'collection':z[_0xb70be3(0x11f)]()['min'](0x1),'cron':z[_0xb70be3(0x11f)]()['min'](0x1),'env':z['string']()[_0xb70be3(0x103)](0x1)['optional'](),'prepare':z['string']()[_0xb70be3(0x103)](0x1)[_0xb70be3(0x100)]()}),McpConfigSchema=z['object']({'transport':z[_0xb70be3(0x113)](_0xb70be3(0x104))}),SandboxConfigSchema=z['object']({'shellCwd':z[_0xb70be3(0x11f)]()['optional'](),'shellTimeoutMs':z[_0xb70be3(0x112)]()[_0xb70be3(0x121)]()['positive']()[_0xb70be3(0x100)](),'exportSecrets':z['array'](z[_0xb70be3(0x11f)]())[_0xb70be3(0x100)](),'database':z[_0xb70be3(0x11f)]()[_0xb70be3(0x100)](),'apiBaseUrl':z[_0xb70be3(0x11f)]()[_0xb70be3(0x11b)]()[_0xb70be3(0x100)](),'uploadDir':z[_0xb70be3(0x11f)]()[_0xb70be3(0x100)]()}),WebServerConfigSchema=z['object']({'command':z['string']()[_0xb70be3(0x103)](0x1),'url':z[_0xb70be3(0x11f)]()[_0xb70be3(0x11b)](),'reuseExistingServer':z[_0xb70be3(0x124)]()[_0xb70be3(0x128)](!![]),'timeoutMs':z[_0xb70be3(0x112)]()[_0xb70be3(0x121)]()['positive']()[_0xb70be3(0x128)](0xea60)}),UnotestConfigSchema=z[_0xb70be3(0x12d)]({'baseUrl':z[_0xb70be3(0x11f)]()[_0xb70be3(0x11b)]()['optional'](),'webServer':WebServerConfigSchema['optional'](),'browsers':z['array'](BrowserSchema)[_0xb70be3(0x103)](0x1),'channel':BrowserChannelSchema,'viewport':ViewportSchema,'retry':RetryConfigSchema,'failureBundle':FailureBundleConfigSchema,'dialogPolicy':DialogPolicySchema,'storageState':z[_0xb70be3(0x11f)]()['optional'](),'testDir':z[_0xb70be3(0x11f)]()[_0xb70be3(0x103)](0x1),'helpersDir':z[_0xb70be3(0x11f)]()[_0xb70be3(0x103)](0x1),'defaultTimeoutMs':z[_0xb70be3(0x112)]()[_0xb70be3(0x121)]()['positive'](),'defaultNavigationTimeoutMs':z[_0xb70be3(0x112)]()[_0xb70be3(0x121)]()[_0xb70be3(0x11d)](),'linter':LinterConfigSchema,'mcp':McpConfigSchema,'queue':QueueConfigSchema,'schedules':z['array'](ScheduleSchema)[_0xb70be3(0x128)]([]),'sandbox':SandboxConfigSchema}),DEFAULT_CONFIG={'browsers':[_0xb70be3(0x12e)],'viewport':{'width':0x500,'height':0x2d0},'retry':{'count':0x0,'on':['transient']},'failureBundle':{'tier1':!![],'tier2':!![],'tier3':{'network':![],'video':![]},'retention':{'runs':0x14,'days':0x7},'storageDir':'.unotest/failures'},'dialogPolicy':'accept','testDir':_0xb70be3(0x10d),'helpersDir':_0xb70be3(0x110),'defaultTimeoutMs':0xbb8,'defaultNavigationTimeoutMs':0x7530,'linter':{'enabled':!![],'rules':{'lint:deep-css':_0xb70be3(0x106),'lint:xpath':_0xb70be3(0x106),'lint:obfuscated-class':'warn','lint:pause-explicit':_0xb70be3(0x106),'lint:disambig-by-index':_0xb70be3(0x118),'lint:evaluate-discouraged':'warn','lint:scenario-in-root':_0xb70be3(0x122),'lint:mustache-in-dsl':_0xb70be3(0x122),'lint:goto-concat':'warn','lint:regex-invalid':'error','lint:echo-assert':_0xb70be3(0x106),'lint:lint-ok-missing-reason':'warn','lint:flow-returns-value':_0xb70be3(0x106),'validator:unknown-function':_0xb70be3(0x122)}},'mcp':{'transport':'stdio'},'queue':{'enabled':!![],'concurrency':0x1},'schedules':[],'sandbox':{}};export{BrowserChannelSchema,BrowserSchema,DEFAULT_CONFIG,DialogPolicySchema,FailureBundleConfigSchema,LinterConfigSchema,LinterRuleIdSchema,LinterSeveritySchema,McpConfigSchema,QueueConfigSchema,RetryConfigSchema,RetryReasonSchema,SandboxConfigSchema,ScheduleSchema,UnotestConfigSchema,ViewportSchema,WebServerConfigSchema};function _0x2f16(){var _0x16bf16=['DMfSAwrHDg9YoMfYzY1RAw5K','mtiXmJe4uwnZzKTe','mti5mJe1mMDPzMHIDa','BNvSBa','mtu3m2fHrvDMAW','nhLID01pDa','B3b0Aw9UywW','ndGWmtK3mKP2revkwG','nteWn1DLrgnVBa','BwLU','C3rKAw8','zw51Bq','D2fYBG','DMfSAwrHDg9YoNDYyxbWzwqTzM9YBwf0','BgLUDdPKzwvWlwnZCW','y2HYB21L','BgLUDdPZy2vUyxjPBY1PBI1YB290','BgLUDdP4Cgf0Aa','BgLUDdPSAw50lw9Rlw1PC3nPBMCTCMvHC29U','Dw5VDgvZDc9LmMu','nJm4mtbutxHAu2G','BgLUDdPLDMfSDwf0zs1KAxnJB3vYywDLza','Dw5VDgvZDc9LmMuVx2HLBhbLCNm','BgLUDdPKAxnHBwjPzY1IEs1PBMrLEa','BNvTyMvY','BgL0zxjHBa','BgLUDdPNB3rVlwnVBMnHDa','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlwv4ChjLC3nPB24','CMvJB3jK','mZvty1zbD2K','B2zM','mZKZnJC4C09xsuvr','BgLUDdPMBg93lxjLDhvYBNmTDMfSDwu','DxjS','DhjHBNnPzw50','Cg9ZAxrPDMu','mtyYu25uqu1A','C3rYAw5N','zMLYzwzVEa','Aw50','zxjYB3i','BgLUDdPHCgKTy2fSBc1MAwXLlwjVzhK','yM9VBgvHBG','D2vIA2L0','BwfUDwfS','DMfSAwrHDg9YoMXPC3qTyxjN','zgvMyxvSDa','BxnLzgDL','nJnovMnIAuO','DMfSAwrHDg9YoNzHCI1ZAgfWzq','BgLUDdPVyMz1C2nHDgvKlwnSyxnZ','B2jQzwn0','y2HYB21PDw0','ywnJzxb0','mtu1odqXnZjqBunTrNi','DMfSAwrHDg9YoMzVCI1ZAgfWzq','Dw5PB24','Bwf4','BMv0D29YAW','DMfSAwrHDg9YoNvUA25VD24TzNvUy3rPB24','BgLUDdPLy2HVlwfZC2vYDa','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlxn0yxrLBwvUDa','yxjYyxK','zgLZBwLZCW'];_0x2f16=function(){return _0x16bf16;};return _0x2f16();}
1
+ var _0x2fa2f7=_0x2c5b;(function(_0x3499ab,_0x5d8568){var _0x15eafc={_0x3b21ab:0x1b8,_0x53bdd8:0x1c4,_0x1d4372:0x1bd,_0x2a51f9:0x1e0,_0x3504e6:0x1dc},_0x17529b=_0x2c5b,_0x17f685=_0x3499ab();while(!![]){try{var _0x12126c=-parseInt(_0x17529b(0x1d4))/0x1+-parseInt(_0x17529b(_0x15eafc._0x3b21ab))/0x2*(parseInt(_0x17529b(0x1b2))/0x3)+-parseInt(_0x17529b(_0x15eafc._0x53bdd8))/0x4+-parseInt(_0x17529b(_0x15eafc._0x1d4372))/0x5+-parseInt(_0x17529b(_0x15eafc._0x2a51f9))/0x6+parseInt(_0x17529b(0x1c9))/0x7+parseInt(_0x17529b(_0x15eafc._0x3504e6))/0x8;if(_0x12126c===_0x5d8568)break;else _0x17f685['push'](_0x17f685['shift']());}catch(_0x1d36eb){_0x17f685['push'](_0x17f685['shift']());}}}(_0x4bad,0x1a19a));function _0x2c5b(_0x2a65eb,_0x5a03d3){_0x2a65eb=_0x2a65eb-0x1b1;var _0x4bad3b=_0x4bad();var _0x2c5b05=_0x4bad3b[_0x2a65eb];if(_0x2c5b['xNMmGo']===undefined){var _0x3be714=function(_0x1319c2){var _0x15751e='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0xbdc2b='',_0x2098aa='';for(var _0x2e3c9d=0x0,_0x103b9f,_0x86a1ad,_0x2a3181=0x0;_0x86a1ad=_0x1319c2['charAt'](_0x2a3181++);~_0x86a1ad&&(_0x103b9f=_0x2e3c9d%0x4?_0x103b9f*0x40+_0x86a1ad:_0x86a1ad,_0x2e3c9d++%0x4)?_0xbdc2b+=String['fromCharCode'](0xff&_0x103b9f>>(-0x2*_0x2e3c9d&0x6)):0x0){_0x86a1ad=_0x15751e['indexOf'](_0x86a1ad);}for(var _0x318be3=0x0,_0x156e43=_0xbdc2b['length'];_0x318be3<_0x156e43;_0x318be3++){_0x2098aa+='%'+('00'+_0xbdc2b['charCodeAt'](_0x318be3)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x2098aa);};_0x2c5b['UUeoiq']=_0x3be714,_0x2c5b['ykZLZs']={},_0x2c5b['xNMmGo']=!![];}var _0x2cb5bb=_0x4bad3b[0x0],_0x25b50c=_0x2a65eb+_0x2cb5bb,_0x145ffc=_0x2c5b['ykZLZs'][_0x25b50c];return!_0x145ffc?(_0x2c5b05=_0x2c5b['UUeoiq'](_0x2c5b05),_0x2c5b['ykZLZs'][_0x25b50c]=_0x2c5b05):_0x2c5b05=_0x145ffc,_0x2c5b05;}import{z}from'zod';function _0x4bad(){var _0x357f87=['y3jHC2G','yxjYyxK','DMfSAwrHDg9YoMzVCI1ZAgfWzq','DMfSAwrHDg9YoNDYyxbWzwqTzM9YBwf0','C3rYAw5N','ndeXnJy4ogv3uNnVBG','DMfSAwrHDg9YoM1LDgeTC2HHCgu','B2zM','lNvUB3rLC3qVzMfPBhvYzxm','mtq3oduYsLf6whfo','DMfSAwrHDg9YoNnLBwfUDgLJlwXVC3m','DMfSAwrHDg9YoNn0zxaTy292zxjHz2u','DxjS','CMvJB3jK','DMfSAwrHDg9YoNzHCI1ZAgfWzq','BgLUDdPYzwDLEc1PBNzHBgLK','BgLUDdPWyxvZzs1LEhbSAwnPDa','D2fYBG','Aw50','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlxn0yxrLBwvUDa','BgLUDdPHCgKTy2fSBc1MAwXLlwjVzhK','BNvSBa','BgLUDdPLy2HVlwfZC2vYDa','D2vIA2L0','BgLUDdPTDxn0ywnOzs1PBI1KC2W','Bwf4','yM9VBgvHBG','BgL0zxjHBa','otmWA1jZEuvM','BMv0D29YAW','BgLUDdPLDMfSDwf0zs1KAxnJB3vYywDLza','DMfSAwrHDg9YoNvUA25VD24TzNvUy3rPB24','DMfSAwrHDg9YoMz1BMn0Aw9UlxnOyxbL','BgLUDdPZy2vUyxjPBY1PBI1YB290','ndjdrg5KsfG','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlwv4ChjLC3nPB24','BgLUDdPKAxnHBwjPzY1IEs1PBMrLEa','zgvMyxvSDa','zgLZBwLZCW','odGWnJa1C2HwB0rm','BgLUDdPVBMuTDgvZDc1WzxiTzMLSzq','BwfUDwfS','BgLUDdPSzwDHy3KTBgf5B3v0','BgLUDdPMBg93lxjLDhvYBNmTDMfSDwu','C3rKAw8','zxjYB3i','nty0mJqWC2H1AuPr','BNvTyMvY','zMLYzwzVEa','BwLU','Cg9ZAxrPDMu','ntGZmJrdChvztu4','DMfSAwrHDg9YoMfYzY1RAw5K','DMfSAwrHDg9YoMXPC3qTyxjN','Dw5VDgvZDc9LmMu','BxnLzgDL','y2HYB21PDw0','zw51Bq','B2jQzwn0','DMfSAwrHDg9YoNn0zxaTC2HHCgu','DhjHBNnPzw50','B3b0Aw9UywW','nJC2nZLLu3vWwwG','Dw5PB24','y2HYB21LlwjLDge'];_0x4bad=function(){return _0x357f87;};return _0x4bad();}var BrowserSchema=z['enum']([_0x2fa2f7(0x1ce),_0x2fa2f7(0x1c6),_0x2fa2f7(0x1ee)]),BrowserChannelSchema=z[_0x2fa2f7(0x1d5)]([z[_0x2fa2f7(0x1b1)]('chrome'),z[_0x2fa2f7(0x1b1)](_0x2fa2f7(0x1cd)),z[_0x2fa2f7(0x1b1)](_0x2fa2f7(0x1d6)),z[_0x2fa2f7(0x1ec)]()])[_0x2fa2f7(0x1d3)](),ViewportSchema=z[_0x2fa2f7(0x1d0)]({'width':z['number']()[_0x2fa2f7(0x1e9)]()[_0x2fa2f7(0x1c8)](),'height':z[_0x2fa2f7(0x1c5)]()[_0x2fa2f7(0x1e9)]()[_0x2fa2f7(0x1c8)]()}),RetryReasonSchema=z['enum']([_0x2fa2f7(0x1d2),_0x2fa2f7(0x1b3),_0x2fa2f7(0x1d7)]),RetryConfigSchema=z['object']({'count':z['number']()[_0x2fa2f7(0x1e9)]()[_0x2fa2f7(0x1c7)](0x0)[_0x2fa2f7(0x1f0)](0xa),'on':z[_0x2fa2f7(0x1d8)](RetryReasonSchema)}),FailureBundleConfigSchema=z[_0x2fa2f7(0x1d0)]({'tier1':z[_0x2fa2f7(0x1b1)](!![])['default'](!![]),'tier2':z[_0x2fa2f7(0x1f1)](),'tier3':z['object']({'network':z[_0x2fa2f7(0x1f1)](),'video':z[_0x2fa2f7(0x1f1)]()}),'retention':z[_0x2fa2f7(0x1d0)]({'runs':z[_0x2fa2f7(0x1c5)]()['int']()[_0x2fa2f7(0x1c8)](),'days':z[_0x2fa2f7(0x1c5)]()[_0x2fa2f7(0x1e9)]()[_0x2fa2f7(0x1c8)]()}),'storageDir':z[_0x2fa2f7(0x1db)]()[_0x2fa2f7(0x1c7)](0x1)}),DialogPolicySchema=z[_0x2fa2f7(0x1cf)](['accept',_0x2fa2f7(0x1bc),_0x2fa2f7(0x1bf)]),LinterRuleIdSchema=z[_0x2fa2f7(0x1cf)](['lint:deep-css','lint:xpath','lint:obfuscated-class',_0x2fa2f7(0x1e7),_0x2fa2f7(0x1ba),_0x2fa2f7(0x1b4),_0x2fa2f7(0x1b7),_0x2fa2f7(0x1ef),'lint:goto-concat',_0x2fa2f7(0x1e6),_0x2fa2f7(0x1ed),_0x2fa2f7(0x1eb),'lint:lint-ok-missing-reason',_0x2fa2f7(0x1c1),_0x2fa2f7(0x1c0),'lint:external-variable-undeclared',_0x2fa2f7(0x1be),_0x2fa2f7(0x1b5),'validator:arity',_0x2fa2f7(0x1ca),_0x2fa2f7(0x1e2),_0x2fa2f7(0x1d1),_0x2fa2f7(0x1dd),_0x2fa2f7(0x1b6),_0x2fa2f7(0x1d9),'validator:if-shape',_0x2fa2f7(0x1e5),_0x2fa2f7(0x1ea),_0x2fa2f7(0x1b9),'validator:string-concat',_0x2fa2f7(0x1e1),_0x2fa2f7(0x1cb),_0x2fa2f7(0x1da)]),LinterSeveritySchema=z[_0x2fa2f7(0x1cf)]([_0x2fa2f7(0x1de),_0x2fa2f7(0x1e8),'error']),LinterConfigSchema=z['object']({'enabled':z['boolean'](),'rules':z[_0x2fa2f7(0x1e4)](LinterRuleIdSchema,LinterSeveritySchema)}),QueueConfigSchema=z[_0x2fa2f7(0x1d0)]({'enabled':z[_0x2fa2f7(0x1f1)]()[_0x2fa2f7(0x1bb)](!![]),'concurrency':z[_0x2fa2f7(0x1c5)]()[_0x2fa2f7(0x1e9)]()['positive']()[_0x2fa2f7(0x1bb)](0x1)}),ScheduleSchema=z[_0x2fa2f7(0x1d0)]({'collection':z[_0x2fa2f7(0x1db)]()['min'](0x1),'cron':z[_0x2fa2f7(0x1db)]()[_0x2fa2f7(0x1c7)](0x1),'env':z['string']()[_0x2fa2f7(0x1c7)](0x1)[_0x2fa2f7(0x1d3)](),'prepare':z[_0x2fa2f7(0x1db)]()[_0x2fa2f7(0x1c7)](0x1)[_0x2fa2f7(0x1d3)]()}),McpConfigSchema=z[_0x2fa2f7(0x1d0)]({'transport':z[_0x2fa2f7(0x1b1)](_0x2fa2f7(0x1c2))}),SandboxConfigSchema=z[_0x2fa2f7(0x1d0)]({'shellCwd':z[_0x2fa2f7(0x1db)]()['optional'](),'shellTimeoutMs':z[_0x2fa2f7(0x1c5)]()['int']()['positive']()[_0x2fa2f7(0x1d3)](),'exportSecrets':z['array'](z[_0x2fa2f7(0x1db)]())[_0x2fa2f7(0x1d3)](),'database':z[_0x2fa2f7(0x1db)]()[_0x2fa2f7(0x1d3)](),'apiBaseUrl':z[_0x2fa2f7(0x1db)]()[_0x2fa2f7(0x1e3)]()[_0x2fa2f7(0x1d3)](),'uploadDir':z[_0x2fa2f7(0x1db)]()[_0x2fa2f7(0x1d3)]()}),WebServerConfigSchema=z[_0x2fa2f7(0x1d0)]({'command':z[_0x2fa2f7(0x1db)]()[_0x2fa2f7(0x1c7)](0x1),'url':z[_0x2fa2f7(0x1db)]()[_0x2fa2f7(0x1e3)](),'reuseExistingServer':z['boolean']()[_0x2fa2f7(0x1bb)](!![]),'timeoutMs':z[_0x2fa2f7(0x1c5)]()['int']()[_0x2fa2f7(0x1c8)]()['default'](0xea60)}),UnotestConfigSchema=z[_0x2fa2f7(0x1d0)]({'baseUrl':z[_0x2fa2f7(0x1db)]()[_0x2fa2f7(0x1e3)]()[_0x2fa2f7(0x1d3)](),'webServer':WebServerConfigSchema[_0x2fa2f7(0x1d3)](),'browsers':z['array'](BrowserSchema)[_0x2fa2f7(0x1c7)](0x1),'channel':BrowserChannelSchema,'viewport':ViewportSchema,'retry':RetryConfigSchema,'failureBundle':FailureBundleConfigSchema,'dialogPolicy':DialogPolicySchema,'storageState':z[_0x2fa2f7(0x1db)]()[_0x2fa2f7(0x1d3)](),'testDir':z[_0x2fa2f7(0x1db)]()['min'](0x1),'helpersDir':z[_0x2fa2f7(0x1db)]()['min'](0x1),'defaultTimeoutMs':z[_0x2fa2f7(0x1c5)]()[_0x2fa2f7(0x1e9)]()[_0x2fa2f7(0x1c8)](),'defaultNavigationTimeoutMs':z[_0x2fa2f7(0x1c5)]()['int']()[_0x2fa2f7(0x1c8)](),'linter':LinterConfigSchema,'mcp':McpConfigSchema,'queue':QueueConfigSchema,'schedules':z['array'](ScheduleSchema)[_0x2fa2f7(0x1bb)]([]),'sandbox':SandboxConfigSchema}),DEFAULT_CONFIG={'browsers':[_0x2fa2f7(0x1ce)],'viewport':{'width':0x500,'height':0x2d0},'retry':{'count':0x0,'on':['transient']},'failureBundle':{'tier1':!![],'tier2':!![],'tier3':{'network':![],'video':![]},'retention':{'runs':0x14,'days':0x7},'storageDir':_0x2fa2f7(0x1df)},'dialogPolicy':'accept','testDir':_0x2fa2f7(0x1cc),'helpersDir':'unotest/e2e/_helpers','defaultTimeoutMs':0xbb8,'defaultNavigationTimeoutMs':0x7530,'linter':{'enabled':!![],'rules':{'lint:deep-css':_0x2fa2f7(0x1e8),'lint:xpath':_0x2fa2f7(0x1e8),'lint:obfuscated-class':_0x2fa2f7(0x1e8),'lint:pause-explicit':'warn','lint:disambig-by-index':_0x2fa2f7(0x1de),'lint:evaluate-discouraged':_0x2fa2f7(0x1e8),'lint:scenario-in-root':'error','lint:mustache-in-dsl':_0x2fa2f7(0x1c3),'lint:goto-concat':'warn','lint:regex-invalid':_0x2fa2f7(0x1c3),'lint:echo-assert':_0x2fa2f7(0x1e8),'lint:lint-ok-missing-reason':_0x2fa2f7(0x1e8),'lint:flow-returns-value':'warn','lint:legacy-layout':_0x2fa2f7(0x1e8),'lint:external-variable-undeclared':_0x2fa2f7(0x1c3),'lint:one-test-per-file':_0x2fa2f7(0x1e8),'validator:unknown-function':_0x2fa2f7(0x1c3)}},'mcp':{'transport':_0x2fa2f7(0x1c2)},'queue':{'enabled':!![],'concurrency':0x1},'schedules':[],'sandbox':{}};export{BrowserChannelSchema,BrowserSchema,DEFAULT_CONFIG,DialogPolicySchema,FailureBundleConfigSchema,LinterConfigSchema,LinterRuleIdSchema,LinterSeveritySchema,McpConfigSchema,QueueConfigSchema,RetryConfigSchema,RetryReasonSchema,SandboxConfigSchema,ScheduleSchema,UnotestConfigSchema,ViewportSchema,WebServerConfigSchema};
@@ -1,5 +1,5 @@
1
- import { E as ElementHint, N as NetworkEntry, W as WebDriver, L as LaunchOptions, C as ContextOptions, D as DriverContext, A as AttachOptions } from '../interfaces-BluheUKs.js';
2
- export { a as ActionTimeout, b as CheckOptions, c as ClickOptions, d as CookieOptions, e as DriverPage, F as FillOptions, G as GotoOptions, H as HoverOptions, f as NavigationOptions, P as PressOptions, R as ReloadOptions, S as ScreenshotOptions, g as SelectOptions, V as Viewport, h as WaitOptions, i as WaitState } from '../interfaces-BluheUKs.js';
1
+ import { E as ElementHint, S as ScreenshotOptions, N as NetworkEntry, W as WebDriver, L as LaunchOptions, C as ContextOptions, D as DriverContext, A as AttachOptions } from '../interfaces-B34N4rfI.js';
2
+ export { a as ActionTimeout, b as CheckOptions, c as ClickOptions, d as CookieOptions, e as DriverPage, F as FillOptions, G as GotoOptions, H as HoverOptions, f as NavigationOptions, P as PressOptions, R as ReloadOptions, g as SelectOptions, V as Viewport, h as WaitOptions, i as WaitState } from '../interfaces-B34N4rfI.js';
3
3
  import '@unotest/protocol';
4
4
  import '../config/schema.js';
5
5
  import 'zod';
@@ -52,6 +52,14 @@ interface FakeBehavior {
52
52
  /** Programmable response for outerHTML(loc). Keys are `data-unotest-ref`
53
53
  * values; anything not in the map → a synthetic `<div data-ref>` string. */
54
54
  outerHtmlByRef?: Record<string, string>;
55
+ /** Bytes screenshot() / screenshotElement() return — a Buffer, or a
56
+ * function of the requested encoding (`png` / `jpeg` / `webp`, undefined
57
+ * when unspecified) for tests that exercise a format fallback. Default:
58
+ * the literal "fake-png"; tests that read dimensions seed a real PNG header. */
59
+ screenshotBytes?: Buffer | ((type: ScreenshotOptions["type"]) => Buffer);
60
+ /** What page.evaluate() resolves to — e.g. an OutlineTree for a capture
61
+ * path under test. Default: undefined. */
62
+ evaluateResult?: unknown;
55
63
  /** Seed console entries that consoleEntries() returns. */
56
64
  consoleEntries?: ReadonlyArray<{
57
65
  level: "log" | "info" | "warn" | "error" | "debug";
@@ -84,4 +92,4 @@ declare class FakeWebDriver implements WebDriver {
84
92
  callsFor(method: string): ReadonlyArray<RecordedCall>;
85
93
  }
86
94
 
87
- export { ContextOptions, DriverContext, type FakeBehavior, FakeWebDriver, LaunchOptions, type RecordedCall, WebDriver };
95
+ export { ContextOptions, DriverContext, type FakeBehavior, FakeWebDriver, LaunchOptions, type RecordedCall, ScreenshotOptions, WebDriver };