Cross-Framework Support
The trace format and the show-trace player are identical across WebdriverIO / Selenium / Nightwatch; this page shows where capture completeness differs. For the full trace-mode reference, see Trace Mode.
The transforms that build a trace live in @wdio/devtools-trace, one layer below the adapters, so the trace format and the show-trace player are identical for every adapter: the same .zip (or directory) opens in the same player regardless of which produced it. The JavaScript adapters additionally share the core options (mode, traceGranularity, tracePolicy, traceFormat, filmstrip, emitArtifactsManifest, captureAssertions).
Capture completeness varies by adapter, though. WebdriverIO is the most complete; Selenium, Nightwatch and Python cover the core flow with the gaps noted below. Framework-specific enable syntax lives on each adapter page; see Selenium and Nightwatch.
The Python adapter (see the Python tabs on the Selenium page) writes the same archive and opens in the same player, and has its own column in the table below. It runs no JavaScript in the test process, so the backend builds its trace from the captured stream instead of the adapter building it in-process. Granularity and retention are set with --devtools-trace-granularity session|test and --devtools-trace-policy, the latter with its retry-aware values degrading to retain-on-failure because nothing on that wire carries an attempt number.
| Feature | WebdriverIO | Selenium | Nightwatch | Python |
|---|---|---|---|---|
Trace mode + show-trace player | ✅ | ✅ | ✅ | ✅ |
| DOM time-travel (mutation capture) | ✅ | ⚠️ with BiDi ¹ | ⚠️ with BiDi ¹ | ✅ |
| Network requests (browser sessions) | ✅ | ⚠️ with BiDi ² | ⚠️ with BiDi ³ | ✅ |
Screencast (filmstrip / video) | ✅ CDP push (Chrome), polling elsewhere | ✅ CDP push (Chromium), polling elsewhere | ⚠️ polling only ⁴ | ✅ CDP push (Chromium), one frame per command elsewhere |
Per-test granularity (traceGranularity: 'test') | ✅ | ✅ | ⚠️ ⁵ | ✅ |
Retry-aware retention (tracePolicy) | ✅ | ✅ | ⚠️ retain-on-failure only ⁶ | ⚠️ retain-on-failure only ⁷ |
Per-test screenshot / video, attached to Allure | ✅ | ✅ | ⚠️ produce-only ⁸ | ❌ ⁹ |
| Cucumber Feature→Scenario→Step nesting | ⚠️ Scenario→Step ¹⁰ | ✅ | ⚠️ Feature→Scenario ¹¹ | ❌ ¹² |
Assertion capture (captureAssertions) | ✅ | ⚠️ node:assert only ¹³ | ⚠️ no expect ¹⁴ | ✅ |
| BiDi console / network capture | ✅ auto | ✅ auto | ⚠️ opt-in ¹⁵ | ✅ auto |
| A11y tab + pick-locator overlay (trace player) | ✅ | ✅ | ✅ | ✅ |
| Transcript + Copy-for-LLM (trace player) | ✅ | ✅ | ✅ | ✅ |
| One row per command in the Actions list | ✅ | ✅ | ✅ | ✅ |
| Waits show as one row with what they issued nested under it | ✅ | ✅ | ⚠️ no element-wait polls ¹⁶ | ✅ |
| Screenshot on every command row | ✅ | ✅ | ✅ | ✅ |
| Browser console logs | ✅ | ✅ | ✅ | ✅ |
| Source tab opens the test line that ran the command | ✅ | ✅ | ✅ | ✅ |
| Metadata tab (session, capabilities, device) | ✅ | ✅ | ✅ | ✅ |
| Performance timings on navigation rows | ✅ | ✅ | ✅ | ✅ |
| Failed command in the Errors tab, with the browser's message | ✅ | ✅ | ✅ | ✅ |
| Run, Rerun and Run all from the dashboard | ⚠️ no Cucumber step rerun ¹⁷ | ⚠️ no Cucumber step rerun ¹⁷ | ⚠️ no Cucumber step rerun ¹⁷ | ✅ |
| Preserve & Rerun (compare a failed run with its rerun) | ✅ | ✅ | ✅ | ✅ |
| Dashboard window opens by itself in live mode, and can be turned off | ⚠️ always opens ¹⁸ | ✅ openUi: false | ⚠️ always opens ¹⁹ | ✅ DEVTOOLS_OPEN=0 |
Turn off per-command screenshots (captureScreenshots) | ❌ ²⁰ | ✅ | ❌ ²¹ | ❌ ²¹ |
Force the test browser headless (headless) | ❌ ²² | ⚠️ Chrome only ²³ | ❌ ²² | ❌ ²² |
| Safari kept frontmost so input lands (live mode) | ⚠️ once ²⁴ | ✅ before each element input | ⚠️ once ²⁴ | ⚠️ once ²⁴ |
Unpacked trace output (traceFormat: 'ndjson-directory') | ✅ | ✅ | ✅ | ❌ zip only ²⁵ |
Artifacts manifest for CI and reporters (emitArtifactsManifest) | ✅ | ✅ | ⚠️ opt-in ²⁶ | ❌ ²⁷ |
| Network without BiDi (Safari, Appium mobile browsers) | ⚠️ ²⁸ | ⚠️ ²⁸ | ⚠️ ²⁸ | ⚠️ ²⁸ |
✅ supported. ⚠️ partial, with the limit in the note below. ❌ not supported. Each supported cell is backed by the cross-adapter conformance suite, a named test or a manual check, listed in the feature list.
¹ Without BiDi (Safari, Appium) the page collector is injected after each navigation, so a page the test leaves within tens of milliseconds is never captured.
² Without BiDi a page the test leaves within tens of milliseconds is never drained, so its requests are not listed.
³ Without BiDi (bidi: true) or Chrome's performance log (goog:loggingPrefs), a page the test leaves within tens of milliseconds is never drained, so its requests are not listed.
⁴ Nightwatch exposes no stable CDP handle, so frames come from a takeScreenshot poll every 200 ms.
⁵ Nightwatch fires the global beforeEach / afterEach once per test module for describe/it and exports-object tests, so they collapse to one slice keyed to the first test; Cucumber scenarios get real per-test slices.
⁶ For describe/it and exports-object tests, --retries reruns a testcase internally without firing the per-test hooks again, so the other policies behave like retain-on-failure; Cucumber scenarios record every attempt.
⁷ Nothing the Python adapter sends carries an attempt number, so the retry-aware policies behave like retain-on-failure.
⁸ Nightwatch has no live Allure attach API, so per-test screenshots and videos are written to disk and listed in the manifest but not attached.
⁹ The Python adapter has no screenshot / video options and no Allure attachment yet.
¹⁰ The service records no feature ancestry for a scenario, so the trace nests Scenario→Step.
¹¹ Nightwatch steps are not stamped as nested groups, so the trace nests Feature→Scenario.
¹² The Python adapter stamps no Feature or Step groups, so a pytest-bdd scenario is one flat test group with no Feature parent and no Step children.
¹³ node:assert rows pass and fail; jest-style expect() and chai produce no rows at all, and a failing matcher only marks its test failed.
¹⁴ assert.*, verify.* and node:assert rows pass and fail; Nightwatch's expect API produces no rows.
¹⁵ Nightwatch turns it on with bidi: true plus webSocketUrl: true in the capabilities.
¹⁶ A waitUntil row holds the commands its condition issued; a waitForElement* row has nothing under it, because Nightwatch polls for the element through its own transport rather than browser.
¹⁷ Under Cucumber a Gherkin step has no CLI filter of its own, so the dashboard reruns scenarios and features, not single steps.
¹⁸ The service always opens the dashboard in live mode; devtoolsCapabilities picks its browser but cannot skip it.
¹⁹ Nightwatch always opens the dashboard in live mode.
²⁰ No option: every command row takes a screenshot, except on Appium, where only native sessions in live mode do.
²¹ No option: every command row takes a screenshot.
²² No option: set headless in the browser capabilities, as for any run.
²³ The option adds --headless=old to goog:chromeOptions only, so other browsers stay headed; set their own headless capability.
²⁴ Brings Safari to the front once after the session starts (live mode, local macOS), so a click issued after another window took the front can still land nowhere.
²⁵ The Python adapter has no option for it and sends no format in its export request, so the backend writes a zip.
²⁶ Nightwatch has no live Allure signal to turn the manifest on by itself, so it stays opt-in.
²⁷ The Python adapter writes no artifacts manifest.
²⁸ Fetch and XHR calls carry headers and bodies; every other load comes from the page's Resource Timing buffer, with timing and size but no headers or body, and no status on Safari.