@unotest/web 0.28.0 → 0.30.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.
@@ -87,6 +87,15 @@ APP_BASE_URL) — same idea as run_test's per-call `env`.
87
87
  `explore_start` opens the browser itself. Do NOT call `new_context`
88
88
  first — it's for RESETTING the browser (Phase 5), not for starting.
89
89
 
90
+ **Variables in steps.** In a value field (`fill` value, `press` key,
91
+ `select_option` value, `goto` url) the bare NAME of a `.env`/`.secrets`
92
+ variable is a reference: `value: "PASSWORD"` types the secret live and
93
+ the saved test says `fill(loc, PASSWORD)`. In a locator's text or an
94
+ assertion's text a bare NAME is the literal it looks like — to reference
95
+ a variable there write `{{NAME}}` (`text: "{{GREETING}}"`); the reply
96
+ warns when a literal equals a variable's name. Never type a secret's
97
+ VALUE: it is recorded as the name anyway, and the reply says so.
98
+
90
99
  ### Phase 2 — first recorded step: navigate
91
100
 
92
101
  ```
@@ -418,7 +427,23 @@ Assertions:
418
427
 
419
428
  State reads:
420
429
  - `getTitle()`, `getUrl()`, `getAttribute(loc, name)`, `getInnerText(loc)`,
421
- `getInputValue(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'))`).
433
+ - A `textarea` / `input` VALUE is not page text: `waitForText` and
434
+ `assertText` never see it. Check it with `assertValue(loc, expected)`
435
+ — it polls until the timeout (5 s by default, `{timeout}` to raise
436
+ it), so a value that fills in late is fine. For a substring of the
437
+ value there is no polling assert: read it in a loop —
438
+ `for (i = 0; i < 20; i = i + 1) { if (textContains(getInputValue(loc), 'x')) { break; } pause(200); // lint-ok: polling a textarea value }`
439
+ — then assert.
440
+ - Only the vocabulary above is expression language. `!` is rejected by
441
+ the parser (`unotest-web lint`: `parse error — Invalid token`);
442
+ `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
446
+ (`assertHidden`, `assertCount`, `.filter({hasText})`, `textContains`).
422
447
 
423
448
  Sandbox primitives:
424
449
  - `shell("cmd", "arg", …, options?)` — `execFile` style, no shell interpretation. Non-zero exit fails the step; pass `{allowNonZero: true}` to inspect `res.code` yourself. Wall-clock budget `{timeoutMs}` (default 120s).
@@ -433,8 +458,17 @@ Sandbox primitives:
433
458
  JSON — there is no key-name magic.
434
459
 
435
460
  Escape hatch:
436
- - `evaluate(\`js body\`, …args)` — raw backticks, no `${}`. Linter
461
+ - `evaluate(\`js body\`, arg?)` — raw backticks, no `${}`. Linter
437
462
  warns `lint:evaluate-discouraged`. Use only when nothing above fits.
463
+ The body gets at most ONE argument — extra arguments reach it like
464
+ this: none → nothing, exactly one → the value itself, **with two or
465
+ more extra arguments the body receives ONE array** — destructure it:
466
+ `evaluate('function(n){ return n * 2 }', 21)` and
467
+ `evaluate('([a, b]) => a + b', a, b)`. The linter's warning says so
468
+ when it sees two or more.
469
+ - Native dialogs (`confirm()` / `alert()` / `prompt()`) are accepted by
470
+ the runner itself (`dialogPolicy: "accept"` by default) — a "Remove"
471
+ that asks first needs no special step.
438
472
 
439
473
  Time helpers: `nowMs()`, `today()`, `daysFromNow(n)`. Marker helper: `randomWord(len)` — random lowercase letters, digit-free. Debug helper: `json(value)` — serialize any value for an assert message: `assertTrue(res.status == 202, json(res.body))`.
440
474
 
@@ -635,6 +669,11 @@ Every locator must resolve to exactly one element. When you see
635
669
  multi-matches.** Element order is brittle. Use `.filter({hasText:
636
670
  '…'})` or `.filter({has: someLocator})`. Linter flags index-based
637
671
  picking as `lint:disambig-by-index`.
672
+ - **Don't assert "the first row of the list / audit".** On a shared
673
+ stand another run (or a person) writes rows between your steps. Give
674
+ your own data a unique marker (`randomWord()` in a name or note),
675
+ find your row by it (`.filter({hasText: marker})`), and remove what
676
+ you created at the end of the scenario.
638
677
  - **Don't reach for `locator(...)` with `>` combinators, hashed class
639
678
  names, or `xpath=…`.** Stop and ask the user whether the app should
640
679
  expose a `data-testid` or accessible name.
@@ -112,6 +112,15 @@ APP_BASE_URL) — same idea as run_test's per-call `env`.
112
112
  `explore_start` opens the browser itself. Do NOT call `new_context`
113
113
  first — it's for RESETTING the browser (Phase 5), not for starting.
114
114
 
115
+ **Variables in steps.** In a value field (`fill` value, `press` key,
116
+ `select_option` value, `goto` url) the bare NAME of a `.env`/`.secrets`
117
+ variable is a reference: `value: "PASSWORD"` types the secret live and
118
+ the saved test says `fill(loc, PASSWORD)`. In a locator's text or an
119
+ assertion's text a bare NAME is the literal it looks like — to reference
120
+ a variable there write `{{NAME}}` (`text: "{{GREETING}}"`); the reply
121
+ warns when a literal equals a variable's name. Never type a secret's
122
+ VALUE: it is recorded as the name anyway, and the reply says so.
123
+
115
124
  ### Phase 2 — record the known steps as ONE batch
116
125
 
117
126
  **Batch-first default.** When the task brief already spells out the
@@ -549,7 +558,23 @@ Assertions:
549
558
 
550
559
  State reads:
551
560
  - `getTitle()`, `getUrl()`, `getAttribute(loc, name)`, `getInnerText(loc)`,
552
- `getInputValue(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'))`).
564
+ - A `textarea` / `input` VALUE is not page text: `waitForText` and
565
+ `assertText` never see it. Check it with `assertValue(loc, expected)`
566
+ — it polls until the timeout (5 s by default, `{timeout}` to raise
567
+ it), so a value that fills in late is fine. For a substring of the
568
+ value there is no polling assert: read it in a loop —
569
+ `for (i = 0; i < 20; i = i + 1) { if (textContains(getInputValue(loc), 'x')) { break; } pause(200); // lint-ok: polling a textarea value }`
570
+ — then assert.
571
+ - Only the vocabulary above is expression language. `!` is rejected by
572
+ the parser (`unotest-web lint`: `parse error — Invalid token`);
573
+ `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
577
+ (`assertHidden`, `assertCount`, `.filter({hasText})`, `textContains`).
553
578
 
554
579
  Sandbox primitives:
555
580
  - `shell("cmd", "arg", …, options?)` — `execFile` style, no shell interpretation. Non-zero exit fails the step; pass `{allowNonZero: true}` to inspect `res.code` yourself. Wall-clock budget `{timeoutMs}` (default 120s).
@@ -564,8 +589,17 @@ Sandbox primitives:
564
589
  JSON — there is no key-name magic.
565
590
 
566
591
  Escape hatch:
567
- - `evaluate(\`js body\`, …args)` — raw backticks, no `${}`. Linter
592
+ - `evaluate(\`js body\`, arg?)` — raw backticks, no `${}`. Linter
568
593
  warns `lint:evaluate-discouraged`. Use only when nothing above fits.
594
+ The body gets at most ONE argument — extra arguments reach it like
595
+ this: none → nothing, exactly one → the value itself, **with two or
596
+ more extra arguments the body receives ONE array** — destructure it:
597
+ `evaluate('function(n){ return n * 2 }', 21)` and
598
+ `evaluate('([a, b]) => a + b', a, b)`. The linter's warning says so
599
+ when it sees two or more.
600
+ - Native dialogs (`confirm()` / `alert()` / `prompt()`) are accepted by
601
+ the runner itself (`dialogPolicy: "accept"` by default) — a "Remove"
602
+ that asks first needs no special step.
569
603
 
570
604
  Time helpers: `nowMs()`, `today()`, `daysFromNow(n)`. Marker helper: `randomWord(len)` — random lowercase letters, digit-free. Debug helper: `json(value)` — serialize any value for an assert message: `assertTrue(res.status == 202, json(res.body))`.
571
605
 
@@ -711,6 +745,9 @@ no recording.
711
745
  - **`StaleRefError`** — a ref from an earlier lookup is no longer in
712
746
  the DOM. Intent locators don't go stale (grounded per call) — retry
713
747
  with the intent step, or re-ground via `ground_element`.
748
+ - **Grounder unavailable** — `explore_start` or the first intent step
749
+ says so; intent locators are off for the session. Use
750
+ `find_element({role, name, near?})` and its ref instead.
714
751
  - **`RefResolveError`** — element has no stable identifier (testId /
715
752
  role+name / aria-label / placeholder / alt / title / text / href /
716
753
  stable id / name attribute). Best fix: ask the app team to add
@@ -769,6 +806,11 @@ Every locator must resolve to exactly one element. When you see
769
806
  multi-matches.** Element order is brittle. Use `.filter({hasText:
770
807
  '…'})` or `.filter({has: someLocator})`. Linter flags index-based
771
808
  picking as `lint:disambig-by-index`.
809
+ - **Don't assert "the first row of the list / audit".** On a shared
810
+ stand another run (or a person) writes rows between your steps. Give
811
+ your own data a unique marker (`randomWord()` in a name or note),
812
+ find your row by it (`.filter({hasText: marker})`), and remove what
813
+ you created at the end of the scenario.
772
814
  - **Don't reach for `locator(...)` with `>` combinators, hashed class
773
815
  names, or `xpath=…`.** Stop and ask the user whether the app should
774
816
  expose a `data-testid` or accessible name.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,202 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.30.0] - 2026-09-03
