You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit ae77e80
Browse filesBrowse the repository at this point in the historyBrowse files
The trace player opens several traces at once. `show-trace` accepts several zips or a folder (`npx show-trace test-results/`), and the hosted player takes several zips through its Open button, or zips and folders dropped on the page. The player then lists every trace beside the timeline, one row per test with its outcome, failures first and then in run order, and plays the one picked without reloading. With `traceGranularity: 'test'` a run is a folder of per-test zips, so the whole run opens in one go. A zip records no test state, so the outcome is read from the trace: failed when an action or step failed, passed when it holds actions and none failed, unknown when it holds none. Files in the folder that are not zips are skipped, and a zip that cannot be opened is listed with the reason without stopping the rest. Opening a single zip works exactly as before.
Copy file name to clipboardExpand all lines: CLAUDE.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -105,7 +105,7 @@ They import from `shared` and `core`, never from each other. They aren't importe
105
105
106
106
### Backend and app are framework-agnostic
107
107
108
-
`backend` and `app` import from `shared` (for contracts) and from each other via the WS/HTTP boundary. Neither imports an adapter package. `backend` also imports `trace`, to write and read zips; `app` imports only `trace`'s reader, which the hosted player (`trace.webdriver.io`, built with `pnpm player:hosted`, deployed by Vercel from `vercel.json`) runs in the browser to open a dropped zip with no backend at all. It runs the reader in a module Web Worker loaded from the player's own origin (`app/src/controller/trace-parse.worker.ts`, which `script-src 'self'` already admits), so the tab stays responsive and the landing screen names the phase the open is on; the live build never references the worker. That build is `HOSTED_PLAYER` in `app/src/controller/constants.ts`; it never writes the trace to browser storage, and `vercel.json` is also what `vite preview` serves, so its CSP is checked locally before it ships.
108
+
`backend` and `app` import from `shared` (for contracts) and from each other via the WS/HTTP boundary. Neither imports an adapter package. `backend` also imports `trace`, to write and read zips; `app` imports only `trace`'s reader, which the hosted player (`trace.webdriver.io`, built with `pnpm player:hosted`, deployed by Vercel from `vercel.json`) runs in the browser to open a dropped zip with no backend at all. It runs the reader in a module Web Worker loaded from the player's own origin (`app/src/controller/trace-parse.worker.ts`, which `script-src 'self'` already admits), so the tab stays responsive and the landing screen names the phase the open is on; the live build never references the worker. That build is `HOSTED_PLAYER` in `app/src/controller/constants.ts`; it never writes the trace to browser storage, and `vercel.json` is also what `vite preview` serves, so its CSP is checked locally before it ships. Several zips or a folder open as a run (`controller/trace-run.ts`), in the hosted player and in `show-trace`, which lists them at `TRACE_API.run` for the app to read: each zip is parsed once, one at a time, and its payload kept for when its row is picked. A zip records no test state, so a row's outcome is read from its rows (`utils/trace-summary.ts`: a failed action or step means failed, actions with none failed mean passed, no actions mean unknown); a jest `expect` that records no row can therefore fail a test whose trace reads as passed. Keeping every payload costs memory in proportion to the run; a reader that reads entries on demand would shrink each payload, which is why the run holds the reader's own payload rather than a cache of its own.
109
109
110
110
Framework-specific behavior in the backend is contained in two files: `runner.ts` and `framework-filters.ts`. Both branch on a typed `TestRunnerId` from shared, never on a magic string. The `framework-filters` dispatch is a `switch` over `TestRunnerId` (not a table lookup) so CodeQL's `unvalidated-dynamic-method-call` query trusts the call site.
Copy file name to clipboardExpand all lines: README.md
+12-1Lines changed: 12 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -262,7 +262,16 @@ The player exposes everything captured in the archive:
262
262
263
263
The `show-trace` bin is exposed by each JavaScript adapter (`@wdio/devtools-service`, `@wdio/nightwatch-devtools`, `@wdio/selenium-devtools`), so `pnpm show-trace <zip>` / `npx show-trace <zip>` work in any project that installs one — no extra dependency.
264
264
265
-
**Hosted player: [trace.webdriver.io](https://trace.webdriver.io).** The same player as a web page, for opening a trace without installing anything: drop a `.zip` on the page or pick one. The archive is parsed in the browser tab and never uploaded, which matters because a trace records everything the run showed or typed. Run controls are absent, as in `show-trace`. A replayed page still loads its own stylesheets and images from the site under test, as it does in `show-trace`; from an `https` page the browser blocks the `http` ones, so a trace of an `http` site can render unstyled there and fully in `show-trace`. To try the hosted build locally:
265
+
**A whole run at once.** With `traceGranularity: 'test'` every test writes its own `trace.zip`, so a run is a folder of them. Give `show-trace` the folder, or several zips, and the player lists every trace beside the timeline, one row per test with its outcome, failures first and then in the order they ran; picking a row plays that trace without reloading (`↑`/`↓` move between rows, `Enter` opens one). The hosted player does the same for several zips picked with its one Open button, or for a folder dropped on the page (a browser's file dialog picks files or folders, never both).
266
+
267
+
```sh
268
+
pnpm show-trace test-results/ # every zip under the folder
269
+
pnpm show-trace a/trace.zip b/trace.zip # several zips
270
+
```
271
+
272
+
Each zip is read once, as the list fills in, and kept for when it is picked. Anything in the folder that is not a `.zip` (screenshots, videos, the artifacts manifest) is skipped; a zip that cannot be opened stays in the list with the reason, and the rest open normally. A zip records no test state, so the outcome is read from the trace itself: **failed** when an action or step in it failed, **passed** when it holds actions and none failed, **unknown** when it holds none. An assertion library that records no row (a jest `expect`, chai) can fail a test whose trace still reads as passed. One zip opens exactly as before, with no list.
273
+
274
+
**Hosted player: [trace.webdriver.io](https://trace.webdriver.io).** The same player as a web page, for opening a trace without installing anything: pick one or several `.zip` files, or drop them or a folder of them on the page. The archive is parsed in the browser tab and never uploaded, which matters because a trace records everything the run showed or typed. Run controls are absent, as in `show-trace`. A replayed page still loads its own stylesheets and images from the site under test, as it does in `show-trace`; from an `https` page the browser blocks the `http` ones, so a trace of an `http` site can render unstyled there and fully in `show-trace`. To try the hosted build locally:
266
275
267
276
```sh
268
277
pnpm player:hosted # builds it and serves it at http://localhost:4173 under the production headers
@@ -534,6 +543,8 @@ With `mode: 'trace'` no UI opens — the run writes a portable `trace.zip` under
0 commit comments