@wdio/nightwatch-devtools 1.8.2 → 2.0.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/README.md +70 -16
- package/dist/{bidi-WNZOXX5X.js → bidi-AZX3WRGJ.js} +4 -2
- package/dist/{bidi-WNZOXX5X.js.map → bidi-AZX3WRGJ.js.map} +1 -1
- package/dist/{chunk-DM4FCAIJ.js → chunk-TUK7ZLQI.js} +627 -88
- package/dist/chunk-TUK7ZLQI.js.map +1 -0
- package/dist/index.js +244 -49
- package/dist/index.js.map +1 -1
- package/package.json +8 -5
- package/dist/chunk-DM4FCAIJ.js.map +0 -1
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ npm install @wdio/nightwatch-devtools
|
|
|
16
16
|
npm install @wdio/nightwatch-devtools
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
Requires Nightwatch 3 or later. For Cucumber, `@cucumber/cucumber` must be installed in your project; the plugin uses your copy rather than bundling one.
|
|
20
|
+
|
|
19
21
|
**2. Wire the plugin into your Nightwatch config** via the `globals` field:
|
|
20
22
|
|
|
21
23
|
```javascript
|
|
@@ -132,7 +134,7 @@ globals: nightwatchDevtools({
|
|
|
132
134
|
|
|
133
135
|
## Live Mode
|
|
134
136
|
|
|
135
|
-
In the default `mode: 'live'`, the plugin launches the DevTools dashboard in a new browser window when your tests run, streaming each test's commands, screenshots, console logs, and network activity in real time. See the [dashboard docs](https://webdriver.io/docs/devtools/dashboard) for a walkthrough of the UI.
|
|
137
|
+
In the default `mode: 'live'`, the plugin launches the DevTools dashboard in a new browser window when your tests run, streaming each test's commands, screenshots, console logs, and network activity in real time. The run stays open after your tests finish so you can review the results: close the DevTools window to end it, or press Ctrl+C to exit and leave the window open. See the [dashboard docs](https://webdriver.io/docs/devtools/dashboard) for a walkthrough of the UI.
|
|
136
138
|
|
|
137
139
|
### Preserve & Rerun (Compare)
|
|
138
140
|
|
|
@@ -151,7 +153,7 @@ globals: nightwatchDevtools({
|
|
|
151
153
|
})
|
|
152
154
|
```
|
|
153
155
|
|
|
154
|
-
Nightwatch emits the **same normalized trace** as the WebdriverIO and Selenium adapters (all three share `@wdio/devtools-
|
|
156
|
+
Nightwatch emits the **same normalized trace** as the WebdriverIO and Selenium adapters (all three share `@wdio/devtools-trace`), so the archive format and the `show-trace` player are identical no matter which adapter produced it. A Nightwatch trace carries the full per-action capture — a screenshot, the depth-indented accessibility-tree snapshot, the interactable-element list, and the Markdown transcript — so it opens in the player with DOM/snapshot time-travel, the **A11y** and **Transcript** tabs, an **Errors** tab surfacing expect/step failures with jump-to-source, the pick-locator element overlay, and (for Cucumber) **Feature → Scenario** nesting. Steps are tracked in the live dashboard but not yet nested as their own groups in the trace. Copied locators prefer plain CSS, which Nightwatch reads by default, and fall back to XPath (captioned `useXpath()` / `locateStrategy: 'xpath'`) only when no unique CSS selector exists.
|
|
155
157
|
|
|
156
158
|
Open a trace with the `show-trace` bin, shipped with this package (no extra dependency):
|
|
157
159
|
|
|
@@ -191,15 +193,17 @@ desiredCapabilities: {
|
|
|
191
193
|
}
|
|
192
194
|
```
|
|
193
195
|
|
|
194
|
-
When attached, the per-command Chrome performance-log network capture path is gated off so requests don't appear twice in the dashboard. If `webSocketUrl` is missing or the chromedriver version doesn't expose BiDi, the attach
|
|
196
|
+
When attached, the per-command Chrome performance-log network capture path is gated off so requests don't appear twice in the dashboard. If `webSocketUrl` is missing or the chromedriver version doesn't expose BiDi, the attach logs a warning and the perf-log fallback continues to work. The injected collector lists every request as well, from two sources of the page's own: a `fetch` / `XMLHttpRequest` call goes through its patch and carries method, headers, status and body, and every other load comes from the page's Resource Timing buffer with its timing and size. On Chrome the performance log then upgrades those Resource Timing rows in place with headers and status; on Safari, or any session Appium serves, they stay as the page saw them, without headers or bodies, and on Safari without a status.
|
|
197
|
+
|
|
198
|
+
**Set `webSocketUrl: true` even without `bidi: true`.** With it, the plugin registers its page collector at document start on every page, so DOM time-travel stays accurate across navigations. Without it, the collector is injected after each navigation instead, which can miss the first moments of a new page.
|
|
195
199
|
|
|
196
200
|
---
|
|
197
201
|
|
|
198
202
|
## Screencast
|
|
199
203
|
|
|
200
|
-
Record a continuous `.webm` video of the browser session.
|
|
204
|
+
Record a continuous `.webm` video of the browser session, live mode only (in trace mode use `filmstrip` / `video`). Each WebDriver session gets its own recording: a mid-run `browser.end()`, or the per-scenario browser quit in Cucumber, finalizes the current video and starts a new one. The last recording is finalized in Nightwatch's `after()` hook. Each is written as `nightwatch-video-<sessionId>.webm` to a `test-results/` folder next to the test file that just ran, falling back to the directory containing `nightwatch.conf.*`, then `process.cwd()`. Directories under `node_modules/` are skipped, and an unwritable directory falls back to the OS temp directory.
|
|
201
205
|
|
|
202
|
-
**Polling mode only.** Nightwatch doesn't expose a stable CDP escape hatch the way WebdriverIO (`browser.getPuppeteer()`) and Selenium (`driver.createCDPConnection`) do, so the screencast captures frames by
|
|
206
|
+
**Polling mode only.** Nightwatch doesn't expose a stable CDP escape hatch the way WebdriverIO (`browser.getPuppeteer()`) and Selenium (`driver.createCDPConnection`) do, so the screencast captures frames by requesting a WebDriver screenshot at a fixed interval, straight over the WebDriver HTTP transport so it never waits behind your test's queued commands. This works on every browser Nightwatch supports.
|
|
203
207
|
|
|
204
208
|
### Quick start
|
|
205
209
|
|
|
@@ -217,6 +221,7 @@ globals: nightwatchDevtools({
|
|
|
217
221
|
| `enabled` | `boolean` | `false` | Master switch. |
|
|
218
222
|
| `pollIntervalMs` | `number` | `200` | Screenshot interval (ms). Lower = smoother video, more WebDriver round-trips. 200 ms ≈ 5 fps. |
|
|
219
223
|
| `captureFormat` | `'jpeg' \| 'png'` | `'jpeg'` | Frame format. WebDriver screenshots are always PNG, so this only affects the encoded output. |
|
|
224
|
+
| `maxBufferFrames` | `number` | `2000` | Cap on frames held in memory; past it the buffer is thinned in place, keeping the first and last frames. |
|
|
220
225
|
| `maxWidth` / `maxHeight` / `quality` | — | — | CDP-only options, ignored in polling mode. Listed for shape compatibility with the WDIO/Selenium adapters. |
|
|
221
226
|
|
|
222
227
|
### Prerequisites
|
|
@@ -251,23 +256,72 @@ The encoded video is sent to the DevTools dashboard via the `screencast` WS scop
|
|
|
251
256
|
|
|
252
257
|
---
|
|
253
258
|
|
|
254
|
-
##
|
|
259
|
+
## Mobile (Appium)
|
|
255
260
|
|
|
256
|
-
|
|
261
|
+
Appium sessions are captured in live and trace mode. Declare Appium under `selenium` with `use_appium: true`, `start_process: false` and `default_path_prefix: ''`. For a native app set `browserName: null`; otherwise Nightwatch fills in Firefox and the plugin treats the session as having a web page. Leave `bidi` off, since Appium serves no BiDi.
|
|
257
262
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
263
|
+
```javascript
|
|
264
|
+
// nightwatch.mobile.conf.cjs
|
|
265
|
+
const nightwatchDevtools = require('@wdio/nightwatch-devtools').default
|
|
266
|
+
|
|
267
|
+
module.exports = {
|
|
268
|
+
selenium: {
|
|
269
|
+
start_process: false,
|
|
270
|
+
use_appium: true,
|
|
271
|
+
host: '127.0.0.1',
|
|
272
|
+
port: 4723,
|
|
273
|
+
default_path_prefix: ''
|
|
274
|
+
},
|
|
275
|
+
test_settings: {
|
|
276
|
+
default: {
|
|
277
|
+
desiredCapabilities: {
|
|
278
|
+
browserName: null,
|
|
279
|
+
platformName: 'Android',
|
|
280
|
+
'appium:automationName': 'UiAutomator2'
|
|
281
|
+
},
|
|
282
|
+
globals: nightwatchDevtools({ mode: 'trace', bidi: false })
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
261
287
|
|
|
262
|
-
|
|
288
|
+
Native sessions record commands, screenshots and element data from the platform's XML tree, with no DOM. A hybrid app's webview is captured as if it were still native. From the root of a built checkout of this repo (`pnpm install && pnpm build`), try it with `pnpm demo:nightwatch:mobile`; prerequisites are in [`examples/MOBILE.md`](../../examples/MOBILE.md), and the full reference is the [Mobile Testing page](https://webdriver.io/docs/devtools/mobile).
|
|
263
289
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
290
|
+
### Native app network
|
|
291
|
+
|
|
292
|
+
A native app has no document and Appium serves no BiDi network events, so by default the Network tab of a native session is empty. The plugin can read the app's traffic from the [appium-interceptor](https://github.com/AppiumTestDistribution/appium-interceptor-plugin) plugin instead, which routes the device through a proxy of its own:
|
|
293
|
+
|
|
294
|
+
```sh
|
|
295
|
+
appium plugin install --source=npm appium-interceptor
|
|
296
|
+
appium --use-plugins=appium-interceptor
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Then ask for the proxy in `desiredCapabilities`:
|
|
300
|
+
|
|
301
|
+
```js
|
|
302
|
+
desiredCapabilities: {
|
|
303
|
+
browserName: null,
|
|
304
|
+
platformName: 'Android',
|
|
305
|
+
'appium:automationName': 'UiAutomator2',
|
|
306
|
+
'appium:app': '/path/to/app.apk',
|
|
307
|
+
'appium:intercept': true
|
|
308
|
+
}
|
|
269
309
|
```
|
|
270
310
|
|
|
311
|
+
The plugin starts a listener for each session, including one that replaces it mid-run, and reads what the proxy recorded at most every 2 seconds between commands (each read returns the whole history), and always before each test's trace slice is written, in both live and trace mode. Each request shows its method, URL, status, headers and bodies. The plugin records no timing, so a request is placed at the moment it was first read and shows no duration. Without the plugin a warning is logged and the session runs as usual. This applies to native sessions only; a mobile browser session already captures its network through the page.
|
|
312
|
+
|
|
313
|
+
The plugin supports Android. For HTTPS traffic the app has to trust the certificate the plugin installs on the device, which a release build usually does not (see Android's network security configuration).
|
|
314
|
+
|
|
315
|
+
## Examples
|
|
316
|
+
|
|
317
|
+
Working examples live in the repo's top-level [`examples/nightwatch/`](../../examples/nightwatch). Build the workspace once (`pnpm install && pnpm build`), then run from the repo root:
|
|
318
|
+
|
|
319
|
+
| Example | Runner | Command |
|
|
320
|
+
|-----------|--------|---------|
|
|
321
|
+
| `examples/nightwatch/` | Nightwatch BDD `describe/it` (trace mode by default; `DEVTOOLS_MODE=live` for the UI) | `pnpm demo:nightwatch` (`pnpm demo:nightwatch:retry` adds `--retries 1`) |
|
|
322
|
+
| `examples/nightwatch/cucumber/` | Nightwatch + Cucumber | `pnpm --filter @wdio/nightwatch-devtools example:cucumber` |
|
|
323
|
+
| `examples/nightwatch/nightwatch.mobile.conf.cjs` | Appium (Android Clock app; iOS Settings with `DEVTOOLS_MOBILE_PLATFORM=ios`) | `pnpm demo:nightwatch:mobile` |
|
|
324
|
+
|
|
271
325
|
---
|
|
272
326
|
|
|
273
327
|
## Limitations
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
attachBidiHandlers
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TUK7ZLQI.js";
|
|
4
4
|
|
|
5
5
|
// src/bidi.ts
|
|
6
6
|
import logger from "@wdio/logger";
|
|
@@ -19,10 +19,12 @@ function buildBidiSinks(capturer) {
|
|
|
19
19
|
capturer.sendUpstream("consoleLogs", [entry]);
|
|
20
20
|
},
|
|
21
21
|
pushNetworkRequest: (entry) => {
|
|
22
|
+
capturer.bidiNetworkObserved = true;
|
|
22
23
|
capturer.networkRequests.push(entry);
|
|
23
24
|
capturer.sendUpstream("networkRequests", [entry]);
|
|
24
25
|
},
|
|
25
26
|
replaceNetworkRequest: (id, entry) => {
|
|
27
|
+
capturer.bidiNetworkObserved = true;
|
|
26
28
|
const idx = capturer.networkRequests.findIndex(
|
|
27
29
|
(r) => r.id === id
|
|
28
30
|
);
|
|
@@ -39,4 +41,4 @@ export {
|
|
|
39
41
|
attachBidiHandlers2 as attachBidiHandlers,
|
|
40
42
|
buildBidiSinks
|
|
41
43
|
};
|
|
42
|
-
//# sourceMappingURL=bidi-
|
|
44
|
+
//# sourceMappingURL=bidi-AZX3WRGJ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bidi.ts"],"sourcesContent":["import logger from '@wdio/logger'\nimport {\n type BidiHandlerSinks,\n attachBidiHandlers as attachBidiHandlersCore\n} from '@wdio/devtools-core'\nimport type { SessionCapturer } from './session.js'\n\nconst log = logger('@wdio/nightwatch-devtools:bidi')\n\n/**\n * Nightwatch wrapper around the core BiDi attach helper. Nightwatch ships\n * selenium-webdriver under the hood (via chromedriver), so the same\n * `selenium-webdriver/bidi` inspectors selenium-devtools uses are available\n * whenever the user has set `webSocketUrl: true` in their capabilities.\n *\n * Opt-in via the plugin's `bidi: true` option. When attached, the per-command\n * Chrome performance-log network capture is gated off to avoid duplicate\n * entries in the dashboard.\n */\nexport async function attachBidiHandlers(\n driver: unknown,\n sinks: BidiHandlerSinks\n): Promise<boolean> {\n return attachBidiHandlersCore(driver, sinks, (level, message) =>\n log[level](message)\n )\n}\n\n/**\n * Build sinks that route BiDi events into the SessionCapturer's local arrays\n * and broadcast them upstream. Mirrors selenium-devtools' `buildBidiSinks` —\n * separate per-adapter because the SessionCapturer concrete types differ.\n */\nexport function buildBidiSinks(capturer: SessionCapturer): BidiHandlerSinks {\n return {\n pushConsoleLog: (entry) => {\n capturer.consoleLogs.push(entry)\n capturer.sendUpstream('consoleLogs', [entry])\n },\n pushNetworkRequest: (entry) => {\n capturer.networkRequests.push(entry)\n capturer.sendUpstream('networkRequests', [entry])\n },\n replaceNetworkRequest: (id, entry) => {\n const idx = capturer.networkRequests.findIndex(\n (r: { id?: string }) => r.id === id\n )\n if (idx !== -1) {\n capturer.networkRequests[idx] = entry\n } else {\n capturer.networkRequests.push(entry)\n }\n capturer.sendUpstream('networkRequests', [entry])\n }\n }\n}\n"],"mappings":";;;;;AAAA,OAAO,YAAY;AAOnB,IAAM,MAAM,OAAO,gCAAgC;AAYnD,eAAsBA,oBACpB,QACA,OACkB;AAClB,SAAO;AAAA,IAAuB;AAAA,IAAQ;AAAA,IAAO,CAAC,OAAO,YACnD,IAAI,KAAK,EAAE,OAAO;AAAA,EACpB;AACF;AAOO,SAAS,eAAe,UAA6C;AAC1E,SAAO;AAAA,IACL,gBAAgB,CAAC,UAAU;AACzB,eAAS,YAAY,KAAK,KAAK;AAC/B,eAAS,aAAa,eAAe,CAAC,KAAK,CAAC;AAAA,IAC9C;AAAA,IACA,oBAAoB,CAAC,UAAU;AAC7B,eAAS,gBAAgB,KAAK,KAAK;AACnC,eAAS,aAAa,mBAAmB,CAAC,KAAK,CAAC;AAAA,IAClD;AAAA,IACA,uBAAuB,CAAC,IAAI,UAAU;AACpC,YAAM,MAAM,SAAS,gBAAgB;AAAA,QACnC,CAAC,MAAuB,EAAE,OAAO;AAAA,MACnC;AACA,UAAI,QAAQ,IAAI;AACd,iBAAS,gBAAgB,GAAG,IAAI;AAAA,MAClC,OAAO;AACL,iBAAS,gBAAgB,KAAK,KAAK;AAAA,MACrC;AACA,eAAS,aAAa,mBAAmB,CAAC,KAAK,CAAC;AAAA,IAClD;AAAA,EACF;AACF;","names":["attachBidiHandlers"]}
|
|
1
|
+
{"version":3,"sources":["../src/bidi.ts"],"sourcesContent":["import logger from '@wdio/logger'\nimport {\n type BidiHandlerSinks,\n attachBidiHandlers as attachBidiHandlersCore\n} from '@wdio/devtools-core'\nimport type { SessionCapturer } from './session.js'\n\nconst log = logger('@wdio/nightwatch-devtools:bidi')\n\n/**\n * Nightwatch wrapper around the core BiDi attach helper. Nightwatch ships\n * selenium-webdriver under the hood (via chromedriver), so the same\n * `selenium-webdriver/bidi` inspectors selenium-devtools uses are available\n * whenever the user has set `webSocketUrl: true` in their capabilities.\n *\n * Opt-in via the plugin's `bidi: true` option. When attached, the per-command\n * Chrome performance-log network capture is gated off to avoid duplicate\n * entries in the dashboard.\n */\nexport async function attachBidiHandlers(\n driver: unknown,\n sinks: BidiHandlerSinks\n): Promise<boolean> {\n return attachBidiHandlersCore(driver, sinks, (level, message) =>\n log[level](message)\n )\n}\n\n/**\n * Build sinks that route BiDi events into the SessionCapturer's local arrays\n * and broadcast them upstream. Mirrors selenium-devtools' `buildBidiSinks` —\n * separate per-adapter because the SessionCapturer concrete types differ.\n */\nexport function buildBidiSinks(capturer: SessionCapturer): BidiHandlerSinks {\n return {\n pushConsoleLog: (entry) => {\n capturer.consoleLogs.push(entry)\n capturer.sendUpstream('consoleLogs', [entry])\n },\n pushNetworkRequest: (entry) => {\n capturer.bidiNetworkObserved = true\n capturer.networkRequests.push(entry)\n capturer.sendUpstream('networkRequests', [entry])\n },\n replaceNetworkRequest: (id, entry) => {\n capturer.bidiNetworkObserved = true\n const idx = capturer.networkRequests.findIndex(\n (r: { id?: string }) => r.id === id\n )\n if (idx !== -1) {\n capturer.networkRequests[idx] = entry\n } else {\n capturer.networkRequests.push(entry)\n }\n capturer.sendUpstream('networkRequests', [entry])\n }\n }\n}\n"],"mappings":";;;;;AAAA,OAAO,YAAY;AAOnB,IAAM,MAAM,OAAO,gCAAgC;AAYnD,eAAsBA,oBACpB,QACA,OACkB;AAClB,SAAO;AAAA,IAAuB;AAAA,IAAQ;AAAA,IAAO,CAAC,OAAO,YACnD,IAAI,KAAK,EAAE,OAAO;AAAA,EACpB;AACF;AAOO,SAAS,eAAe,UAA6C;AAC1E,SAAO;AAAA,IACL,gBAAgB,CAAC,UAAU;AACzB,eAAS,YAAY,KAAK,KAAK;AAC/B,eAAS,aAAa,eAAe,CAAC,KAAK,CAAC;AAAA,IAC9C;AAAA,IACA,oBAAoB,CAAC,UAAU;AAC7B,eAAS,sBAAsB;AAC/B,eAAS,gBAAgB,KAAK,KAAK;AACnC,eAAS,aAAa,mBAAmB,CAAC,KAAK,CAAC;AAAA,IAClD;AAAA,IACA,uBAAuB,CAAC,IAAI,UAAU;AACpC,eAAS,sBAAsB;AAC/B,YAAM,MAAM,SAAS,gBAAgB;AAAA,QACnC,CAAC,MAAuB,EAAE,OAAO;AAAA,MACnC;AACA,UAAI,QAAQ,IAAI;AACd,iBAAS,gBAAgB,GAAG,IAAI;AAAA,MAClC,OAAO;AACL,iBAAS,gBAAgB,KAAK,KAAK;AAAA,MACrC;AACA,eAAS,aAAa,mBAAmB,CAAC,KAAK,CAAC;AAAA,IAClD;AAAA,EACF;AACF;","names":["attachBidiHandlers"]}
|