4
+
5
+ ### Minor Changes
6
+
7
+ - 23de03c: On a hosted viewer (a box), the project and environment you are looking at
8
+ are now named and switched in the viewer's own tree header, in place of
9
+ the checkout directory it used to show there (`current`, which told
10
+ nobody anything). Previously the only way to another environment was
11
+ logging out and using the picker page. The chevrons appear on hover, like
12
+ the refresh button beside them, and only when something fronts the viewer
13
+ and offers it a list; a plain local viewer keeps the folder name it
14
+ always showed. Because
15
+ each environment on a box is its own viewer process, picking one is a full
16
+ page load into that viewer, and the menu shows which test bundle each
17
+ environment is running. The status bar's `.env.<name>` overlay switcher is
18
+ now labelled "env overlay", so the two senses of "environment" no longer
19
+ share a name. `@unotest/viewer/session` carries the two URLs this needs
20
+ (`environmentsUrl`, `switchEnvUrl`) and the `ViewerEnvOption` type, both
21
+ optional — a proxy that does not offer them gets the old behaviour.
22
+
23
+ ### Patch Changes
24
+
25
+ - A run started in the first moments after the viewer boots is now discovered: the run watcher finishes its initial scan of the day directory before reporting itself started, instead of filing such a run as history.
26
+ - 3f5cab7: `bundle push` and `env push` no longer send you to "the box's
27
+ admin page" for a project token — there is no such page; tokens are
28
+ issued per project by the box's operator, and the refusal hints and the
29
+ missing-token message now say so.
30
+ - 3f5cab7: The vocabulary's description of `evaluate` now says how extra
31
+ arguments reach the body — none → nothing, exactly one → the value
32
+ itself, two or more → one array — matching the runtime, the linter's
33
+ hint and the authoring skill; it used to read as if they were positional
34
+ (`evaluate(js, ...args)`), and so did the generated DSL typings.
35
+ - 3f5cab7: A scenario that answers a native `confirm()` — a "Remove" button that
36
+ asks first, say — no longer fails when `run_test` auto-attaches the MCP
37
+ session to the run's browser, or after `attach_debug_session`. The
38
+ attaching client now applies the same dialog policy the run does
39
+ (`dialogPolicy`, accept by default) to the page it watches; before, it
40
+ listened for no dialogs at all, and Playwright dismisses every dialog on
41
+ behalf of a client that has no listener — so the second pair of eyes was
42
+ answering "no" before the run's own accept could land. The same scenario
43
+ passed with an exploration session open only because that session
44
+ happened to keep the run's browser to itself. Under `manual` the attached
45
+ client leaves the dialog to whoever handles it instead of dismissing it.
46
+ - 9f2e244: On a box, an administrator can now see a secret's value from the guard's
47
+ values page — the eye reveals it in the row, the copy button puts it on
48
+ the clipboard without showing it — and every look is a `secret.revealed`
49
+ entry in the box's audit trail, naming who, which secret and whether it
50
+ was shown or copied. The page is one table now (target, variables,
51
+ secrets), edited in place, with a JSON view that changes the whole
52
+ environment at once; a secret left as `"••••"` there is kept as it is.
53
+ The token door `env push` / `env set` talk to is unchanged: secrets stay
54
+ write-only on the wire.
55
+
56
+ `@unotest/protocol` carries the contract: `boxEnvSecretRevealPath` /
57
+ `boxEnvSecretsRevealPath` with their response parsers, the session-door
58
+ batch `BoxEnvValuesReplaceRequest` (`null` for a secret means "keep") and
59
+ `parseBoxEnvValuesReplaceRequest`, and the refusal code `unknown-secret`
60
+ for a reveal or a keep that names a secret the environment does not
61
+ hold. `isEnvVarName` now refuses `__proto__`: it is spelled like a
62
+ variable, but a plain object cannot hold it and the value was silently
63
+ lost. The CLI explains an `unknown-secret` refusal.
64
+
65
+ - 3f5cab7: `evaluate(js, …args)` has always handed the body its extra arguments in
66
+ one of three shapes — none, the single value, or ONE array for two or
67
+ more — while the authoring skill described them as positional. The
68
+ skill now states the rule with both spellings
69
+ (`evaluate('function(n){…}', 21)` / `evaluate('([a, b]) => …', a, b)`),
70
+ and the `lint:evaluate-discouraged` warning adds the same hint when it
71
+ sees two or more extra arguments; the runtime is unchanged. The skill
72
+ also gains the getters it left out (`count`, `getInputValue`,
73
+ `textContains`), the note that `waitForText` never sees a textarea's
74
+ value, the parser's refusal of `!` / `indexOf` / string methods, the
75
+ shared-stand rule against "the first row" (mark your own data, filter
76
+ by it, clean up), that native dialogs are accepted by the runner, and
77
+ what to do when the grounder is unavailable.
78
+ - 3f5cab7: While recording with `explore_step` / `explore_steps`, the bare NAME of a
79
+ scenario variable is substituted only where the step types a value into
80
+ the page — `fill`'s value, `press`'s key, `select_option`'s value,
81
+ `goto`'s url. In a locator's text or an assertion's expected text a bare
82
+ name is now the literal it looks like: `assertText(el, "BOX_LAB_PASSWORD")`
83
+ expects those letters, where before the live step silently waited for
84
+ the secret's value and the saved test said something else. To reference
85
+ a variable in a matcher, write `{{NAME}}`; the reply warns when a literal
86
+ happens to equal a variable's name. And a secret's value typed into a
87
+ value field is recorded as the secret's name (the reply says which), so
88
+ the value never lands in the test file.
89
+ - 3f5cab7: `run_test` no longer reports `spawn_failed` about a runner that is still
90
+ starting. Two runs launched together on a busy box took longer than the
91
+ fixed 10-second wait to write their first `runtime.json`, and the second
92
+ was declared dead while it was booting a browser. The wait now lasts as
93
+ long as the runner child is alive (up to 60 seconds), ends early when the
94
+ child joins the run queue, and — when the child really dies — says so with
95
+ its exit code and the last lines of its stderr, which the runner now
96
+ writes to `spawn.stderr.log` in its run directory.
97
+
98
+ `explore_start` now reports whether the grounder is usable for the
99
+ session: `grounder: {available: true}`, or `{available: false, reason,
100
+ hint}` when grounding is off, the backend is unreachable, or a required
101
+ model is not pulled (`"embeddinggemma" is not available there — pull it:
102
+ \`ollama pull embeddinggemma\``). An intent step in such a session fails
103
+ with the same words, not with the backend's raw error; the probe is one
104
+ short request per session.
105
+
106
+ Secret masking no longer rewrites the runner's own identifiers in
107
+ `runtime.json`: with `LOGIN=admin`, the scenario path `guard-admin.js`,
108
+ the test function `test_guard_admin` and the run id kept their names in
109
+ `inspect_runtime` replies instead of turning into `guard-‹secret:LOGIN›.js`.
110
+ Masking by value is unchanged everywhere else; the run id, scenario
111
+ path, test function and call-stack names are an explicit exception.
112
+
113
+ - 3f5cab7: `save_exploration_as_test` (and `generate_dsl_from_exploration`) now
114
+ write scoped locators — a `getByRole` / `getByText` / `locator(css)` step
115
+ under a parent, such as the "Reveal" button inside one table row — as
116
+ the chain the DSL already runs:
117
+ `locator('tr[data-row="A"]').getByRole('button', {name: 'Reveal', exact: true})`.
118
+ Before, any recorded step whose locator went below its root was skipped
119
+ with `NO_DSL_PRIMITIVE`, and the save was refused, although the step
120
+ had executed and the hand-written form worked. Every locator is now
121
+ rendered in the same method-chain spelling — narrowing steps too
122
+ (`getByRole('row').filter({hasText: 'Alice'}).first()` instead of
123
+ `first(filter(getByRole('row'), {hasText: 'Alice'}))`); both spellings
124
+ remain valid input, the runtime is unchanged.
125
+ - Updated dependencies [23de03c]
126
+ - Updated dependencies [9f2e244]
127
+ - @unotest/viewer@0.30.0
128
+ - @unotest/protocol@0.30.0
129
+ - @unotest/core@0.30.0
130
+ - @unotest/dsl@0.30.0
131
+ - @unotest/grounder-client@0.30.0
132
+
133
+ ## [0.29.0] - 2026-09-02
134
+
135
+ ### Minor Changes
136
+
137
+ - ab296ff: New `env push`, `env set` and `env rm` commands send an environment's
138
+ values to a box — the target, the variables and the secrets a suite runs
139
+ with there — from the same files a local run reads (`unotest/.env`,
140
+ `.env.<env>`, `.secrets`, `.secrets.<env>`), or from files named with
141
+ `--env-file` / `--secrets-file`. `.env*` become the box environment's
142
+ variables, `.secrets*` its secrets and `APP_BASE_URL` its target;
143
+ `UNOTEST_*` and empty values stay home and are listed as skipped. A push
144
+ replaces the box's layers and reports what it removed; `env set` reads
145
+ one value from stdin, never from the command line. Values never print.
146
+ The commands use the project token of `bundle push`, minted on the box
147
+ with the new `--values` scope — a token without it is refused, so a CI
148
+ token that pushes suites cannot rewrite an environment's credentials.
149
+ `@unotest/protocol` carries the wire (`box-values.ts`) and `TARGET_ENV_VAR`.
150
+ The viewer's messages about box-held variables now point at these
151
+ commands instead of the box's shell.
152
+ - 64108b8: The Variables panel of a viewer on a box now lists what the box injects
153
+ into every run of the environment — the target URL, the operator's
154
+ variables and the names of the environment's secrets — as read-only rows
155
+ with a `box` badge. It used to read `unotest/.env*`, which never travel
156
+ in a bundle, and show an empty panel next to a full run history; a
157
+ secret's value is still never sent, only its name. The box passes the
158
+ names through `UNOTEST_BOX_VARIABLE_NAMES` / `UNOTEST_BOX_SECRET_NAMES`
159
+ (constants in `@unotest/protocol`); writes to such a key are refused
160
+ with 409 and point at `boxd.config.mjs` / `boxd.mjs secret set`.
161
+ - 64108b8: `UNOTEST_BROWSER` and `UNOTEST_BROWSER_CHANNEL` now exist as per-run
162
+ overrides of `browsers[0]` and `channel` in `unotest.config.*`.
163
+ `UNOTEST_BROWSER` was shown in the CI manual and the `.env.example`
164
+ template, but nothing read it — a browser matrix ran Chromium three
165
+ times. A value outside `chromium | firefox | webkit` (or `chrome |
166
+ msedge | chrome-beta | bundled`) is an error, not a silent default. The
167
+ config travels with the suite in a bundle, so a `channel: "chrome"`
168
+ written on a laptop used to ask a box for a Google Chrome it does not
169
+ have; a box now sets `UNOTEST_BROWSER_CHANNEL=bundled` for every run and
170
+ the run log names each override. Constants: `BROWSER_ENV`,
171
+ `BROWSER_CHANNEL_ENV`, `BUNDLED_BROWSER_CHANNEL` in `@unotest/protocol`.
172
+
173
+ ### Patch Changes
174
+
175
+ - 64108b8: `init` without `--force` still leaves an existing `unotest/.env.example`
176
+ alone, but the skip now names the keys the current template declares
177
+ that the file does not — a project seeded on an older version never
178
+ learnt about `UNOTEST_STEP_SCREENSHOTS`, because nothing compared its
179
+ file with the template. The file is not touched.
180
+ `declaredEnvKeys()` in `@unotest/protocol` reads active and
181
+ commented-out keys alike. The DSL reference now documents
182
+ `UNOTEST_STEP_SCREENSHOTS` next to `screenshot()`: readers of that page
183
+ concluded the every-step mode did not exist.
184
+ - 64108b8: `shell()` tells a missing working directory apart from a missing
185
+ binary. Node reports both as `ENOENT`, and the old message sent people
186
+ looking for a tool that was there all along while the real cause was a
187
+ `sandbox.shellCwd` that exists on the laptop and not in CI or on a box.
188
+ The directory is checked before the spawn and the new
189
+ `ShellCwdMissingError` names it and where it came from.
190
+ - Updated dependencies [ab296ff]
191
+ - Updated dependencies [64108b8]
192
+ - Updated dependencies [64108b8]
193
+ - Updated dependencies [64108b8]
194
+ - @unotest/protocol@0.29.0
195
+ - @unotest/viewer@0.29.0
196
+ - @unotest/core@0.29.0
197
+ - @unotest/dsl@0.29.0
198
+ - @unotest/grounder-client@0.29.0
199
+
3
200
  ## [0.28.0] - 2026-09-01
