@unotest/viewer 0.25.0 → 0.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +209 -0
- package/dist/server/main.d.ts +25 -1
- package/dist/server/main.js +1 -1
- package/dist/server/session.js +1 -1
- package/dist/web/assets/{DslEditor-CH1LMVsm.js → DslEditor-CT74_mfE.js} +2 -2
- package/dist/web/assets/index-BLJmmyy1.css +32 -0
- package/dist/web/assets/index-_nO3nPAp.js +55 -0
- package/dist/web/index.html +2 -2
- package/package.json +6 -5
- package/dist/web/assets/index-BXkiMgUh.js +0 -55
- package/dist/web/assets/index-DuC1twE7.css +0 -32
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,214 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.26.1] - 2026-08-30
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fix: a run started from a box's viewer stayed pending and never reached
|
|
8
|
+
the history
|
|
9
|
+
|
|
10
|
+
The viewer watched the run directories of environments it could see on
|
|
11
|
+
disk — overlay files `unotest/.env.<name>` and existing `.runs.<name>`
|
|
12
|
+
directories. A box has neither at start: environment values come from the
|
|
13
|
+
daemon, not from a file, and the runs directory appears with the first
|
|
14
|
+
run. So the viewer watched only the base root while every run was filed
|
|
15
|
+
under `.runs.<environment>`: the tab stayed PENDING, the history stayed
|
|
16
|
+
empty and the run 404-ed by its own id, until a restart happened to find
|
|
17
|
+
the directory already there. The environment a viewer was started for is
|
|
18
|
+
now known to it by definition, whatever the disk says.
|
|
19
|
+
|
|
20
|
+
- Fix: a run's captured output landed outside the run's directory
|
|
21
|
+
|
|
22
|
+
`stdout.log` / `stderr.log` were written to `<runs-root>/<runId>/` while
|
|
23
|
+
the run itself lives under its date shard — two orphan directories next to
|
|
24
|
+
the shard, holding the only copy of what the child said.
|
|
25
|
+
|
|
26
|
+
- Fix: a viewer started for an environment listed no runs at all
|
|
27
|
+
|
|
28
|
+
The standalone launcher read the project root, the port, the host and the
|
|
29
|
+
target from its environment — but not `UNOTEST_ENV`. A box starts one
|
|
30
|
+
viewer per environment and names it exactly that way, so every one of them
|
|
31
|
+
came up on the BASE runs directory while its runs were being filed under
|
|
32
|
+
`.runs.<environment>`: an empty history on a box that had just finished a
|
|
33
|
+
suite. Found on the first end-to-end run of the local box stand.
|
|
34
|
+
|
|
35
|
+
- 9424f6b: Fix: screenshots stayed blank in the viewer when runs write to a separate
|
|
36
|
+
artifact root
|
|
37
|
+
|
|
38
|
+
A run whose artifacts do not live under the working directory — every run on
|
|
39
|
+
a box, where the sources are a disposable copy of a test bundle — emitted
|
|
40
|
+
`screenshot` events whose path was relativised against the working directory.
|
|
41
|
+
That came out as `../../../…`, which the viewer's asset route refuses to
|
|
42
|
+
serve, so every step preview rendered as a broken image. Artifact paths are
|
|
43
|
+
now relative to the artifact root, which is still the project root on every
|
|
44
|
+
local run.
|
|
45
|
+
|
|
46
|
+
The failure bundle had the mirror-image problem: it was written to
|
|
47
|
+
`.unotest/failures/` under the working directory, so on a box it landed
|
|
48
|
+
inside the bundle copy — outside the tree the viewer serves, and discarded on
|
|
49
|
+
the next bundle push. It now hangs off the artifact root too, which leaves
|
|
50
|
+
local runs byte-for-byte unchanged.
|
|
51
|
+
|
|
52
|
+
The inspector's Semantic DOM, Console, Network and Snapshot panes were dark
|
|
53
|
+
for a third reason, and this one bit local runs as well: they composed the
|
|
54
|
+
run's directory in the browser and left out the date shard runs have been
|
|
55
|
+
filed under since M-10, plus the environment suffix on a box. The viewer's
|
|
56
|
+
asset route now takes `?file=<name-relative-to-the-run-dir>` and resolves the
|
|
57
|
+
directory itself — runs root, target suffix, environment suffix and shard are
|
|
58
|
+
all things only the server knows. `?path=` stays for the whole paths the
|
|
59
|
+
server ships on run events.
|
|
60
|
+
|
|
61
|
+
- Updated dependencies [9424f6b]
|
|
62
|
+
- @unotest/protocol@0.26.1
|
|
63
|
+
- @unotest/core@0.26.1
|
|
64
|
+
- @unotest/dsl@0.26.1
|
|
65
|
+
|
|
66
|
+
## [0.26.0] - 2026-08-30
|
|
67
|
+
|
|
68
|
+
### Minor Changes
|
|
69
|
+
|
|
70
|
+
- 3eede7c: The viewer can now be hosted: it shows which test bundle an environment
|
|
71
|
+
is running, and lets you switch it.
|
|
72
|
+
|
|
73
|
+
This is the other half of `bundle push`. Nothing changes for a local
|
|
74
|
+
viewer — everything here appears only when something is hosting it.
|
|
75
|
+
|
|
76
|
+
- **The artifact root and the project root are now genuinely separate.**
|
|
77
|
+
The viewer already took `UNOTEST_ARTIFACTS_ROOT` for the run queue;
|
|
78
|
+
run discovery, the run index, snapshots, log capture and the viewer's
|
|
79
|
+
own lock file now honour it too. Locally the two are the same directory
|
|
80
|
+
and nothing moves. Where they differ — sources in a disposable copy of a
|
|
81
|
+
bundle, history in the environment beside it — the history is no longer
|
|
82
|
+
read out of (or written into) the sources.
|
|
83
|
+
- **Bundle badge in the status bar.** `main@1a2b3c4`, or `wip` for a
|
|
84
|
+
bundle packed from an uncommitted tree, with the author, the pinned
|
|
85
|
+
`@unotest/web` and who switched the environment last. Clicking it lists
|
|
86
|
+
the bundles pushed to this environment and switches to one — that runs
|
|
87
|
+
as a maintenance ticket on the host, so it waits for the environment to
|
|
88
|
+
be free instead of pulling the code out from under a running suite.
|
|
89
|
+
- **Runs remember their bundle.** `manifest.json` and `GET /api/runs`
|
|
90
|
+
carry `bundleId` (from `UNOTEST_BUNDLE_ID`, set by the host); the runs
|
|
91
|
+
list marks the ones that ran on another bundle, so "was this red run
|
|
92
|
+
even the code I am looking at?" has an answer.
|
|
93
|
+
- **The contract is a file, not a mode.** `@unotest/protocol` gains
|
|
94
|
+
`WorkspaceFile` — the host writes `unotest/.workspace.json` beside the
|
|
95
|
+
artifacts and the viewer reads it, the same way the guard's session
|
|
96
|
+
header narrows the UI. No file, no bundle UI; the viewer never learns
|
|
97
|
+
what a box is. Values of environment variables and secrets never appear
|
|
98
|
+
in it — only their names.
|
|
99
|
+
- **Queue tickets can name a bundle.** `QueueTicket.source.bundleId` is
|
|
100
|
+
recorded when a run is queued, so a run executes the code it was
|
|
101
|
+
ordered with even if the environment moved on while it waited.
|
|
102
|
+
|
|
103
|
+
- dbfa36f: Your CI can now ask a box to run the suite it just pushed, and a box can
|
|
104
|
+
report the result back to GitHub.
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
npx @unotest/web bundle push --run --env test --collection smoke
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`--run` sends the second half of the CI recipe: upload the bundle, then
|
|
111
|
+
order a run of it. Two requests rather than one flag on the upload,
|
|
112
|
+
because a bundle is _content_ — pushing an identical tree twice is normal
|
|
113
|
+
and answers `exists` — while "run it" is an event. The same split is what
|
|
114
|
+
lets a deploy script run a bundle somebody pushed hours ago.
|
|
115
|
+
|
|
116
|
+
- **The box answers as soon as the runs are queued** (202) with their run
|
|
117
|
+
ids. A suite takes minutes to hours; an HTTP request held open for that
|
|
118
|
+
long is a timeout in somebody's proxy, not a result. The ids are real
|
|
119
|
+
from the moment you get them, so a CI log can print a link into the
|
|
120
|
+
viewer straight away.
|
|
121
|
+
- **`--env <name>` is required with `--run`.** Which environments a box
|
|
122
|
+
has is the operator's decision, and guessing one would be guessing
|
|
123
|
+
which system gets tested.
|
|
124
|
+
- **Without `--collection`, the box runs what that environment normally
|
|
125
|
+
runs** — the collections its `schedules` name. Naming them explicitly is
|
|
126
|
+
the deploy-check case; leaving it out is the "same as every night" case.
|
|
127
|
+
- **`--pr <number>` coalesces.** A newer push of the same pull request
|
|
128
|
+
withdraws its older runs that are still _waiting_; a run that already
|
|
129
|
+
started is never killed. Three pushes in five minutes cost one suite.
|
|
130
|
+
`--json` reports how many were withdrawn, so "my run vanished" has an
|
|
131
|
+
answer in the log of the run that replaced it.
|
|
132
|
+
- **Refusals are typed and say what to do**: no such environment, an
|
|
133
|
+
environment belonging to another project, a bundle the box no longer
|
|
134
|
+
holds, nothing to run.
|
|
135
|
+
|
|
136
|
+
On a hosted viewer, the queue panel now names the change each machine
|
|
137
|
+
ticket belongs to (`PR #412@1a2b3c4`) instead of a row of identical "ci"
|
|
138
|
+
entries, and the history gained a **this bundle only** filter for the
|
|
139
|
+
moment you are judging the bundle in front of you rather than the last
|
|
140
|
+
month of runs.
|
|
141
|
+
|
|
142
|
+
Nothing changes for a local `npx @unotest/web viewer`: there are no
|
|
143
|
+
bundles there, so neither the badge nor the filter appears.
|
|
144
|
+
|
|
145
|
+
- c43aa00: Runs of one project now take turns instead of colliding.
|
|
146
|
+
|
|
147
|
+
Until now nothing coordinated them: the viewer refused a second run with
|
|
148
|
+
HTTP 409, and that was the whole defence — a `npx @unotest/web e2e` in a
|
|
149
|
+
terminal, an agent's `run_test` and a scheduled suite would all start on
|
|
150
|
+
top of each other, driving the same browser and the same seeded database
|
|
151
|
+
at the same time. The 409 protected the UI, not the machine.
|
|
152
|
+
|
|
153
|
+
- **A filesystem queue**, in `unotest/.queue<target>[.<env>]/` beside the
|
|
154
|
+
runs root it belongs to. A run writes a ticket, waits until it is at
|
|
155
|
+
the head, takes a slot, runs, and gives the slot back. There is no
|
|
156
|
+
daemon: whoever holds the slot executes the run itself, so nothing new
|
|
157
|
+
has to be installed, started or kept alive. Only `open("wx")`, rename,
|
|
158
|
+
unlink and mtime — no `flock`, which lies on network and container
|
|
159
|
+
filesystems. A crashed producer is reaped by whoever comes next.
|
|
160
|
+
- **Every producer is in it**: the CLI (`e2e`, `collection`, `author`),
|
|
161
|
+
the viewer's Run button, and the MCP `run_test` (which spawns the CLI).
|
|
162
|
+
A collection is ONE run — its `workers` still run in parallel inside
|
|
163
|
+
it, because a child process carries its parent's lease and skips the
|
|
164
|
+
queue.
|
|
165
|
+
- **The viewer shows the queue**: the Active panel lists what is waiting,
|
|
166
|
+
including tickets a terminal or an agent wrote, with a button to take
|
|
167
|
+
any of them back out. `GET /api/queue`, `DELETE /api/queue/:ticket`,
|
|
168
|
+
and a `queue:changed` websocket message.
|
|
169
|
+
- **Config**: `queue.concurrency` (default 1) and `queue.enabled`
|
|
170
|
+
(default true) in `unotest.config`. Both the CLI and the viewer read
|
|
171
|
+
the same file, so they cannot disagree about how many slots exist.
|
|
172
|
+
- **Escape hatches**: `UNOTEST_NO_QUEUE=1` runs without queueing;
|
|
173
|
+
Ctrl-C while waiting gives up your place in line and runs nothing.
|
|
174
|
+
- **For boxes**: `UNOTEST_QUEUE_GLOBAL_DIR` + `UNOTEST_QUEUE_GLOBAL_SLOTS`
|
|
175
|
+
add a host-wide budget several environments share (a collection weighs
|
|
176
|
+
its worker count), and `UNOTEST_ARTIFACTS_ROOT` puts `.runs` / `.queue`
|
|
177
|
+
somewhere other than the directory the tests live in — so the history
|
|
178
|
+
outlives a throwaway copy of the tests.
|
|
179
|
+
|
|
180
|
+
### Migration notes
|
|
181
|
+
|
|
182
|
+
**`POST /api/run` no longer answers 409.** Ordering a run while another
|
|
183
|
+
one is active used to fail with `ActiveRunConflictError` (HTTP 409); it
|
|
184
|
+
now succeeds and the run waits. The response changed shape with it:
|
|
185
|
+
|
|
186
|
+
```diff
|
|
187
|
+
- { runId, kind, ref, pid, startedAt }
|
|
188
|
+
+ { runId, kind, ref, status: "queued" | "running", ticket, acceptedAt }
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`runId` is still final and immediately usable — open the tab on it as
|
|
192
|
+
before — but the run may not have started yet, and `pid` is not known at
|
|
193
|
+
that point. `POST /api/runs/:runId/abort` covers both states: it
|
|
194
|
+
withdraws a waiting ticket or SIGTERMs a running child.
|
|
195
|
+
|
|
196
|
+
Anything that treated 409 as "busy, try later" should now simply order
|
|
197
|
+
the run. Anything that relied on "only one run can exist" should read
|
|
198
|
+
`GET /api/queue`. To keep the old immediate-start behaviour (without the
|
|
199
|
+
protection), set `queue.enabled: false`.
|
|
200
|
+
|
|
201
|
+
### Patch Changes
|
|
202
|
+
|
|
203
|
+
- Updated dependencies [3eede7c]
|
|
204
|
+
- Updated dependencies [6d1c612]
|
|
205
|
+
- Updated dependencies [dbfa36f]
|
|
206
|
+
- Updated dependencies [c43aa00]
|
|
207
|
+
- Updated dependencies [8ec4177]
|
|
208
|
+
- @unotest/protocol@0.26.0
|
|
209
|
+
- @unotest/core@0.26.0
|
|
210
|
+
- @unotest/dsl@0.26.0
|
|
211
|
+
|
|
3
212
|
## [0.25.0] - 2026-08-29
|
|
4
213
|
|
|
5
214
|
### Minor Changes
|
package/dist/server/main.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { IRunnerAdapter, IDslLanguageService, IProcessLauncher } from '@unotest/protocol';
|
|
2
2
|
|
|
3
|
+
interface ViewerQueueConfig {
|
|
4
|
+
/** With queueing off, the viewer starts every run immediately — and
|
|
5
|
+
* so does every terminal. Nothing serialises them. */
|
|
6
|
+
readonly enabled: boolean;
|
|
7
|
+
/** Runs allowed in flight for one environment. */
|
|
8
|
+
readonly concurrency: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
interface RunnerEntry {
|
|
4
12
|
/** Short target id derived from the runner package name —
|
|
5
13
|
* `web`/`mobile`/`unity`. Drives the UI switcher and per-target tree
|
|
@@ -38,6 +46,14 @@ interface StartViewerOptions {
|
|
|
38
46
|
* injects its bundled `node` + runner bin so terminal commands resolve
|
|
39
47
|
* without a system install). */
|
|
40
48
|
terminalPathPrefix?: readonly string[];
|
|
49
|
+
/** Run-queue policy, read from the project's `unotest.config` by the
|
|
50
|
+
* launcher. Omitted (the standalone bin) = the shipped default: queue
|
|
51
|
+
* on, one run at a time. Both the viewer and the CLI must see the SAME
|
|
52
|
+
* numbers — they share one queue directory. */
|
|
53
|
+
queue?: ViewerQueueConfig;
|
|
54
|
+
/** Absolute artifact root when it is not the project root
|
|
55
|
+
* (`UNOTEST_ARTIFACTS_ROOT`); see `ViewerConfig.artifactsRoot`. */
|
|
56
|
+
artifactsRoot?: string;
|
|
41
57
|
}
|
|
42
58
|
interface ViewerHandle {
|
|
43
59
|
url: string;
|
|
@@ -57,6 +73,14 @@ declare function startViewerServer(opts: StartViewerOptions): Promise<ViewerHand
|
|
|
57
73
|
* the installed `@unotest/*` runner packages (by name — DIP boundary
|
|
58
74
|
* intact). `UNOTEST_RUNNER_PKG` (legacy single-runner var) and
|
|
59
75
|
* `UNOTEST_TARGET` just pick which detected target is active at boot. */
|
|
76
|
+
/** Everything the standalone launcher reads from its environment, in one
|
|
77
|
+
* pure place so the plumbing is testable without starting a server.
|
|
78
|
+
*
|
|
79
|
+
* `activeEnv` is the one that has bitten: a box starts one viewer per
|
|
80
|
+
* environment and says which through `UNOTEST_ENV`. Dropping it left every
|
|
81
|
+
* viewer reading the BASE runs directory while its runs were filed under
|
|
82
|
+
* `.runs.<env>` — an empty history on a box that had just run a suite. */
|
|
83
|
+
declare function viewerCliOptions(env: NodeJS.ProcessEnv, cwd: string): Omit<StartViewerOptions, "runners">;
|
|
60
84
|
declare function runViewerCli(): Promise<void>;
|
|
61
85
|
|
|
62
|
-
export { type RunnerEntry, type StartViewerOptions, type ViewerHandle, runViewerCli, startViewerServer };
|
|
86
|
+
export { type RunnerEntry, type StartViewerOptions, type ViewerHandle, runViewerCli, startViewerServer, viewerCliOptions };
|