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