4
201
 
5
202
  ### Minor Changes
package/README.md CHANGED
@@ -172,6 +172,20 @@ back to GitHub. `--pr` makes a newer push withdraw the older runs of the
172
172
  same pull request that are still waiting, so three pushes in five minutes
173
173
  cost one suite. Recipe: `guides/manuals/ci-setup.md`.
174
174
 
175
+ The values a suite runs with on the box — `APP_BASE_URL`, its `.env`
176
+ settings, its secrets — are sent separately, from the same files a local
177
+ run reads:
178
+
179
+ ```sh
180
+ npx @unotest/web env push dev # .env + .env.dev + .secrets + .secrets.dev
181
+ printf '%s' "$KEY" | npx @unotest/web env set dev API_KEY --secret
182
+ ```
183
+
184
+ `.env*` become the environment's variables, `.secrets*` its secrets,
185
+ `APP_BASE_URL` its target; `UNOTEST_*` stay home. A value never prints.
186
+ The token must be minted with `--values` on the box. Admins also see and
187
+ change them on the box's admin page. Manual: `guides/manuals/box-values.md`.
188
+
175
189
  ## 5. Watch it run — the viewer
176
190
 
177
191
  `npx @unotest/web viewer` opens a local UI (no cloud, no account):
@@ -215,15 +215,15 @@ declare const WebServerConfigSchema: z.ZodObject<{
215
215
  /** How long to wait for the URL to come up after spawning. */
216
216
  timeoutMs: z.ZodDefault<z.ZodNumber>;
217
217
  }, "strip", z.ZodTypeAny, {
218
- command: string;
219
218
  url: string;
220
- reuseExistingServer: boolean;
221
219
  timeoutMs: number;
222
- }, {
223
220
  command: string;
221
+ reuseExistingServer: boolean;
222
+ }, {
224
223
  url: string;
225
- reuseExistingServer?: boolean | undefined;
224
+ command: string;
226
225
  timeoutMs?: number | undefined;
226
+ reuseExistingServer?: boolean | undefined;
227
227
  }>;
