Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
df2bf12
fix(selenium-devtools): capture a plain script and let it exit
vishnuv688 Oct 12, 2026
4e1378e
refactor(shared): one replaceCommand rule for the app and the backend
vishnuv688 Oct 12, 2026
ec141fd
refactor(shared): move RunCapabilities and RunnerOptions into shared
vishnuv688 Oct 12, 2026
c2c4f83
fix(selenium-devtools-py): carry the browser's error message, not str()
vishnuv688 Oct 12, 2026
6e848a8
test: add a cross-adapter conformance suite
vishnuv688 Oct 12, 2026
b42554f
ci: run the conformance suite with Python and upload its report on fa…
vishnuv688 Oct 12, 2026
c490b5a
docs: describe the conformance suite and add an adapter-author guide
vishnuv688 Oct 12, 2026
bca22d8
test(conformance): compare adapters with each other, not only with th…
vishnuv688 Oct 13, 2026
da05573
test(conformance): show where adapters agree in the report
vishnuv688 Oct 13, 2026
7803f26
docs: describe cross-adapter agreement and the adapter registry
vishnuv688 Oct 13, 2026
5ee1461
test(conformance): judge rows and anchors against the browser's own c…
vishnuv688 Oct 13, 2026
09b9356
test(conformance): keep a hung scenario's frames, and only count a re…
vishnuv688 Oct 13, 2026
bb49e1c
docs(adapters): replaceCommand matches by id first, then by the old t…
vishnuv688 Oct 13, 2026
c190176
test(conformance): compare what a fill typed, not only that it typed
vishnuv688 Oct 13, 2026
46e186c
test(conformance): scope a gap to the step it occurs on, and hold eve…
vishnuv688 Oct 13, 2026
1f74553
test(conformance): keep the recorded run when the checker cannot read it
vishnuv688 Oct 13, 2026
98ea0f4
test(conformance): a navigation row must name the page the browser lo…
vishnuv688 Oct 13, 2026
9485829
test(conformance): refuse a row without the fields the rules read
vishnuv688 Oct 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/selenium-plain-script-capture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@wdio/selenium-devtools': patch
---

A plain `node script.js` run with no test runner is now captured without calling `DevTools.startTest`: its commands land under the "Selenium Session" row the README describes, where before every command was dropped. Such a script also exits once its work is done, where before the open dashboard connection kept the process alive indefinitely, which also left a rerun of a plain script running after it finished.
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,22 @@ jobs:
# because it is fast and its failures are cheaper to read.
- name: 🔎 Typecheck
run: pnpm typecheck
# The conformance suite runs the Python adapter beside the JS ones, so a
# capture fix missing from one language fails this job.
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'
- name: Install the Python adapter
run: pip install -e packages/selenium-devtools-py
- name: 🧪 Run Tests
run: pnpm test
- name: Upload conformance report
if: failure()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: conformance-report
path: packages/conformance/out/
if-no-files-found: ignore

# Separate job because these are the only tests that need a real browser, and
# they parallelise with `build` instead of extending it. No bundle step: the
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ examples/**/trace-*/

# test results
examples/**/test-results*/
packages/conformance/**/test-results*/
packages/conformance/out/

# vitest --coverage output
coverage/
Expand Down
14 changes: 13 additions & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ Contains:
- `pytest_plugin.py` — the suite tree, keyed by pytest nodeid; auto-discovered, opt-in by env var.
- `rerun.py`, `run_id.py`, `performance.py`, `transport.py` — run controls, run identity, navigation timings, and a stdlib-only WebSocket client.

Live mode only: it does not write a trace archive. That work, and the question of whether the ~3,100 lines of trace transforms in `core` should move behind the wire rather than be reimplemented per language, is tracked in [#330](https://github.com/webdriverio/devtools/issues/330) and [#278](https://github.com/webdriverio/devtools/issues/278).
It writes trace archives without running the transforms itself: `trace_export.py` streams the action snapshots and filmstrip frames, then sends a `traceExport` request and the backend builds the archive from the run it accumulated, answering with `traceExported`. `export_trace()` and teardown (`disable()`, the pytest plugin's session finish) trigger it. Writing an adapter in another language is covered in [docs/ADAPTERS.md](./docs/ADAPTERS.md).

Imports from: `selenium` (required, 4.44+). Does not import: `core`, `shared`, any other package.

Expand Down Expand Up @@ -188,6 +188,18 @@ Imports from: `core`. The script bodies, serializers, types, and locator generat

The DOM-walking scripts run in the page via `browser.execute`, so — like `script` — they avoid Node-only APIs.

### `packages/conformance`: cross-adapter conformance suite

Test-only and never published or bundled. Each adapter runs one scenario (open `/login`, type, submit to `/secure`, log out, then a navigation that fails) as its own process, against a fake W3C WebDriver server that models two pages and records what really happened in the browser: which documents were born and when, and which navigations failed. The adapter reports into a recording backend that stands in for the dashboard, reached through the same reuse handshake a rerun uses, so no adapter gains a code path for being tested. `src/checker.ts` then judges the recorded frame stream against behavioural rules, for example "a row replays the page the browser was on when its action completed" and "every document gets exactly one anchor at its birth time". Every adapter is checked by the same rules, so a capture fix that lands in one language and not another fails CI.

Each scenario runs twice, with and without BiDi. The fake answers the BiDi commands the adapters send, and a registered preload puts the collector into every later document from birth, as in Chrome. A difference an adapter is allowed to show lives in `src/allowlist.ts` with a mandatory reason, and an entry that stops matching fails the run, so a closed gap forces its own removal.

Every run, passing or failing, dumps its frames, ground truth, violations and scenario output to `packages/conformance/out/<adapter>-<bidi|no-bidi>.json` and rebuilds `out/index.html`, a self-contained page laying each run out as a timeline of documents, command rows and DOM anchors with every violation beside the event it concerns. CI uploads `out/` as the `conformance-report` artifact when the `build` job fails.

Beside the rules, the adapters are compared with each other: each run is reduced to what a dashboard user sees (steps, outcomes, the page each step replays, snapshots, run controls) and any difference between adapters in the same mode fails unless a declared gap explains it. The rules catch every adapter being wrong in the same way; the comparison catches a difference no rule anticipated. Adapters are registered once in `src/adapters.ts`.

Covers `selenium-devtools` and `selenium-devtools-py`. The WDIO service and Nightwatch have no scenario yet. The fake emits no BiDi events, so console and network capture are not checked.

### `examples/`

Per-adapter demo projects used for manual verification. One directory per adapter, and inside it one directory per test runner, named for the runner itself:
Expand Down
Loading
Loading