@unotest/web 0.43.2 → 0.44.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.
@@ -427,9 +427,10 @@ Assertions:
427
427
 
428
428
  State reads:
429
429
  - `getTitle()`, `getUrl()`, `getAttribute(loc, name)`, `getInnerText(loc)`,
430
- `getInputValue(loc)`, `count(loc)`; `textContains(haystack, needle)`
431
- for a substring probe on a string you already hold
432
- (`assertTrue(textContains(out.stdout, 'ready'))`).
430
+ `getInputValue(loc)`, `count(loc)`. A string you already hold answers
431
+ `s.length`, `s.trim()`, `s.includes(x)`, `s.startsWith(x)`
432
+ (`assertTrue(out.stdout.includes('ready'))`); `textContains(haystack,
433
+ needle)` is the same probe as a function.
433
434
  - A `textarea` / `input` VALUE is not page text: `waitForText` and
434
435
  `assertText` never see it. Check it with `assertValue(loc, expected)`
435
436
  — it polls until the timeout (5 s by default, `{timeout}` to raise
@@ -440,9 +441,9 @@ State reads:
440
441
  - Only the vocabulary above is expression language. `!` is rejected by
441
442
  the parser (`unotest-web lint`: `parse error — Invalid token`);
442
443
  `JSON.stringify` / `Date.now()` / `indexOf` and other JS globals and
443
- string methods are rejected by the validator with the replacement
444
- named (`use json(value)`, `use nowMs()`, `use textContains(haystack,
445
- needle)`). Express the check as an assertion or a locator
444
+ string methods beyond the four above are rejected by the validator
445
+ with the replacement named (`use json(value)`, `use nowMs()`, `use
446
+ s.includes(needle)`). Express the check as an assertion or a locator
446
447
  (`assertHidden`, `assertCount`, `.filter({hasText})`, `textContains`).
447
448
 
448
449
  Sandbox primitives:
@@ -558,9 +558,10 @@ Assertions:
558
558
 
559
559
  State reads:
560
560
  - `getTitle()`, `getUrl()`, `getAttribute(loc, name)`, `getInnerText(loc)`,
561
- `getInputValue(loc)`, `count(loc)`; `textContains(haystack, needle)`
562
- for a substring probe on a string you already hold
563
- (`assertTrue(textContains(out.stdout, 'ready'))`).
561
+ `getInputValue(loc)`, `count(loc)`. A string you already hold answers
562
+ `s.length`, `s.trim()`, `s.includes(x)`, `s.startsWith(x)`
563
+ (`assertTrue(out.stdout.includes('ready'))`); `textContains(haystack,
564
+ needle)` is the same probe as a function.
564
565
  - A `textarea` / `input` VALUE is not page text: `waitForText` and
565
566
  `assertText` never see it. Check it with `assertValue(loc, expected)`
566
567
  — it polls until the timeout (5 s by default, `{timeout}` to raise
@@ -571,9 +572,9 @@ State reads:
571
572
  - Only the vocabulary above is expression language. `!` is rejected by
572
573
  the parser (`unotest-web lint`: `parse error — Invalid token`);
573
574
  `JSON.stringify` / `Date.now()` / `indexOf` and other JS globals and
574
- string methods are rejected by the validator with the replacement
575
- named (`use json(value)`, `use nowMs()`, `use textContains(haystack,
576
- needle)`). Express the check as an assertion or a locator
575
+ string methods beyond the four above are rejected by the validator
576
+ with the replacement named (`use json(value)`, `use nowMs()`, `use
577
+ s.includes(needle)`). Express the check as an assertion or a locator
577
578
  (`assertHidden`, `assertCount`, `.filter({hasText})`, `textContains`).
578
579
 
579
580
  Sandbox primitives:
package/CHANGELOG.md CHANGED
@@ -1,5 +1,93 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.44.0] - 2026-09-30
4
+
5
+ ### Minor Changes
6
+
7
+ - eb7be5d: Page clock, time zone and locale.
8
+
9
+ - **New DSL functions `clockFreeze(iso)`, `clockTick(ms)`, `clockRun()`.** `clockFreeze` stops time on the page: `Date` reads the given instant, and `setTimeout`, `setInterval` and `requestAnimationFrame` stand still. A "typing…" indicator or a countdown then gives the same screenshot on every run. `clockTick` moves frozen time forward and fires the timers that fall due. `clockRun` lets time run again. `clockFreeze` works at any point, including after `goto`, and takes past dates as well as future ones.
10
+ - **When the clock is installed.** A run puts the fake clock on the browser before the first page loads, and only for scenarios that can reach a clock call, directly or through a helper. Every other scenario keeps real time, as before. Playwright's spelling (`clock.freeze(…)`, `pauseAt`, `runFor`, `resume`) is refused with the DSL name to use instead.
11
+ - **MCP.** `new_context` and `explore_start` take `clock: true`. `explore_step` gains `clock_freeze {time}`, `clock_tick {ms}` and `clock_run`, recorded as the DSL calls. On a browser opened without the clock they are refused, and the refusal says how to open one with it.
12
+ - **Config `timezone` and `locale`** (`"Europe/Madrid"`, `"es-ES"`) for every page. `UNOTEST_TIMEZONE` and `UNOTEST_LOCALE` still override them for one run. An unknown zone or a malformed locale is refused when the config loads.
13
+ - Screenshots taken while time is frozen no longer wait for an animation frame that cannot come. Each used to cost up to two seconds.
14
+
15
+ - 816e2ea: A second browser context in one test: two clients of the same app.
16
+
17
+ - **New DSL functions `newContext()` and `setContext(index)`.** `newContext()` opens another browser context with the same options as the first: base URL, viewport, `device`, time zone, locale and page clock. It has its own cookies, storage and tabs, makes it the active one and returns its number (the test's own context is `0`). `setContext(i)` switches. Each context keeps its own tab and frame, so a switch back lands where the scenario left off. At the end of the test every context is closed.
18
+ - **Config `maxContexts`** (default 4) caps contexts per test. The next `newContext()` is refused and the refusal names the key. On a browser profile (`launch.userDataDir`) `newContext()` is refused: every page there shares one context.
19
+ - **Run journal and failure bundle.** Once a second context exists, each step records the context it started in (`contextIndex`), and the viewer's Trace shows it as a `ctx N` chip. A failure bundles the active context's page, console and network, with `contextIndex` in `failure.json`. A one-context test writes exactly what it did before. Both fields are additive: an older viewer reads the new journal and a newer one reads the old.
20
+ - **MCP.** `explore_step` gains `newContext` and `setContext {index}`, recorded as the same DSL calls. The `new_context` tool still resets the browser. Intent grounding follows the active context. An agent joining a paused debug run (`take_wheel`, `attach_debug_session`) lands in the context the run is on (Chromium).
21
+ - **New lint rule `lint:shadows-dsl-function`** (warning): a function or variable of your own that has a DSL function's name.
22
+
23
+ **If your scenarios define their own `newContext` or `setContext`:** a call by that name still runs your function, so nothing changes at run time. The new DSL function is out of reach until you rename yours. `lint:shadows-dsl-function` points at the definition.
24
+
25
+ - 565ef67: Strings, object literals and indexes in scenarios.
26
+
27
+ - A string value answers `s.length`, `s.trim()`, `s.includes(search)` and `s.startsWith(prefix)` — in asserts, in conditions, on literals and on call results (`assertTrue(getTitle().trim().length > 0)`). Any other member (`s.padStart(3)`) is a lint error, `validator:unsupported-string-member`, that names it and lists the four. A member of the list used on a value that is not a string at run time fails the step with the value's type in the message.
28
+ - An object literal is a value: `h = {x: 1, y: "z"}` can be kept in a variable, nested (`{a: {b: [1]}}`) and passed to a helper. A slot that wants a specific kind (a string, a locator) still rejects an object with its `arg-kind` error.
29
+ - An index works anywhere in a chain: `res.body.items[0].id`, `dbQuery(sql)[0].id`, `a.b[1][0]` — no temporary variable. Indexing a locator is still rejected.
30
+ - The lint hints for JS string habits now point at the string members (`indexOf` → `use s.includes(needle)`).
31
+
32
+ - 5ac6c72: `teardown("label", () => { … })` — give the stand back whatever happens.
33
+
34
+ - A scenario registers a rollback block where it turns something on; after the test body every registered block runs, newest first, whether the test passed, failed, ran out of time or was stopped — including a run stopped while paused at its failure (the debugger, `run_test`). One failing block does not stop the others. Flows and helpers can carry their own rollback.
35
+ - A green test whose teardown failed is failed; a failed test keeps its own error and lists the teardown failures next to it (CLI, `run_test` → `next.teardownFailures`, `runtime.json`). The failure bundle is taken before the rollback, so it shows the page the test broke on.
36
+ - The CLI prints `↺ teardown "…"` per block; the journal gets `teardown:started` / `teardown:finished` / `teardown:skipped` events and a `teardown` flag on the block frame; the viewer marks those frames and shows "returning the stand…" while a stopped run rolls back.
37
+ - Stop now rolls back first: the first Stop (viewer, `abort_runtime`, SIGTERM, Ctrl-C) plays the teardown blocks and then ends the run; a second Stop skips what is left and says so. `abort_runtime` answers `status: "returning the stand…"` while that happens.
38
+ - New config key `teardownTimeoutMs` (default 60000): the ceiling for all teardown blocks of a run, separate from the run's own time budget. A killed process, or blocks cut by this ceiling, leave the stand as the test set it — the run result names them.
39
+ - Lint: `teardown-shape` (string-literal label, no `return` / `break` out of the block, no nested teardown) and `teardown-name-conflict`.
40
+
41
+ **Breaking for scenarios that define their own `teardown`.** A function, parameter or variable named `teardown` is now a lint error (`teardown-name-conflict`), and a statement-level call `teardown(x)` no longer parses as a call. Rename it, e.g. to `undo_setup`.
42
+
43
+ - d1605b2: `assertScreenshot` — the page, or an element, against a PNG baseline in the repo.
44
+
45
+ - `assertScreenshot(name, options?)` / `assertScreenshot(locator, name, options?)` compares a snapshot with `unotest/e2e/<scenario>.screenshots/<name>.png` — a Figma export or a snapshot you accepted. A pixel differs when any channel differs by more than `threshold` (default 32); the assert fails when the share of differing pixels is more than `maxDiffRatio` (default 0) — exactly the limit passes. `mask: [locator…]` and `ignore: [{x, y, width, height}…]` leave areas out of the comparison on both sides. A different size fails at once with both sizes; nothing is resampled. `fullPage: true` compares the whole page.
46
+ - No baseline yet: the assert fails and the snapshot is saved in the run's artifacts as a candidate under the baseline's file name. `e2e --update-screenshots` (MCP: `run_test {updateScreenshots: true}`) writes the snapshots as baselines; it is refused on a box.
47
+ - A failed assert keeps `expected`, `actual` and `diff` pictures (per retry attempt); the viewer shows them side by side on the failed step with a "Download as baseline" button, the failure bundle points at them, and `run_test` returns them in `next.visual`. `box run --download` / `box_run_download` unpack baseline candidates next to the zip.
48
+ - A baseline is read as untrusted input: an image over 25 megapixels, or one whose data unpacks to more than its header allows, is refused before it is decoded.
49
+ - The journal gets a `visual-assert` event per assert; `runtime.json` carries the last failed one as `visual`.
50
+ - A suite over 128 MB is warned about before the upload — boxes accept 128 MB by default — naming its biggest files and baselines.
51
+
52
+ New dependency of `@unotest/web`: `pngjs` 7.0.0 (MIT, no dependencies of its own), the PNG codec behind the comparison.
53
+
54
+ - 3939ae6: Window size and scale: set them in the config, per MCP call, or mid-scenario.
55
+
56
+ - **`viewport.deviceScaleFactor`** in `unotest.config`. `{ width: 390, height: 844, deviceScaleFactor: 2 }` makes every screenshot 780×1688, the scale design mockups are usually drawn at. Every `viewport` field is now optional: a missing one comes from `device` or from the 1280×720 default. A config without `viewport` opens at 1280×720, as before.
57
+ - **`device`** in the config: a Playwright device preset by its exact name (`"iPhone 14"`, `"Pixel 7"`), applied whole — size, scale, touch, mobile mode, user agent. `viewport` next to it overrides the preset field by field. An unknown name is refused with the nearest ones. A mobile preset on Firefox is refused: Firefox has no mobile mode. A preset's viewport is the page area, smaller than the screen: `"iPhone 14"` is 390×664. To match a 390×844 mockup, set `viewport` explicitly.
58
+ - **MCP `new_context`** takes `viewport` and `device`, and opens the context at that window. **`explore_start`** takes them too when no browser is open yet. With a browser already open it refuses and points to `new_context`. Before this, `new_context` accepted any argument, ignored it and answered success. Now an unknown argument is refused and the reply names the accepted fields.
59
+ - **New DSL function `setViewport({width, height})`.** It resizes every open tab in place, with no reload, and tabs opened later start at the same size. `deviceScaleFactor` is refused here: the scale is fixed when the browser opens.
60
+
61
+ ### Patch Changes
62
+
63
+ - 3780074: A finished run opened from history keeps its rollback pass: the viewer no longer drops `teardown:started` / `teardown:finished` / `teardown:skipped` from a stored journal, so the teardown frames of a stopped run show next to the step it was stopped in — not inside it — as they do while the run is live.
64
+ - 99ba57f: The run budget (`UNOTEST_MAX_DURATION_MS`, `maxDurationMs`) is now a deadline, not a check between statements.
65
+
66
+ - **Behaviour change:** a run whose last action took it past the budget used to finish green, and so did a run whose single action outlasted the whole budget. Both are now red with `maxDurationMs budget (…ms) exhausted`, reported on the action that spent it.
67
+ - An action still running when the budget runs out is abandoned at that moment instead of being waited for. Its browser call is not killed: it ends at its own timeout or when the context closes, and its late failure is not reported. Teardown blocks still run afterwards, on their own `teardownTimeoutMs`.
68
+ - Every budget now fails with a typed `BudgetExhaustedError` (`setting: "maxSteps" | "maxDurationMs" | "teardownTimeoutMs"`, `kind: "steps" | "duration"`). The message names the setting that was spent: a teardown cut by its own ceiling says `teardownTimeoutMs (…ms) exhausted — the rollback did not finish`, as before, not the run's budget.
69
+
70
+ - d66cf72: `readBounded(handle, size, max)` reads an open file into a buffer of its measured size plus one byte: a file over `max` is refused before anything is allocated, and one that grew after it was measured is refused rather than read in part (`BoundedReadError`). Reading a screenshot baseline no longer reserves memory for the largest file allowed — only for the file there is.
71
+ - 832c101: `resume` and `step` now answer with the stop that comes after the command, not the pause the run was already in.
72
+
73
+ A paused run keeps refreshing its runtime file, and the tools took a fresh timestamp on a paused state for the next pause. An agent could be told the run had moved on while it still sat at the old breakpoint, and take the wheel there. The runner now counts its pauses in `runtime.json` (`pauseSeq`, one more on every pause, the same line again included), and `resume` / `step` wait for that count to grow or for the run to end. A run from an older runner, without the count, is waited on as before.
74
+
75
+ - b613684: A screenshot the browser refuses to capture is asked for once more. Chromium now and then refuses a frame on a busy machine, and `assertScreenshot`, `screenshot()` and the MCP screenshot step used to fail on the first refusal with a raw protocol error. A second refusal is now `ScreenCaptureError`, which names the browser's reason and what to do. A closed page or a timeout is not retried.
76
+ - e417c08: A stopped run never ends silently: if the first Stop's rollback — or what runs before it, such as framing a paused failure — is still going at `teardownTimeoutMs` plus 15 seconds, the runner prints that it is exiting without finishing the rollback, then exits. A rollback block cut as hung is named in the output. The DSL reference now states both Stop limits: the rollback budget with its 15-second exit margin, and the viewer's 5-minute force-kill as a safety net only.
77
+ - Updated dependencies [816e2ea]
78
+ - Updated dependencies [565ef67]
79
+ - Updated dependencies [5ac6c72]
80
+ - Updated dependencies [d1605b2]
81
+ - Updated dependencies [3780074]
82
+ - Updated dependencies [99ba57f]
83
+ - Updated dependencies [d66cf72]
84
+ - Updated dependencies [832c101]
85
+ - @unotest/protocol@0.44.0
86
+ - @unotest/viewer@0.44.0
87
+ - @unotest/dsl@0.44.0
88
+ - @unotest/core@0.44.0
89
+ - @unotest/grounder-client@0.44.0
90
+
3
91
  ## [0.43.2] - 2026-09-30
4
92
 
5
93
  ### Patch Changes
@@ -1366,7 +1454,7 @@ picker on` fetches this project's own access and writes the three grounder
1366
1454
 
1367
1455
  That screen named one command:
1368
1456
 
1369
- npx @unotest/web bundle push --run --env ENVIRONMENT
1457
+ npx @unotest/web bundle push --run --env ENVIRONMENT
1370
1458
 
1371
1459
  In a project that has just been created, the command refuses with `no box
1372
1460
  address` before it does anything: the project holds neither the box's address
@@ -1375,8 +1463,8 @@ address` before it does anything: the project holds neither the box's address
1375
1463
 
1376
1464
  The screen now names both steps, in the order they have to happen:
1377
1465
 
1378
- npx @unotest/web box access larch
1379
- npx @unotest/web bundle push --run --env ENVIRONMENT
1466
+ npx @unotest/web box access larch
1467
+ npx @unotest/web bundle push --run --env ENVIRONMENT
1380
1468
 
1381
1469
  The box's own name is filled in when its licence carries one. `box access`
1382
1470
  with no name refuses, and its refusal offers to create a box — to somebody who
@@ -20,14 +20,19 @@ declare const BROWSER_CHANNEL_WORDS: readonly ["chrome", "msedge", "chrome-beta"
20
20
  declare const BrowserChannelSchema: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["chrome", "msedge", "chrome-beta", "chromium"]>, z.ZodEffects<z.ZodLiteral<"bundled">, null, "bundled">, z.ZodNull]>>;
21
21
  type BrowserChannel = z.infer<typeof BrowserChannelSchema>;
22
22
  declare const ViewportSchema: z.ZodObject<{
23
- width: z.ZodNumber;
24
- height: z.ZodNumber;
23
+ width: z.ZodOptional<z.ZodNumber>;
24
+ height: z.ZodOptional<z.ZodNumber>;
25
+ /** CSS pixel → device pixel ratio: 2 makes a 390×844 page a 780×1688
26
+ * screenshot, the scale design mockups are usually drawn at. */
27
+ deviceScaleFactor: z.ZodOptional<z.ZodNumber>;
25
28
  }, "strict", z.ZodTypeAny, {
26
- width: number;
27
- height: number;
29
+ width?: number | undefined;
30
+ height?: number | undefined;
31
+ deviceScaleFactor?: number | undefined;
28
32
  }, {
29
- width: number;
30
- height: number;
33
+ width?: number | undefined;
34
+ height?: number | undefined;
35
+ deviceScaleFactor?: number | undefined;
31
36
  }>;
32
37
  type Viewport = z.infer<typeof ViewportSchema>;
33
38
  declare const RetryReasonSchema: z.ZodEnum<["transient", "network", "crash"]>;
@@ -104,19 +109,19 @@ declare const FailureBundleConfigSchema: z.ZodObject<{
104
109
  type FailureBundleConfig = z.infer<typeof FailureBundleConfigSchema>;
105
110
  declare const DialogPolicySchema: z.ZodEnum<["accept", "dismiss", "manual"]>;
106
111
  type DialogPolicy = z.infer<typeof DialogPolicySchema>;
107
- 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", "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"]>;
112
+ 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", "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"]>;
108
113
  type LinterRuleId = z.infer<typeof LinterRuleIdSchema>;
109
114
  declare const LinterSeveritySchema: z.ZodEnum<["off", "warn", "error"]>;
110
115
  type LinterSeverity = z.infer<typeof LinterSeveritySchema>;
111
116
  declare const LinterConfigSchema: z.ZodObject<{
112
117
  enabled: z.ZodBoolean;
113
- 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", "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"]>>;
118
+ 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", "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"]>>;
114
119
  }, "strict", z.ZodTypeAny, {
115
120
  enabled: boolean;
116
- 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" | "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">>;
121
+ 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" | "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">>;
117
122
  }, {
118
123
  enabled: boolean;
119
- 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" | "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">>;
124
+ 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" | "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">>;
120
125
  }>;
121
126
  type LinterConfig = z.infer<typeof LinterConfigSchema>;
122
127
  declare const QueueConfigSchema: z.ZodObject<{
@@ -286,16 +291,39 @@ declare const UnotestConfigSchema: z.ZodObject<{
286
291
  }>>;
287
292
  browsers: z.ZodArray<z.ZodEnum<["chromium", "firefox", "webkit"]>, "many">;
288
293
  channel: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["chrome", "msedge", "chrome-beta", "chromium"]>, z.ZodEffects<z.ZodLiteral<"bundled">, null, "bundled">, z.ZodNull]>>;
289
- viewport: z.ZodObject<{
290
- width: z.ZodNumber;
291
- height: z.ZodNumber;
294
+ viewport: z.ZodOptional<z.ZodObject<{
295
+ width: z.ZodOptional<z.ZodNumber>;
296
+ height: z.ZodOptional<z.ZodNumber>;
297
+ /** CSS pixel → device pixel ratio: 2 makes a 390×844 page a 780×1688
298
+ * screenshot, the scale design mockups are usually drawn at. */
299
+ deviceScaleFactor: z.ZodOptional<z.ZodNumber>;
292
300
  }, "strict", z.ZodTypeAny, {
293
- width: number;
294
- height: number;
301
+ width?: number | undefined;
302
+ height?: number | undefined;
303
+ deviceScaleFactor?: number | undefined;
295
304
  }, {
296
- width: number;
297
- height: number;
298
- }>;
305
+ width?: number | undefined;
306
+ height?: number | undefined;
307
+ deviceScaleFactor?: number | undefined;
308
+ }>>;
309
+ /** A device preset by its Playwright name (`"iPhone 14"`, `"Pixel 7"`):
310
+ * size, scale, touch, mobile mode and user agent at once. `viewport`
311
+ * next to it overrides the preset's size. The name is checked by the
312
+ * driver when a context opens — the list is Playwright's, and this
313
+ * schema is imported where Playwright is not installed. */
314
+ device: z.ZodOptional<z.ZodString>;
315
+ /** IANA time zone of every page (`"Europe/Madrid"`): `Date#toString`,
316
+ * `Intl` and `getTimezoneOffset` answer in it. Unset → the machine's.
317
+ * `UNOTEST_TIMEZONE` overrides it. */
318
+ timezone: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
319
+ /** BCP 47 locale of every page (`"es-ES"`): `navigator.language`, `Intl`
320
+ * defaults, Accept-Language. Unset → the browser's. `UNOTEST_LOCALE`
321
+ * overrides it. */
322
+ locale: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
323
+ /** Browser contexts one test may hold at once — the run's own plus
324
+ * every `newContext()`. The next one past it is refused: a guard
325
+ * against a loop that opens a browser per iteration. Default 4. */
326
+ maxContexts: z.ZodOptional<z.ZodNumber>;
299
327
  /** How the browser is started: a profile and extra arguments
300
328
  * (`config/launch.ts`). Unset → as before: a fresh browser, a fresh
301
329
  * context per scenario. */
@@ -398,6 +426,12 @@ declare const UnotestConfigSchema: z.ZodObject<{
398
426
  * slow-but-correct navigation.
399
427
  * Override via `UNOTEST_DEFAULT_NAVIGATION_TIMEOUT_MS`. */
400
428
  defaultNavigationTimeoutMs: z.ZodNumber;
429
+ /** Wall-clock ceiling for a run's rollback pass — every `teardown(...)`
430
+ * block together. Separate from the run's own time budget on purpose: a
431
+ * test that failed BY that budget still has to give the stand back.
432
+ * Unset → 60000. A pass cut by it leaves the rest of the stand as the
433
+ * test set it, and the run result says which blocks did not finish. */
434
+ teardownTimeoutMs: z.ZodOptional<z.ZodNumber>;
401
435
  /** Cross-environment declarations (`.env.<name>` overlays). */
402
436
  env: z.ZodObject<{
403
437
  /** Variable names whose base `.env` value is deliberately shared by
@@ -411,13 +445,13 @@ declare const UnotestConfigSchema: z.ZodObject<{
411
445
  }>;
412
446
  linter: z.ZodObject<{
413
447
  enabled: z.ZodBoolean;
414
- 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", "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"]>>;
448
+ 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", "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"]>>;
415
449
  }, "strict", z.ZodTypeAny, {
416
450
  enabled: boolean;
417
- 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" | "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">>;
451
+ 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" | "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">>;
418
452
  }, {
419
453
  enabled: boolean;
420
- 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" | "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">>;
454
+ 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" | "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">>;
421
455
  }>;
422
456
  mcp: z.ZodObject<{
423
457
  transport: z.ZodLiteral<"stdio">;
@@ -513,10 +547,6 @@ declare const UnotestConfigSchema: z.ZodObject<{
513
547
  defaultTimeoutMs: number;
514
548
  defaultNavigationTimeoutMs: number;
515
549
  browsers: ("chromium" | "firefox" | "webkit")[];
516
- viewport: {
517
- width: number;
518
- height: number;
519
- };
520
550
  retry: {
521
551
  count: number;
522
552
  on: ("network" | "transient" | "crash")[];
@@ -543,7 +573,7 @@ declare const UnotestConfigSchema: z.ZodObject<{
543
573
  };
544
574
  linter: {
545
575
  enabled: boolean;
546
- 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" | "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">>;
576
+ 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" | "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">>;
547
577
  };
548
578
  mcp: {
549
579
  transport: "stdio";
@@ -566,6 +596,8 @@ declare const UnotestConfigSchema: z.ZodObject<{
566
596
  apiBaseUrl?: string | undefined;
567
597
  uploadDir?: string | undefined;
568
598
  };
599
+ locale?: string | undefined;
600
+ timezone?: string | undefined;
569
601
  baseUrl?: string | undefined;
570
602
  webServer?: {
571
603
  url: string;
@@ -574,19 +606,23 @@ declare const UnotestConfigSchema: z.ZodObject<{
574
606
  reuseExistingServer: boolean;
575
607
  } | undefined;
576
608
  channel?: "chrome" | "msedge" | "chrome-beta" | "chromium" | null | undefined;
609
+ viewport?: {
610
+ width?: number | undefined;
611
+ height?: number | undefined;
612
+ deviceScaleFactor?: number | undefined;
613
+ } | undefined;
614
+ device?: string | undefined;
615
+ maxContexts?: number | undefined;
577
616
  launch?: {
578
617
  args?: string[] | undefined;
579
618
  userDataDir?: string | undefined;
580
619
  } | undefined;
581
620
  storageState?: string | undefined;
621
+ teardownTimeoutMs?: number | undefined;
582
622
  }, {
583
623
  defaultTimeoutMs: number;
584
624
  defaultNavigationTimeoutMs: number;
585
625
  browsers: ("chromium" | "firefox" | "webkit")[];
586
- viewport: {
587
- width: number;
588
- height: number;
589
- };
590
626
  retry: {
591
627
  count: number;
592
628
  on: ("network" | "transient" | "crash")[];
@@ -613,7 +649,7 @@ declare const UnotestConfigSchema: z.ZodObject<{
613
649
  };
614
650
  linter: {
615
651
  enabled: boolean;
616
- 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" | "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">>;
652
+ 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" | "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">>;
617
653
  };
618
654
  mcp: {
619
655
  transport: "stdio";
@@ -630,6 +666,8 @@ declare const UnotestConfigSchema: z.ZodObject<{
630
666
  apiBaseUrl?: string | undefined;
631
667
  uploadDir?: string | undefined;
632
668
  };
669
+ locale?: string | undefined;
670
+ timezone?: string | undefined;
633
671
  baseUrl?: string | undefined;
634
672
  webServer?: {
635
673
  url: string;
@@ -638,11 +676,19 @@ declare const UnotestConfigSchema: z.ZodObject<{
638
676
  reuseExistingServer?: boolean | undefined;
639
677
  } | undefined;
640
678
  channel?: "chrome" | "msedge" | "chrome-beta" | "chromium" | "bundled" | null | undefined;
679
+ viewport?: {
680
+ width?: number | undefined;
681
+ height?: number | undefined;
682
+ deviceScaleFactor?: number | undefined;
683
+ } | undefined;
684
+ device?: string | undefined;
685
+ maxContexts?: number | undefined;
641
686
  launch?: {
642
687
  args?: string[] | undefined;
643
688
  userDataDir?: string | undefined;
644
689
  } | undefined;
645
690
  storageState?: string | undefined;
691
+ teardownTimeoutMs?: number | undefined;
646
692
  schedules?: {
647
693
  collection: string;
648
694
  cron: string;
@@ -1 +1 @@
1
- var _0x14f507=_0x26f9;(function(_0x5575a5,_0x2c08b9){var _0x104177={_0x1ddfca:0x131,_0x7410b2:0x10f,_0x3db77c:0x139,_0x5a0e30:0x107,_0x1cada0:0x117,_0x27734c:0x121},_0x1443de=_0x26f9,_0x1a5570=_0x5575a5();while(!![]){try{var _0x14cc5f=parseInt(_0x1443de(0x11f))/0x1*(parseInt(_0x1443de(_0x104177._0x1ddfca))/0x2)+-parseInt(_0x1443de(_0x104177._0x7410b2))/0x3*(-parseInt(_0x1443de(0xf4))/0x4)+-parseInt(_0x1443de(0x10c))/0x5*(-parseInt(_0x1443de(_0x104177._0x3db77c))/0x6)+-parseInt(_0x1443de(0xf2))/0x7*(-parseInt(_0x1443de(0x123))/0x8)+parseInt(_0x1443de(_0x104177._0x5a0e30))/0x9*(parseInt(_0x1443de(_0x104177._0x1cada0))/0xa)+parseInt(_0x1443de(0x133))/0xb+-parseInt(_0x1443de(_0x104177._0x27734c))/0xc;if(_0x14cc5f===_0x2c08b9)break;else _0x1a5570['push'](_0x1a5570['shift']());}catch(_0xa7e7c8){_0x1a5570['push'](_0x1a5570['shift']());}}}(_0x347e,0xe35b6));var __defProp=Object['defineProperty'],__name=(_0x150d5a,_0xc62c67)=>__defProp(_0x150d5a,_0x14f507(0x11b),{'value':_0xc62c67,'configurable':!![]});import{z as _0x3d70ee}from'zod';function _0x347e(){var _0x163dba=['C3rYAwn0','mti0v2jSywXP','BgLUDdPVyMz1C2nHDgvKlwnSyxnZ','DMfSAwrHDg9YoMzVCI1ZAgfWzq','DxjS','DMfSAwrHDg9YoNDYyxbWzwqTzM9YBwf0','Dw5RBM93BIbRzxKGiG','BNvSBa','DMfSAwrHDg9YoNn0zxaTC2HHCgu','yxjYyxK','zNvSBa','C3rKAw8','zxjYB3jnyxa','DMfSAwrHDg9YoNn0CMLUzY1JB25Jyxq','zgvMyxvSDa','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlxn0yxrLBwvUDa','y2HYB21PDw0','BwLU','AM9PBG','Dw5VDgvZDc9LmMuVx2HLBhbLCNm','ntm1mJngDgnNvxm','BgLUDdPSAw50lw9Rlw1PC3nPBMCTCMvHC29U','D2fYBG','DMfSAwrHDg9YoMLMlxnOyxbL','Aw50','ndaWyxbhsLLW','A2v5CW','yM9VBgvHBG','mZmWodfRvhLozKe','BgLUDdPKAxnHBwjPzY1IEs1PBMrLEa','y3jHC2G','BMv0D29YAW','BgLUDdPVBMuTDgvZDc1WzxiTzMLSzq','zxjYB3i','BgLUDdPWyxvZzs1LEhbSAwnPDa','Dg9mB3DLCKnHC2u','nZeWzgTpD252','DMfSAwrHDg9YoMz1BMn0Aw9UlxnOyxbL','BgL0zxjHBa','BgLUDdPKzwvWlwnZCW','BMfTzq','DMfSAwrHDg9YoMfYAxr5','BgLUDdPHCgKTy2fSBc1MAwXLlwjVzhK','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlwv4ChjLC3nPB24','mtG1mJa1mwvfuxLLBq','C3rYAwn0t2jQzwn0','nti2nJi5odryB3r1vfC','DMfSAwrHDg9YoNn0zxaTy292zxjHz2u','nZi1nNjUDejTrq','DMfSAwrHDg9YoNnLBwfUDgLJlwXVC3m','zgLZBwLZCW','BgLUDdPLy2HVlwfZC2vYDa','BgLUDdPZy2vUyxjPBY1PBI1YB290','CMvJB3jK','zw51Bq','DMfSAwrHDg9YoNvUA25VD24TzNvUy3rPB24','C3rYAw5N','B3b0Aw9UywW','BNvTyMvY','ywnJzxb0','BwfW','DMfSAwrHDg9YoMXPC3qTyxjN','mMHPy0PhAq','y29Kzq','mZK5nZK2mxDcBgXnEG','y2HYB21L','DMfSAwrHDg9YoNzHCI1ZAgfWzq','y2HYB21LlwjLDge','B2zM','BgLUDdPTDxn0ywnOzs1PBI1KC2W','mteXntC2wxPJsfrx','zgLZDgfUy2u','zgvMyxvSDevYCM9Y','BgLUDdP4Cgf0Aa','Dw5YzwnVz25PEMvKx2TLExm','y2XVC2vZDeTLEq','B2jQzwn0','Cg9ZAxrPDMu','DhjHBNnPzw50','BgLUDdPNB3rVlwnVBMnHDa','A2v5','BgLUDdPLBNyTAg9ZDc1MCM9TlwjHC2u','D2vIA2L0','BxnLzgDL','BgLUDdPLEhrLCM5HBc12yxjPywjSzs11BMrLy2XHCMvK','zMLYzwzVEa','Dw5RBM93BKTLEu1LC3nHz2u','nJu4merutM1ksG'];_0x347e=function(){return _0x163dba;};return _0x347e();}import{z}from'zod';import{levenshteinDistance}from'@unotest/core';var MAX_EDITS=0x2;function closestKey(_0x100013,_0x405cc3){var _0x1e6e7c={_0x47fc35:0x116},_0xf87393=_0x14f507;let _0x1a132e;for(const _0x5bc5b1 of _0x405cc3){const _0x2a2ede=levenshteinDistance(_0x100013[_0xf87393(0x116)](),_0x5bc5b1[_0xf87393(_0x1e6e7c._0x47fc35)]());if(_0x2a2ede>MAX_EDITS)continue;if(_0x1a132e===void 0x0||_0x2a2ede<_0x1a132e[_0xf87393(0x13a)])_0x1a132e={'key':_0x5bc5b1,'distance':_0x2a2ede};}return _0x1a132e?.[_0xf87393(0xeb)];}__name(closestKey,_0x14f507(0x13e));function unknownKeyMessage(_0x450cf7,_0x157ab7){var _0x4ff0e8={_0xfe46e:0xf9},_0x4c3292=_0x14f507;return _0x450cf7[_0x4c3292(0x12f)](_0x3e5a78=>{var _0x114484=_0x4c3292;const _0x2f4e59=closestKey(_0x3e5a78,_0x157ab7);return _0x2f4e59===void 0x0?_0x114484(0xf9)+_0x3e5a78+'\x22\x20—\x20not\x20a\x20config\x20key;\x20check\x20your\x20@unotest/web\x20version\x20if\x20it\x20comes\x20from\x20a\x20newer\x20release':_0x114484(_0x4ff0e8._0xfe46e)+_0x3e5a78+'\x22\x20—\x20did\x20you\x20mean\x20\x22'+_0x2f4e59+'\x22?';})[_0x4c3292(0x105)](';\x20');}__name(unknownKeyMessage,_0x14f507(0xf1));function _0x26f9(_0x5d081d,_0x3a0c2e){_0x5d081d=_0x5d081d-0xe7;var _0x347ea3=_0x347e();var _0x26f93e=_0x347ea3[_0x5d081d];if(_0x26f9['lHlPHF']===undefined){var _0x23de78=function(_0x1228a3){var _0x2b022f='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0x3d70ee='',_0x3e4f30='';for(var _0x150d5a=0x0,_0xc62c67,_0x100013,_0x405cc3=0x0;_0x100013=_0x1228a3['charAt'](_0x405cc3++);~_0x100013&&(_0xc62c67=_0x150d5a%0x4?_0xc62c67*0x40+_0x100013:_0x100013,_0x150d5a++%0x4)?_0x3d70ee+=String['fromCharCode'](0xff&_0xc62c67>>(-0x2*_0x150d5a&0x6)):0x0){_0x100013=_0x2b022f['indexOf'](_0x100013);}for(var _0x1a132e=0x0,_0x5bc5b1=_0x3d70ee['length'];_0x1a132e<_0x5bc5b1;_0x1a132e++){_0x3e4f30+='%'+('00'+_0x3d70ee['charCodeAt'](_0x1a132e)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x3e4f30);};_0x26f9['ohjWJT']=_0x23de78,_0x26f9['ASeMoG']={},_0x26f9['lHlPHF']=!![];}var _0x41a637=_0x347ea3[0x0],_0x194252=_0x5d081d+_0x41a637,_0x4343d9=_0x26f9['ASeMoG'][_0x194252];return!_0x4343d9?(_0x26f93e=_0x26f9['ohjWJT'](_0x26f93e),_0x26f9['ASeMoG'][_0x194252]=_0x26f93e):_0x26f93e=_0x4343d9,_0x26f93e;}function strictObject(_0xfeb4d){var _0x107bf1={_0x394081:0x10d,_0x26a0ed:0xff,_0x2b9be8:0xf3},_0x31aedc=_0x14f507;const _0x3c9e92=Object[_0x31aedc(_0x107bf1._0x394081)](_0xfeb4d);return z[_0x31aedc(0xe7)](_0xfeb4d,{'errorMap':__name((_0x1d3557,_0x4dc016)=>_0x1d3557[_0x31aedc(0x132)]===z['ZodIssueCode'][_0x31aedc(0x13d)]?{'message':unknownKeyMessage(_0x1d3557[_0x31aedc(0x10d)],_0x3c9e92)}:{'message':_0x4dc016[_0x31aedc(0x13b)]},_0x31aedc(_0x107bf1._0x26a0ed))})[_0x31aedc(_0x107bf1._0x2b9be8)]();}__name(strictObject,_0x14f507(0x120));import{BUNDLED_BROWSER_CHANNEL}from'@unotest/protocol';import{z as _0x3e4f30}from'zod';import{UnotestError}from'@unotest/core';var LaunchConfigSchema=_0x3e4f30[_0x14f507(0xe7)]({'userDataDir':_0x3e4f30[_0x14f507(0x12b)]()[_0x14f507(0x104)](0x1)[_0x14f507(0x12c)](),'args':_0x3e4f30[_0x14f507(0xfc)](_0x3e4f30['string']()[_0x14f507(0x104)](0x1))[_0x14f507(0x12c)]()})[_0x14f507(0xf3)](),BrowserSchema=_0x3d70ee['enum'](['chromium',_0x14f507(0xf0),_0x14f507(0xed)]),SYSTEM_BROWSER_CHANNELS=[_0x14f507(0x134),_0x14f507(0xee),_0x14f507(0x136),_0x14f507(0x103)],BROWSER_CHANNEL_WORDS=[...SYSTEM_BROWSER_CHANNELS,BUNDLED_BROWSER_CHANNEL],BrowserChannelSchema=_0x3d70ee['union']([_0x3d70ee[_0x14f507(0x129)](SYSTEM_BROWSER_CHANNELS),_0x3d70ee[_0x14f507(0x119)](BUNDLED_BROWSER_CHANNEL)['transform'](()=>null),_0x3d70ee[_0x14f507(0xfa)]()])[_0x14f507(0x12c)](),ViewportSchema=strictObject({'width':_0x3d70ee[_0x14f507(0x12d)]()['int']()[_0x14f507(0xe8)](),'height':_0x3d70ee[_0x14f507(0x12d)]()[_0x14f507(0x10b)]()[_0x14f507(0xe8)]()}),RetryReasonSchema=_0x3d70ee[_0x14f507(0x129)]([_0x14f507(0xe9),_0x14f507(0x112),_0x14f507(0x111)]),RetryConfigSchema=strictObject({'count':_0x3d70ee[_0x14f507(0x12d)]()[_0x14f507(0x10b)]()[_0x14f507(0x104)](0x0)['max'](0xa),'on':_0x3d70ee[_0x14f507(0xfc)](RetryReasonSchema)}),FailureBundleConfigSchema=strictObject({'tier1':_0x3d70ee['literal'](!![])[_0x14f507(0x101)](!![]),'tier2':_0x3d70ee[_0x14f507(0x10e)](),'tier3':strictObject({'network':_0x3d70ee[_0x14f507(0x10e)](),'video':_0x3d70ee[_0x14f507(0x10e)]()}),'retention':strictObject({'runs':_0x3d70ee[_0x14f507(0x12d)]()['int']()[_0x14f507(0xe8)](),'days':_0x3d70ee['number']()[_0x14f507(0x10b)]()['positive']()}),'storageDir':_0x3d70ee['string']()['min'](0x1),'pageHtml':_0x3d70ee[_0x14f507(0x129)](['redacted',_0x14f507(0xfd)])}),DialogPolicySchema=_0x3d70ee[_0x14f507(0x129)]([_0x14f507(0x12e),_0x14f507(0x125),'manual']),LinterRuleIdSchema=_0x3d70ee[_0x14f507(0x129)]([_0x14f507(0x11a),_0x14f507(0x13c),_0x14f507(0xf5),_0x14f507(0x115),_0x14f507(0x110),'lint:evaluate-discouraged',_0x14f507(0x127),_0x14f507(0x138),_0x14f507(0xea),'lint:regex-invalid',_0x14f507(0x126),_0x14f507(0x11d),_0x14f507(0x108),'lint:flow-returns-value','lint:legacy-layout',_0x14f507(0xef),_0x14f507(0xec),_0x14f507(0x113),_0x14f507(0x12a),_0x14f507(0x11c),'validator:arg-kind',_0x14f507(0x122),_0x14f507(0xfb),'validator:meta-shape',_0x14f507(0x118),_0x14f507(0xf6),_0x14f507(0x10a),_0x14f507(0x135),_0x14f507(0x102),_0x14f507(0x11e),_0x14f507(0x100),_0x14f507(0x124),_0x14f507(0x130),_0x14f507(0xf8)]),LinterSeveritySchema=_0x3d70ee[_0x14f507(0x129)]([_0x14f507(0x137),_0x14f507(0x109),_0x14f507(0x114)]),LinterConfigSchema=strictObject({'enabled':_0x3d70ee[_0x14f507(0x10e)](),'rules':_0x3d70ee[_0x14f507(0x128)](LinterRuleIdSchema,LinterSeveritySchema)}),QueueConfigSchema=strictObject({'enabled':_0x3d70ee['boolean']()[_0x14f507(0x101)](!![]),'concurrency':_0x3d70ee['number']()['int']()[_0x14f507(0xe8)]()[_0x14f507(0x101)](0x1)}),ScheduleSchema=strictObject({'collection':_0x3d70ee[_0x14f507(0x12b)]()[_0x14f507(0x104)](0x1),'cron':_0x3d70ee[_0x14f507(0x12b)]()[_0x14f507(0x104)](0x1),'env':_0x3d70ee[_0x14f507(0x12b)]()[_0x14f507(0x104)](0x1)[_0x14f507(0x12c)](),'prepare':_0x3d70ee['string']()['min'](0x1)[_0x14f507(0x12c)]()}),McpConfigSchema=strictObject({'transport':_0x3d70ee['literal'](_0x14f507(0xfe))}),SandboxConfigSchema=strictObject({'shellCwd':_0x3d70ee['string']()[_0x14f507(0x12c)](),'shellTimeoutMs':_0x3d70ee[_0x14f507(0x12d)]()[_0x14f507(0x10b)]()[_0x14f507(0xe8)]()[_0x14f507(0x12c)](),'exportSecrets':_0x3d70ee[_0x14f507(0xfc)](_0x3d70ee[_0x14f507(0x12b)]())[_0x14f507(0x12c)](),'database':_0x3d70ee['string']()[_0x14f507(0x12c)](),'apiBaseUrl':_0x3d70ee[_0x14f507(0x12b)]()[_0x14f507(0xf7)]()[_0x14f507(0x12c)](),'uploadDir':_0x3d70ee[_0x14f507(0x12b)]()['optional']()}),WebServerConfigSchema=strictObject({'command':_0x3d70ee[_0x14f507(0x12b)]()['min'](0x1),'url':_0x3d70ee['string']()[_0x14f507(0xf7)](),'reuseExistingServer':_0x3d70ee[_0x14f507(0x10e)]()[_0x14f507(0x101)](!![]),'timeoutMs':_0x3d70ee['number']()[_0x14f507(0x10b)]()['positive']()[_0x14f507(0x101)](0xea60)}),EnvConfigSchema=strictObject({'shared':_0x3d70ee[_0x14f507(0xfc)](_0x3d70ee[_0x14f507(0x12b)]())[_0x14f507(0x101)]([])}),UnotestConfigSchema=strictObject({'baseUrl':_0x3d70ee[_0x14f507(0x12b)]()[_0x14f507(0xf7)]()[_0x14f507(0x12c)](),'webServer':WebServerConfigSchema[_0x14f507(0x12c)](),'browsers':_0x3d70ee[_0x14f507(0xfc)](BrowserSchema)['min'](0x1),'channel':BrowserChannelSchema,'viewport':ViewportSchema,'launch':LaunchConfigSchema[_0x14f507(0x12c)](),'retry':RetryConfigSchema,'failureBundle':FailureBundleConfigSchema,'dialogPolicy':DialogPolicySchema,'storageState':_0x3d70ee['string']()['optional'](),'testDir':_0x3d70ee['string']()[_0x14f507(0x104)](0x1),'helpersDir':_0x3d70ee[_0x14f507(0x12b)]()[_0x14f507(0x104)](0x1),'defaultTimeoutMs':_0x3d70ee['number']()[_0x14f507(0x10b)]()['positive'](),'defaultNavigationTimeoutMs':_0x3d70ee[_0x14f507(0x12d)]()[_0x14f507(0x10b)]()['positive'](),'env':EnvConfigSchema,'linter':LinterConfigSchema,'mcp':McpConfigSchema,'queue':QueueConfigSchema,'schedules':_0x3d70ee[_0x14f507(0xfc)](ScheduleSchema)[_0x14f507(0x101)]([]),'sandbox':SandboxConfigSchema}),DEFAULT_CONFIG={'browsers':[_0x14f507(0x103)],'viewport':{'width':0x500,'height':0x2d0},'retry':{'count':0x0,'on':['transient']},'failureBundle':{'tier1':!![],'tier2':!![],'tier3':{'network':![],'video':![]},'retention':{'runs':0x14,'days':0x7},'storageDir':'.unotest/failures','pageHtml':'redacted'},'dialogPolicy':_0x14f507(0x12e),'testDir':'unotest/e2e','helpersDir':_0x14f507(0x106),'defaultTimeoutMs':0xbb8,'defaultNavigationTimeoutMs':0x7530,'linter':{'enabled':!![],'rules':{'lint:deep-css':_0x14f507(0x109),'lint:xpath':_0x14f507(0x109),'lint:obfuscated-class':_0x14f507(0x109),'lint:pause-explicit':_0x14f507(0x109),'lint:disambig-by-index':_0x14f507(0x137),'lint:evaluate-discouraged':_0x14f507(0x109),'lint:scenario-in-root':_0x14f507(0x114),'lint:mustache-in-dsl':_0x14f507(0x114),'lint:goto-concat':_0x14f507(0x109),'lint:regex-invalid':'error','lint:echo-assert':'warn','lint:lint-ok-missing-reason':_0x14f507(0x109),'lint:flow-returns-value':_0x14f507(0x109),'lint:legacy-layout':_0x14f507(0x109),'lint:external-variable-undeclared':'error','lint:env-host-from-base':_0x14f507(0x114),'lint:one-test-per-file':_0x14f507(0x109),'validator:unknown-function':'error'}},'env':{'shared':[]},'mcp':{'transport':_0x14f507(0xfe)},'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};
1
+ var _0x32c00a=_0x43f6;function _0x4910(){var _0x3628ac=['D2fYBG','B3b0Aw9UywW','ntmYmJzKsxrmAeW','lNvUB3rLC3qVzMfPBhvYzxm','DMfSAwrHDg9YoNn0zxaTC2HHCgu','A2v5CW','CMvKywn0zwq','mtGYBvrcrMjS','zw4Tvvm','AxnuAw1LwM9Uzq','zMLYzwzVEa','DhjHBNnPzw50','DMfSAwrHDg9YoNn0zxaTy292zxjHz2u','C3rKAw8','y29Kzq','BgLUDdPLy2HVlwfZC2vYDa','y2HYB21LlwjLDge','BgLUDdPSzwDHy3KTBgf5B3v0','Dw5VDgvZDc9LmMuVx2HLBhbLCNm','z2v0q2fUB25Py2fStg9JywXLCW','BgLUDdP4Cgf0Aa','DxjS','AM9PBG','mta4mJG2ntz3rhvdB2C','BgLUDdPSAw50lw9Rlw1PC3nPBMCTCMvHC29U','DMfSAwrHDg9YoMz1BMn0Aw9UlxnOyxbL','BMfTzq','y3jHC2G','y2XVC2vZDeTLEq','Bwf4','Dw5RBM93BKTLEu1LC3nHz2u','Dg9mB3DLCKnHC2u','BgL0zxjHBa','yxjYyxK','iIdIGjqGzgLKihLVDsbTzwfUici','DMfSAwrHDg9YoNnLBwfUDgLJlwXVC3m','BgLUDdPNB3rVlwnVBMnHDa','Aw50','mJC4mdCYtKPxAxHi','CMvMAw5L','D2vIA2L0','zgLZBwLZCW','BgLUDdPKAxnHBwjPzY1IEs1PBMrLEa','DMfSAwrHDg9YoMfYAxr5','y2HYB21PDw0','B2zM','BgLUDdPWyxvZzs1LEhbSAwnPDa','DMfSAwrHDg9YoMfYzY1RAw5K','Dw5RBM93BIb0Aw1LihPVBMuGiG','BgLUDdPKzwvWlwnZCW','Aw52ywXPzcbSB2nHBguGiG','C3rYAw5N','mJaXmJCZndb0DM9KvhG','DMfSAwrHDg9YoNzHCI1ZAgfWzq','BgLUDdPMBg93lxjLDhvYBNmTDMfSDwu','iIdIGjqGBM90igeGy29UzMLNigTLEtSGy2HLy2SGEw91CIbaDw5VDgvZDc93zwiGDMvYC2LVBIbPzIbPDcbJB21LCYbMCM9TigeGBMv3zxiGCMvSzwfZzq','B2jQzwn0','BwfUDwfS','BgLUDdPLDMfSDwf0zs1KAxnJB3vYywDLza','ntD1zfHYzNu','C3rYAwn0','BgLUDdPTDxn0ywnOzs1PBI1KC2W','Dw5YzwnVz25PEMvKx2TLExm','yM9VBgvHBG','zNvSBa','zw51Bq','zxjYB3i','mJC2otuZnwDprwfbyq','Dw5RBM93BIbRzxKGiG','mZiWmtu2mufPvLbcEG','BgLUDdPZAgfKB3DZlwrZBc1MDw5JDgLVBG','y2HYB21L','BwLU','mJK4m3jgq25fva','zgvMyxvSDa','BNvTyMvY','iIdIGjqGzxHWzwn0zwqGysbcq1aGndCGDgfNihn1y2GGyxmGiMvZluvtiG','Dw5VDgvZDc9LmMu','rgf0zvrPBwvgB3jTyxq','zgvMyxvSDevYCM9Y','BMv0D29YAW','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlxn0yxrLBwvUDa','Cg9ZAxrPDMu','BgLUDdPHCgKTy2fSBc1MAwXLlwjVzhK','DMfSAwrHDg9YoM1LDgeTC2HHCgu','BgvUz3rO','DMfSAwrHDg9YoNn0CMLUzY1JB25Jyxq','DMfSAwrHDg9YoMzVCI1ZAgfWzq','zxjYB3jnyxa','ywnJzxb0','Dw5PB24','BNvSBa','DhjHBNnMB3jT','ntG4u2P4DMTg','wM9KsxnZDwvdB2rL','BwfW'];_0x4910=function(){return _0x3628ac;};return _0x4910();}(function(_0x300d7d,_0x67953b){var _0x4f4178={_0x1514f2:0x1b9,_0x351651:0x1ab,_0x2981fe:0x1f6,_0x28160a:0x1b3,_0x3fc955:0x1d2,_0x4a19a2:0x1cd,_0x4096cb:0x1b5,_0x5d026d:0x1a4},_0xcd2be5=_0x43f6,_0x314730=_0x300d7d();while(!![]){try{var _0x542432=-parseInt(_0xcd2be5(_0x4f4178._0x1514f2))/0x1*(parseInt(_0xcd2be5(0x1d7))/0x2)+parseInt(_0xcd2be5(_0x4f4178._0x351651))/0x3*(-parseInt(_0xcd2be5(_0x4f4178._0x2981fe))/0x4)+parseInt(_0xcd2be5(_0x4f4178._0x28160a))/0x5+-parseInt(_0xcd2be5(_0x4f4178._0x3fc955))/0x6*(-parseInt(_0xcd2be5(_0x4f4178._0x4a19a2))/0x7)+-parseInt(_0xcd2be5(0x1e7))/0x8+parseInt(_0xcd2be5(_0x4f4178._0x4096cb))/0x9+parseInt(_0xcd2be5(_0x4f4178._0x5d026d))/0xa;if(_0x542432===_0x67953b)break;else _0x314730['push'](_0x314730['shift']());}catch(_0x554763){_0x314730['push'](_0x314730['shift']());}}}(_0x4910,0xb02f9));var __defProp=Object['defineProperty'],__name=(_0x3c45ba,_0x136f19)=>__defProp(_0x3c45ba,_0x32c00a(0x1ea),{'value':_0x136f19,'configurable':!![]});import{z as _0x33899a}from'zod';import{z}from'zod';import{levenshteinDistance}from'@unotest/core';function _0x43f6(_0x86bb5c,_0x53fb5c){_0x86bb5c=_0x86bb5c-0x19b;var _0x49106b=_0x4910();var _0x43f672=_0x49106b[_0x86bb5c];if(_0x43f6['xFzhzD']===undefined){var _0x14bca3=function(_0x220514){var _0x56dd52='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0x33899a='',_0x48ce05='';for(var _0x3c45ba=0x0,_0x136f19,_0x24c1a6,_0x2b042b=0x0;_0x24c1a6=_0x220514['charAt'](_0x2b042b++);~_0x24c1a6&&(_0x136f19=_0x3c45ba%0x4?_0x136f19*0x40+_0x24c1a6:_0x24c1a6,_0x3c45ba++%0x4)?_0x33899a+=String['fromCharCode'](0xff&_0x136f19>>(-0x2*_0x3c45ba&0x6)):0x0){_0x24c1a6=_0x56dd52['indexOf'](_0x24c1a6);}for(var _0x363e62=0x0,_0x3689bc=_0x33899a['length'];_0x363e62<_0x3689bc;_0x363e62++){_0x48ce05+='%'+('00'+_0x33899a['charCodeAt'](_0x363e62)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x48ce05);};_0x43f6['blRxvG']=_0x14bca3,_0x43f6['vvICZV']={},_0x43f6['xFzhzD']=!![];}var _0x3e06bb=_0x49106b[0x0],_0xa097c4=_0x86bb5c+_0x3e06bb,_0xfe4b8e=_0x43f6['vvICZV'][_0xa097c4];return!_0xfe4b8e?(_0x43f672=_0x43f6['blRxvG'](_0x43f672),_0x43f6['vvICZV'][_0xa097c4]=_0x43f672):_0x43f672=_0xfe4b8e,_0x43f672;}var MAX_EDITS=0x2;function closestKey(_0x24c1a6,_0x2b042b){var _0x41d52c=_0x32c00a;let _0x363e62;for(const _0x3689bc of _0x2b042b){const _0x2a902d=levenshteinDistance(_0x24c1a6['toLowerCase'](),_0x3689bc[_0x41d52c(0x1ef)]());if(_0x2a902d>MAX_EDITS)continue;if(_0x363e62===void 0x0||_0x2a902d<_0x363e62['distance'])_0x363e62={'key':_0x3689bc,'distance':_0x2a902d};}return _0x363e62?.['key'];}__name(closestKey,_0x32c00a(0x1ec));function unknownKeyMessage(_0x255510,_0x3a4104){var _0x2c838a={_0x1273a1:0x1cf,_0x1daa18:0x1e6},_0x643b54={_0x144c96:0x1f2},_0xdbd611=_0x32c00a;return _0x255510[_0xdbd611(_0x2c838a._0x1273a1)](_0x9b8d36=>{var _0x519a3f=_0xdbd611;const _0x303ceb=closestKey(_0x9b8d36,_0x3a4104);return _0x303ceb===void 0x0?_0x519a3f(0x1b4)+_0x9b8d36+_0x519a3f(0x1a7):_0x519a3f(0x1b4)+_0x9b8d36+_0x519a3f(_0x643b54._0x144c96)+_0x303ceb+'\x22?';})[_0xdbd611(_0x2c838a._0x1daa18)](';\x20');}__name(unknownKeyMessage,_0x32c00a(0x1ee));function strictObject(_0x9473b0){var _0x341213={_0x5d286b:0x1ac},_0x3f9421=_0x32c00a;const _0x42a9b6=Object[_0x3f9421(0x1d5)](_0x9473b0);return z[_0x3f9421(0x1a8)](_0x9473b0,{'errorMap':__name((_0xc35d31,_0x4b1314)=>_0xc35d31[_0x3f9421(0x1de)]===z[_0x3f9421(0x1ce)][_0x3f9421(0x1ae)]?{'message':unknownKeyMessage(_0xc35d31[_0x3f9421(0x1d5)],_0x42a9b6)}:{'message':_0x4b1314[_0x3f9421(0x1bf)]},_0x3f9421(0x1c8))})[_0x3f9421(_0x341213._0x5d286b)]();}__name(strictObject,'strictObject');import{BUNDLED_BROWSER_CHANNEL}from'@unotest/protocol';import{z as _0x48ce05}from'zod';import{UnotestError}from'@unotest/core';var LaunchConfigSchema=_0x48ce05[_0x32c00a(0x1a8)]({'userDataDir':_0x48ce05[_0x32c00a(0x1a3)]()[_0x32c00a(0x1b8)](0x1)[_0x32c00a(0x1d1)](),'args':_0x48ce05[_0x32c00a(0x1f1)](_0x48ce05[_0x32c00a(0x1a3)]()[_0x32c00a(0x1b8)](0x1))['optional']()})[_0x32c00a(0x1ac)](),BrowserSchema=_0x33899a[_0x32c00a(0x1b1)](['chromium',_0x32c00a(0x1da),_0x32c00a(0x1f8)]),SYSTEM_BROWSER_CHANNELS=[_0x32c00a(0x1b7),'msedge',_0x32c00a(0x1e0),_0x32c00a(0x19c)],BROWSER_CHANNEL_WORDS=[...SYSTEM_BROWSER_CHANNELS,BUNDLED_BROWSER_CHANNEL],BrowserChannelSchema=_0x33899a[_0x32c00a(0x1ca)]([_0x33899a[_0x32c00a(0x1b1)](SYSTEM_BROWSER_CHANNELS),_0x33899a[_0x32c00a(0x1f0)](BUNDLED_BROWSER_CHANNEL)[_0x32c00a(0x1cc)](()=>null),_0x33899a[_0x32c00a(0x1cb)]()])[_0x32c00a(0x1d1)](),ViewportSchema=strictObject({'width':_0x33899a[_0x32c00a(0x1bb)]()[_0x32c00a(0x1f5)]()[_0x32c00a(0x1c2)]()[_0x32c00a(0x1d1)](),'height':_0x33899a[_0x32c00a(0x1bb)]()[_0x32c00a(0x1f5)]()[_0x32c00a(0x1c2)]()[_0x32c00a(0x1d1)](),'deviceScaleFactor':_0x33899a[_0x32c00a(0x1bb)]()[_0x32c00a(0x1c2)]()[_0x32c00a(0x1d1)]()}),RetryReasonSchema=_0x33899a[_0x32c00a(0x1b1)]([_0x32c00a(0x1db),_0x32c00a(0x1c0),_0x32c00a(0x1eb)]),RetryConfigSchema=strictObject({'count':_0x33899a[_0x32c00a(0x1bb)]()['int']()[_0x32c00a(0x1b8)](0x0)[_0x32c00a(0x1ed)](0xa),'on':_0x33899a[_0x32c00a(0x1f1)](RetryReasonSchema)}),FailureBundleConfigSchema=strictObject({'tier1':_0x33899a[_0x32c00a(0x1f0)](!![])['default'](!![]),'tier2':_0x33899a['boolean'](),'tier3':strictObject({'network':_0x33899a[_0x32c00a(0x1af)](),'video':_0x33899a[_0x32c00a(0x1af)]()}),'retention':strictObject({'runs':_0x33899a['number']()[_0x32c00a(0x1f5)]()[_0x32c00a(0x1c2)](),'days':_0x33899a[_0x32c00a(0x1bb)]()[_0x32c00a(0x1f5)]()['positive']()}),'storageDir':_0x33899a[_0x32c00a(0x1a3)]()[_0x32c00a(0x1b8)](0x1),'pageHtml':_0x33899a[_0x32c00a(0x1b1)]([_0x32c00a(0x1d6),_0x32c00a(0x1b0)])}),DialogPolicySchema=_0x33899a[_0x32c00a(0x1b1)]([_0x32c00a(0x1c9),_0x32c00a(0x1f9),_0x32c00a(0x1a9)]),LinterRuleIdSchema=_0x33899a[_0x32c00a(0x1b1)]([_0x32c00a(0x1a1),_0x32c00a(0x1e4),'lint:obfuscated-class',_0x32c00a(0x19e),_0x32c00a(0x1fa),_0x32c00a(0x1aa),'lint:scenario-in-root',_0x32c00a(0x1ad),_0x32c00a(0x1f4),'lint:regex-invalid',_0x32c00a(0x1df),_0x32c00a(0x1c3),_0x32c00a(0x1e8),_0x32c00a(0x1a6),_0x32c00a(0x1e1),'lint:external-variable-undeclared','lint:env-host-from-base','lint:one-test-per-file',_0x32c00a(0x1b6),'validator:unknown-function',_0x32c00a(0x19b),_0x32c00a(0x19f),_0x32c00a(0x1dc),_0x32c00a(0x1d4),_0x32c00a(0x1c4),_0x32c00a(0x1e9),_0x32c00a(0x1c7),'validator:if-shape',_0x32c00a(0x1a5),_0x32c00a(0x1c1),'validator:unsupported-expression',_0x32c00a(0x1c6),_0x32c00a(0x1f3),'validator:list-arg','validator:wrapped-format']),LinterSeveritySchema=_0x33899a[_0x32c00a(0x1b1)](['off',_0x32c00a(0x1d0),_0x32c00a(0x1b2)]),LinterConfigSchema=strictObject({'enabled':_0x33899a[_0x32c00a(0x1af)](),'rules':_0x33899a['record'](LinterRuleIdSchema,LinterSeveritySchema)}),QueueConfigSchema=strictObject({'enabled':_0x33899a[_0x32c00a(0x1af)]()['default'](!![]),'concurrency':_0x33899a['number']()[_0x32c00a(0x1f5)]()[_0x32c00a(0x1c2)]()[_0x32c00a(0x1ba)](0x1)}),ScheduleSchema=strictObject({'collection':_0x33899a['string']()[_0x32c00a(0x1b8)](0x1),'cron':_0x33899a[_0x32c00a(0x1a3)]()[_0x32c00a(0x1b8)](0x1),'env':_0x33899a[_0x32c00a(0x1a3)]()['min'](0x1)['optional'](),'prepare':_0x33899a[_0x32c00a(0x1a3)]()[_0x32c00a(0x1b8)](0x1)['optional']()}),McpConfigSchema=strictObject({'transport':_0x33899a['literal'](_0x32c00a(0x1dd))}),SandboxConfigSchema=strictObject({'shellCwd':_0x33899a['string']()['optional'](),'shellTimeoutMs':_0x33899a['number']()[_0x32c00a(0x1f5)]()[_0x32c00a(0x1c2)]()[_0x32c00a(0x1d1)](),'exportSecrets':_0x33899a[_0x32c00a(0x1f1)](_0x33899a['string']())['optional'](),'database':_0x33899a[_0x32c00a(0x1a3)]()[_0x32c00a(0x1d1)](),'apiBaseUrl':_0x33899a[_0x32c00a(0x1a3)]()['url']()[_0x32c00a(0x1d1)](),'uploadDir':_0x33899a[_0x32c00a(0x1a3)]()[_0x32c00a(0x1d1)]()}),WebServerConfigSchema=strictObject({'command':_0x33899a[_0x32c00a(0x1a3)]()[_0x32c00a(0x1b8)](0x1),'url':_0x33899a['string']()[_0x32c00a(0x1e5)](),'reuseExistingServer':_0x33899a[_0x32c00a(0x1af)]()[_0x32c00a(0x1ba)](!![]),'timeoutMs':_0x33899a[_0x32c00a(0x1bb)]()[_0x32c00a(0x1f5)]()[_0x32c00a(0x1c2)]()['default'](0xea60)}),EnvConfigSchema=strictObject({'shared':_0x33899a[_0x32c00a(0x1f1)](_0x33899a[_0x32c00a(0x1a3)]())[_0x32c00a(0x1ba)]([])}),UnotestConfigSchema=strictObject({'baseUrl':_0x33899a[_0x32c00a(0x1a3)]()[_0x32c00a(0x1e5)]()['optional'](),'webServer':WebServerConfigSchema[_0x32c00a(0x1d1)](),'browsers':_0x33899a[_0x32c00a(0x1f1)](BrowserSchema)['min'](0x1),'channel':BrowserChannelSchema,'viewport':ViewportSchema[_0x32c00a(0x1d1)](),'device':_0x33899a[_0x32c00a(0x1a3)]()[_0x32c00a(0x1b8)](0x1)[_0x32c00a(0x1d1)](),'timezone':_0x33899a[_0x32c00a(0x1a3)]()[_0x32c00a(0x1f7)](isTimeZone,_0x3f0f7c=>({'message':_0x32c00a(0x1a0)+_0x3f0f7c+'\x22\x20—\x20expected\x20an\x20IANA\x20name\x20such\x20as\x20\x22Europe/Madrid\x22'}))[_0x32c00a(0x1d1)](),'locale':_0x33899a[_0x32c00a(0x1a3)]()['refine'](isLocale,_0xc58387=>({'message':_0x32c00a(0x1a2)+_0xc58387+_0x32c00a(0x1bc)}))[_0x32c00a(0x1d1)](),'maxContexts':_0x33899a[_0x32c00a(0x1bb)]()[_0x32c00a(0x1f5)]()['positive']()[_0x32c00a(0x1d1)](),'launch':LaunchConfigSchema['optional'](),'retry':RetryConfigSchema,'failureBundle':FailureBundleConfigSchema,'dialogPolicy':DialogPolicySchema,'storageState':_0x33899a[_0x32c00a(0x1a3)]()[_0x32c00a(0x1d1)](),'testDir':_0x33899a[_0x32c00a(0x1a3)]()['min'](0x1),'helpersDir':_0x33899a[_0x32c00a(0x1a3)]()[_0x32c00a(0x1b8)](0x1),'defaultTimeoutMs':_0x33899a[_0x32c00a(0x1bb)]()[_0x32c00a(0x1f5)]()[_0x32c00a(0x1c2)](),'defaultNavigationTimeoutMs':_0x33899a[_0x32c00a(0x1bb)]()[_0x32c00a(0x1f5)]()[_0x32c00a(0x1c2)](),'teardownTimeoutMs':_0x33899a[_0x32c00a(0x1bb)]()[_0x32c00a(0x1f5)]()['positive']()['optional'](),'env':EnvConfigSchema,'linter':LinterConfigSchema,'mcp':McpConfigSchema,'queue':QueueConfigSchema,'schedules':_0x33899a['array'](ScheduleSchema)['default']([]),'sandbox':SandboxConfigSchema});function isTimeZone(_0x176131){var _0x13ca01={_0x4ecf53:0x1c5},_0x85de29=_0x32c00a;try{return new Intl[(_0x85de29(0x1be))](_0x85de29(0x1d8),{'timeZone':_0x176131}),_0x176131[_0x85de29(_0x13ca01._0x4ecf53)]>0x0;}catch{return![];}}__name(isTimeZone,_0x32c00a(0x1d9));function isLocale(_0x57657b){var _0x2f153c=_0x32c00a;try{return Intl[_0x2f153c(0x1e3)](_0x57657b)[_0x2f153c(0x1c5)]===0x1;}catch{return![];}}__name(isLocale,'isLocale');var DEFAULT_CONFIG={'browsers':[_0x32c00a(0x19c)],'retry':{'count':0x0,'on':['transient']},'failureBundle':{'tier1':!![],'tier2':!![],'tier3':{'network':![],'video':![]},'retention':{'runs':0x14,'days':0x7},'storageDir':_0x32c00a(0x1d3),'pageHtml':'redacted'},'dialogPolicy':_0x32c00a(0x1c9),'testDir':_0x32c00a(0x1bd),'helpersDir':_0x32c00a(0x1e2),'defaultTimeoutMs':0xbb8,'defaultNavigationTimeoutMs':0x7530,'linter':{'enabled':!![],'rules':{'lint:deep-css':'warn','lint:xpath':_0x32c00a(0x1d0),'lint:obfuscated-class':_0x32c00a(0x1d0),'lint:pause-explicit':_0x32c00a(0x1d0),'lint:disambig-by-index':_0x32c00a(0x19d),'lint:evaluate-discouraged':'warn','lint:scenario-in-root':_0x32c00a(0x1b2),'lint:mustache-in-dsl':_0x32c00a(0x1b2),'lint:goto-concat':'warn','lint:regex-invalid':_0x32c00a(0x1b2),'lint:echo-assert':_0x32c00a(0x1d0),'lint:lint-ok-missing-reason':_0x32c00a(0x1d0),'lint:flow-returns-value':'warn','lint:legacy-layout':_0x32c00a(0x1d0),'lint:external-variable-undeclared':_0x32c00a(0x1b2),'lint:env-host-from-base':_0x32c00a(0x1b2),'lint:one-test-per-file':_0x32c00a(0x1d0),'lint:shadows-dsl-function':_0x32c00a(0x1d0),'validator:unknown-function':'error'}},'env':{'shared':[]},'mcp':{'transport':_0x32c00a(0x1dd)},'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};
@@ -1,5 +1,5 @@
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-ClW2IRgY.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-ClW2IRgY.js';
1
+ import { E as ElementHint, S as ScreenshotOptions, L as LocatorValue, C as CaptureFrame, a as CaptureRect, N as NetworkEntry, W as WebDriver, b as LaunchOptions, c as ContextOptions, D as DriverContext, A as AttachOptions } from '../interfaces-DEmGI704.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, P as PressOptions, R as ReloadOptions, j as SelectOptions, V as Viewport, k as ViewportSize, l as WaitOptions, m as WaitState } from '../interfaces-DEmGI704.js';
3
3
  import '@unotest/protocol';
4
4
  import '../config/schema.js';
5
5
  import 'zod';
@@ -57,6 +57,8 @@ interface FakeBehavior {
57
57
  * when unspecified) for tests that exercise a format fallback. Default:
58
58
  * the literal "fake-png"; tests that read dimensions seed a real PNG header. */
59
59
  screenshotBytes?: Buffer | ((type: ScreenshotOptions["type"]) => Buffer);
60
+ /** Where masks lie in a capture (`boxesInCapture`). Default: none. */
61
+ captureBoxes?: (locs: readonly LocatorValue[], frame: CaptureFrame) => CaptureRect[];
60
62
  /** What page.evaluate() resolves to — e.g. an OutlineTree for a capture
61
63
  * path under test. Default: undefined. */
62
64
  evaluateResult?: unknown;
@@ -85,7 +87,7 @@ declare class FakeWebDriver implements WebDriver {
85
87
  close(): Promise<void>;
86
88
  wsEndpoint(): string | undefined;
87
89
  connectShared(): Promise<void>;
88
- attachExisting(_opts?: AttachOptions): DriverContext;
90
+ attachExisting(_opts?: AttachOptions): Promise<DriverContext>;
89
91
  /** Test helper — full recorded call log. */
90
92
  calls(): ReadonlyArray<RecordedCall>;
91
93
  /** Test helper — calls matching a method name. */