228
228
  type WebServerConfig = z.infer<typeof WebServerConfigSchema>;
229
229
  declare const UnotestConfigSchema: z.ZodObject<{
@@ -249,15 +249,15 @@ declare const UnotestConfigSchema: z.ZodObject<{
249
249
  /** How long to wait for the URL to come up after spawning. */
250
250
  timeoutMs: z.ZodDefault<z.ZodNumber>;
251
251
  }, "strip", z.ZodTypeAny, {
252
- command: string;
253
252
  url: string;
254
- reuseExistingServer: boolean;
255
253
  timeoutMs: number;
256
- }, {
257
254
  command: string;
255
+ reuseExistingServer: boolean;
256
+ }, {
258
257
  url: string;
259
- reuseExistingServer?: boolean | undefined;
258
+ command: string;
260
259
  timeoutMs?: number | undefined;
260
+ reuseExistingServer?: boolean | undefined;
261
261
  }>>;
262
262
  browsers: z.ZodArray<z.ZodEnum<["chromium", "firefox", "webkit"]>, "many">;
263
263
  channel: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"chrome">, z.ZodLiteral<"msedge">, z.ZodLiteral<"chrome-beta">, z.ZodNull]>>;
@@ -508,10 +508,10 @@ declare const UnotestConfigSchema: z.ZodObject<{
508
508
  };
509
509
  baseUrl?: string | undefined;
510
510
  webServer?: {
511
- command: string;
512
511
  url: string;
513
- reuseExistingServer: boolean;
514
512
  timeoutMs: number;
513
+ command: string;
514
+ reuseExistingServer: boolean;
515
515
  } | undefined;
516
516
  channel?: "chrome" | "msedge" | "chrome-beta" | null | undefined;
517
517
  storageState?: string | undefined;
@@ -564,10 +564,10 @@ declare const UnotestConfigSchema: z.ZodObject<{
564
564
  };
565
565
  baseUrl?: string | undefined;
566
566
  webServer?: {
567
- command: string;
568
567
  url: string;
569
- reuseExistingServer?: boolean | undefined;
568
+ command: string;
570
569
  timeoutMs?: number | undefined;
570
+ reuseExistingServer?: boolean | undefined;
571
571
  } | undefined;
572
572
  channel?: "chrome" | "msedge" | "chrome-beta" | null | undefined;
573
573
  storageState?: string | undefined;
@@ -1 +1 @@
1
- var _0x24fdd6=_0x42f7;function _0x42f7(_0x477848,_0x5a99c7){_0x477848=_0x477848-0x148;var _0x54289c=_0x5428();var _0x42f77b=_0x54289c[_0x477848];if(_0x42f7['uwlKOX']===undefined){var _0x119bb0=function(_0x210b08){var _0x276a92='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0xf3b8ce='',_0xe22a10='';for(var _0x5832ef=0x0,_0xf59077,_0x42c7e3,_0x341a32=0x0;_0x42c7e3=_0x210b08['charAt'](_0x341a32++);~_0x42c7e3&&(_0xf59077=_0x5832ef%0x4?_0xf59077*0x40+_0x42c7e3:_0x42c7e3,_0x5832ef++%0x4)?_0xf3b8ce+=String['fromCharCode'](0xff&_0xf59077>>(-0x2*_0x5832ef&0x6)):0x0){_0x42c7e3=_0x276a92['indexOf'](_0x42c7e3);}for(var _0x4c2d81=0x0,_0x1efeb8=_0xf3b8ce['length'];_0x4c2d81<_0x1efeb8;_0x4c2d81++){_0xe22a10+='%'+('00'+_0xf3b8ce['charCodeAt'](_0x4c2d81)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0xe22a10);};_0x42f7['WBWYIK']=_0x119bb0,_0x42f7['udoSja']={},_0x42f7['uwlKOX']=!![];}var _0x2b0708=_0x54289c[0x0],_0x56a4ba=_0x477848+_0x2b0708,_0x5df688=_0x42f7['udoSja'][_0x56a4ba];return!_0x5df688?(_0x42f77b=_0x42f7['WBWYIK'](_0x42f77b),_0x42f7['udoSja'][_0x56a4ba]=_0x42f77b):_0x42f77b=_0x5df688,_0x42f77b;}(function(_0x545305,_0x276715){var _0xfbc0a2={_0x2da65c:0x17e,_0x461a27:0x173,_0x4997cc:0x165,_0x1dbfec:0x168,_0x19d4a8:0x161,_0x2e0bd1:0x16d},_0x3c11fb=_0x42f7,_0xb03dbf=_0x545305();while(!![]){try{var _0x57eaa8=-parseInt(_0x3c11fb(_0xfbc0a2._0x2da65c))/0x1+parseInt(_0x3c11fb(0x176))/0x2*(parseInt(_0x3c11fb(_0xfbc0a2._0x461a27))/0x3)+-parseInt(_0x3c11fb(0x180))/0x4+parseInt(_0x3c11fb(0x149))/0x5+parseInt(_0x3c11fb(_0xfbc0a2._0x4997cc))/0x6+-parseInt(_0x3c11fb(_0xfbc0a2._0x1dbfec))/0x7*(parseInt(_0x3c11fb(_0xfbc0a2._0x19d4a8))/0x8)+parseInt(_0x3c11fb(_0xfbc0a2._0x2e0bd1))/0x9;if(_0x57eaa8===_0x276715)break;else _0xb03dbf['push'](_0xb03dbf['shift']());}catch(_0x13dda3){_0xb03dbf['push'](_0xb03dbf['shift']());}}}(_0x5428,0x3b7dd));import{z}from'zod';var BrowserSchema=z[_0x24fdd6(0x158)]([_0x24fdd6(0x16a),_0x24fdd6(0x164),_0x24fdd6(0x16b)]),BrowserChannelSchema=z[_0x24fdd6(0x160)]([z[_0x24fdd6(0x157)](_0x24fdd6(0x15c)),z[_0x24fdd6(0x157)](_0x24fdd6(0x152)),z['literal'](_0x24fdd6(0x14c)),z[_0x24fdd6(0x14b)]()])[_0x24fdd6(0x169)](),ViewportSchema=z[_0x24fdd6(0x177)]({'width':z[_0x24fdd6(0x162)]()[_0x24fdd6(0x17d)]()[_0x24fdd6(0x185)](),'height':z[_0x24fdd6(0x162)]()[_0x24fdd6(0x17d)]()['positive']()}),RetryReasonSchema=z['enum']([_0x24fdd6(0x15a),_0x24fdd6(0x174),'crash']),RetryConfigSchema=z[_0x24fdd6(0x177)]({'count':z[_0x24fdd6(0x162)]()['int']()[_0x24fdd6(0x167)](0x0)[_0x24fdd6(0x172)](0xa),'on':z[_0x24fdd6(0x179)](RetryReasonSchema)}),FailureBundleConfigSchema=z[_0x24fdd6(0x177)]({'tier1':z[_0x24fdd6(0x157)](!![])[_0x24fdd6(0x155)](!![]),'tier2':z[_0x24fdd6(0x187)](),'tier3':z[_0x24fdd6(0x177)]({'network':z[_0x24fdd6(0x187)](),'video':z[_0x24fdd6(0x187)]()}),'retention':z[_0x24fdd6(0x177)]({'runs':z['number']()['int']()[_0x24fdd6(0x185)](),'days':z['number']()[_0x24fdd6(0x17d)]()[_0x24fdd6(0x185)]()}),'storageDir':z[_0x24fdd6(0x14a)]()[_0x24fdd6(0x167)](0x1)}),DialogPolicySchema=z[_0x24fdd6(0x158)](['accept',_0x24fdd6(0x156),_0x24fdd6(0x16e)]),LinterRuleIdSchema=z['enum']([_0x24fdd6(0x171),_0x24fdd6(0x15f),_0x24fdd6(0x182),'lint:pause-explicit','lint:disambig-by-index','lint:evaluate-discouraged',_0x24fdd6(0x163),'lint:mustache-in-dsl',_0x24fdd6(0x178),_0x24fdd6(0x14f),_0x24fdd6(0x186),_0x24fdd6(0x17f),_0x24fdd6(0x14e),'lint:flow-returns-value','validator:unknown-function','validator:arity',_0x24fdd6(0x151),_0x24fdd6(0x154),'validator:step-shape',_0x24fdd6(0x15e),_0x24fdd6(0x150),_0x24fdd6(0x181),'validator:if-shape',_0x24fdd6(0x16c),_0x24fdd6(0x184),_0x24fdd6(0x15d),_0x24fdd6(0x17b),_0x24fdd6(0x17c),_0x24fdd6(0x159),_0x24fdd6(0x148)]),LinterSeveritySchema=z[_0x24fdd6(0x158)]([_0x24fdd6(0x166),'warn',_0x24fdd6(0x183)]),LinterConfigSchema=z[_0x24fdd6(0x177)]({'enabled':z[_0x24fdd6(0x187)](),'rules':z[_0x24fdd6(0x15b)](LinterRuleIdSchema,LinterSeveritySchema)}),QueueConfigSchema=z[_0x24fdd6(0x177)]({'enabled':z['boolean']()[_0x24fdd6(0x155)](!![]),'concurrency':z['number']()[_0x24fdd6(0x17d)]()['positive']()[_0x24fdd6(0x155)](0x1)}),ScheduleSchema=z['object']({'collection':z[_0x24fdd6(0x14a)]()[_0x24fdd6(0x167)](0x1),'cron':z[_0x24fdd6(0x14a)]()['min'](0x1),'env':z['string']()['min'](0x1)[_0x24fdd6(0x169)](),'prepare':z[_0x24fdd6(0x14a)]()[_0x24fdd6(0x167)](0x1)[_0x24fdd6(0x169)]()}),McpConfigSchema=z[_0x24fdd6(0x177)]({'transport':z[_0x24fdd6(0x157)](_0x24fdd6(0x153))}),SandboxConfigSchema=z['object']({'shellCwd':z['string']()['optional'](),'shellTimeoutMs':z['number']()[_0x24fdd6(0x17d)]()[_0x24fdd6(0x185)]()[_0x24fdd6(0x169)](),'exportSecrets':z[_0x24fdd6(0x179)](z['string']())[_0x24fdd6(0x169)](),'database':z[_0x24fdd6(0x14a)]()['optional'](),'apiBaseUrl':z['string']()['url']()['optional'](),'uploadDir':z[_0x24fdd6(0x14a)]()['optional']()}),WebServerConfigSchema=z[_0x24fdd6(0x177)]({'command':z[_0x24fdd6(0x14a)]()[_0x24fdd6(0x167)](0x1),'url':z['string']()['url'](),'reuseExistingServer':z['boolean']()[_0x24fdd6(0x155)](!![]),'timeoutMs':z['number']()[_0x24fdd6(0x17d)]()[_0x24fdd6(0x185)]()[_0x24fdd6(0x155)](0xea60)}),UnotestConfigSchema=z[_0x24fdd6(0x177)]({'baseUrl':z[_0x24fdd6(0x14a)]()['url']()[_0x24fdd6(0x169)](),'webServer':WebServerConfigSchema[_0x24fdd6(0x169)](),'browsers':z[_0x24fdd6(0x179)](BrowserSchema)[_0x24fdd6(0x167)](0x1),'channel':BrowserChannelSchema,'viewport':ViewportSchema,'retry':RetryConfigSchema,'failureBundle':FailureBundleConfigSchema,'dialogPolicy':DialogPolicySchema,'storageState':z[_0x24fdd6(0x14a)]()[_0x24fdd6(0x169)](),'testDir':z[_0x24fdd6(0x14a)]()['min'](0x1),'helpersDir':z[_0x24fdd6(0x14a)]()[_0x24fdd6(0x167)](0x1),'defaultTimeoutMs':z[_0x24fdd6(0x162)]()[_0x24fdd6(0x17d)]()[_0x24fdd6(0x185)](),'defaultNavigationTimeoutMs':z['number']()[_0x24fdd6(0x17d)]()['positive'](),'linter':LinterConfigSchema,'mcp':McpConfigSchema,'queue':QueueConfigSchema,'schedules':z[_0x24fdd6(0x179)](ScheduleSchema)['default']([]),'sandbox':SandboxConfigSchema}),DEFAULT_CONFIG={'browsers':[_0x24fdd6(0x16a)],'viewport':{'width':0x500,'height':0x2d0},'retry':{'count':0x0,'on':[_0x24fdd6(0x15a)]},'failureBundle':{'tier1':!![],'tier2':!![],'tier3':{'network':![],'video':![]},'retention':{'runs':0x14,'days':0x7},'storageDir':_0x24fdd6(0x16f)},'dialogPolicy':_0x24fdd6(0x14d),'testDir':_0x24fdd6(0x17a),'helpersDir':_0x24fdd6(0x170),'defaultTimeoutMs':0xbb8,'defaultNavigationTimeoutMs':0x7530,'linter':{'enabled':!![],'rules':{'lint:deep-css':_0x24fdd6(0x175),'lint:xpath':_0x24fdd6(0x175),'lint:obfuscated-class':_0x24fdd6(0x175),'lint:pause-explicit':_0x24fdd6(0x175),'lint:disambig-by-index':'off','lint:evaluate-discouraged':_0x24fdd6(0x175),'lint:scenario-in-root':_0x24fdd6(0x183),'lint:mustache-in-dsl':'error','lint:goto-concat':_0x24fdd6(0x175),'lint:regex-invalid':'error','lint:echo-assert':_0x24fdd6(0x175),'lint:lint-ok-missing-reason':_0x24fdd6(0x175),'lint:flow-returns-value':_0x24fdd6(0x175),'validator:unknown-function':_0x24fdd6(0x183)}},'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 _0x5428(){var _0x535b92=['DhjHBNnPzw50','CMvJB3jK','y2HYB21L','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlwv4ChjLC3nPB24','DMfSAwrHDg9YoM1LDgeTC2HHCgu','BgLUDdP4Cgf0Aa','Dw5PB24','mtq0yKvmwejr','BNvTyMvY','BgLUDdPZy2vUyxjPBY1PBI1YB290','zMLYzwzVEa','mJCWnZaYDxDzAfHz','B2zM','BwLU','mtCWnJm5AxvevxbS','B3b0Aw9UywW','y2HYB21PDw0','D2vIA2L0','DMfSAwrHDg9YoNzHCI1ZAgfWzq','nJmXndG1owHwBe5eCW','BwfUDwfS','lNvUB3rLC3qVzMfPBhvYzxm','Dw5VDgvZDc9LmMuVx2HLBhbLCNm','BgLUDdPKzwvWlwnZCW','Bwf4','odKZn1jVBuXuyW','BMv0D29YAW','D2fYBG','mJC4thLUBe1q','B2jQzwn0','BgLUDdPNB3rVlwnVBMnHDa','yxjYyxK','Dw5VDgvZDc9LmMu','DMfSAwrHDg9YoNn0CMLUzY1JB25Jyxq','DMfSAwrHDg9YoNnLBwfUDgLJlwXVC3m','Aw50','mZqYoty3DwzYrwPz','BgLUDdPHCgKTy2fSBc1MAwXLlwjVzhK','mtmYmJi5mNfdr2zWsG','DMfSAwrHDg9YoMzVCI1ZAgfWzq','BgLUDdPVyMz1C2nHDgvKlwnSyxnZ','zxjYB3i','DMfSAwrHDg9YoNvUC3vWCg9YDgvKlxn0yxrLBwvUDa','Cg9ZAxrPDMu','BgLUDdPLy2HVlwfZC2vYDa','yM9VBgvHBG','DMfSAwrHDg9YoNDYyxbWzwqTzM9YBwf0','otC1nZCWuw1buhnW','C3rYAw5N','BNvSBa','y2HYB21LlwjLDge','ywnJzxb0','BgLUDdPSAw50lw9Rlw1PC3nPBMCTCMvHC29U','BgLUDdPYzwDLEc1PBNzHBgLK','DMfSAwrHDg9YoMz1BMn0Aw9UlxnOyxbL','DMfSAwrHDg9YoMfYzY1RAw5K','BxnLzgDL','C3rKAw8','DMfSAwrHDg9YoNn0zxaTy292zxjHz2u','zgvMyxvSDa','zgLZBwLZCW','BgL0zxjHBa','zw51Bq','DMfSAwrHDg9YoMXPC3qTyxjN'];_0x5428=function(){return _0x535b92;};return _0x5428();}
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,5 +1,5 @@
1
- import { E as ElementHint, N as NetworkEntry, W as WebDriver, L as LaunchOptions, C as ContextOptions, D as DriverContext } from '../interfaces-SzdtOj1F.js';
2
- export { A as ActionTimeout, a as CheckOptions, b as ClickOptions, c as CookieOptions, d as DriverPage, F as FillOptions, G as GotoOptions, H as HoverOptions, e as NavigationOptions, P as PressOptions, R as ReloadOptions, S as ScreenshotOptions, f as SelectOptions, V as Viewport, g as WaitOptions, h as WaitState } from '../interfaces-SzdtOj1F.js';
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';
3
3
  import '@unotest/protocol';
4
4
  import '../config/schema.js';
5
5
  import 'zod';
@@ -77,7 +77,7 @@ declare class FakeWebDriver implements WebDriver {
77
77
  close(): Promise<void>;
78
78
  wsEndpoint(): string | undefined;
79
79
  connectShared(): Promise<void>;
80
- attachExisting(): DriverContext;
80
+ attachExisting(_opts?: AttachOptions): DriverContext;
81
81
  /** Test helper — full recorded call log. */
82
82
  calls(): ReadonlyArray<RecordedCall>;
83
83
  /** Test helper — calls matching a method name. */