@wdio/nightwatch-devtools 1.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 ADDED
@@ -0,0 +1,127 @@
1
+ # @wdio/nightwatch-devtools
2
+
3
+ > Nightwatch adapter for [WebdriverIO DevTools](../../README.md) - brings the same visual debugging UI to your Nightwatch test suite with zero test code changes.
4
+
5
+ > **Note:** `@wdio/nightwatch-devtools` is included as a dependency of `@wdio/devtools-service`. Install the service package and import from `@wdio/nightwatch-devtools` directly.
6
+
7
+ ---
8
+
9
+ ## Setup
10
+
11
+ ### Standard Nightwatch (mocha-style)
12
+
13
+ ```javascript
14
+ // nightwatch.conf.cjs
15
+ const nightwatchDevtools = require('@wdio/nightwatch-devtools').default
16
+
17
+ module.exports = {
18
+ src_folders: ['tests'],
19
+
20
+ test_settings: {
21
+ default: {
22
+ desiredCapabilities: {
23
+ browserName: 'chrome',
24
+ // Required for network request capture
25
+ 'goog:loggingPrefs': { performance: 'ALL' }
26
+ },
27
+ globals: nightwatchDevtools({ port: 3000 })
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ Run your tests as normal — the DevTools UI opens automatically in a new browser window:
34
+
35
+ ```bash
36
+ nightwatch
37
+ ```
38
+
39
+ > No changes to your test files are needed.
40
+
41
+ ---
42
+
43
+ ### Cucumber / BDD
44
+
45
+ Import `cucumberHooksPath` alongside the main export and pass it to the Cucumber `require` option. This registers `Before` / `After` scenario hooks that mirror the WebdriverIO service's `beforeScenario` / `afterScenario` behaviour.
46
+
47
+ ```javascript
48
+ // nightwatch.conf.cjs
49
+ const nightwatchDevtools = require('@wdio/nightwatch-devtools').default
50
+ const { cucumberHooksPath } = require('@wdio/nightwatch-devtools')
51
+
52
+ module.exports = {
53
+ src_folders: ['features/step_definitions'],
54
+
55
+ test_runner: {
56
+ type: 'cucumber',
57
+ options: {
58
+ feature_path: 'features',
59
+ require: [cucumberHooksPath] // <-- register DevTools Cucumber hooks
60
+ }
61
+ },
62
+
63
+ test_settings: {
64
+ default: {
65
+ desiredCapabilities: {
66
+ browserName: 'chrome',
67
+ 'goog:loggingPrefs': { performance: 'ALL' }
68
+ },
69
+ globals: nightwatchDevtools({ port: 3000 })
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Configuration Options
78
+
79
+ | Option | Type | Default | Description |
80
+ |--------|------|---------|-------------|
81
+ | `port` | `number` | `3000` | Port for the DevTools backend server. Auto-incremented if already in use. |
82
+ | `hostname` | `string` | `'localhost'` | Hostname the backend server binds to. |
83
+
84
+ ```javascript
85
+ globals: nightwatchDevtools({
86
+ port: 3000,
87
+ hostname: 'localhost'
88
+ })
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Examples
94
+
95
+ Working examples are included in this package:
96
+
97
+ | Directory | Runner | Command |
98
+ |-----------|--------|---------|
99
+ | [`example/`](./example) | Nightwatch mocha-style | `pnpm example` |
100
+
101
+ Build the package first:
102
+
103
+ ```bash
104
+ # From repo root
105
+ pnpm build --filter @wdio/nightwatch-devtools
106
+ cd packages/nightwatch-devtools
107
+ pnpm example
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Limitations
113
+
114
+ Nightwatch does not provide the same depth of framework hooks as WebdriverIO, so there are a few differences from the WDIO DevTools service:
115
+
116
+ | Limitation | Detail |
117
+ |-----------|--------|
118
+ | No native command hooks | Nightwatch has no `beforeCommand` / `afterCommand` hook. Commands are intercepted via a browser proxy wrapper instead. |
119
+ | Limited test context | `browser.currentTest` provides less metadata than the WDIO runner context; test names and file paths require additional heuristics. |
120
+ | Flat suite nesting | Nightwatch does not natively support multiply-nested `describe` blocks; the plugin reports a maximum of two levels. |
121
+ | Delayed result availability | Test results are only finalised in `afterEach`, not available mid-test. |
122
+
123
+ Overall feature parity with the WebdriverIO DevTools service is approximately **80–90%**.
124
+
125
+ ## :page_facing_up: License
126
+
127
+ [MIT](/LICENSE)
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Internal Nightwatch commands to exclude from capture
3
+ */
4
+ export declare const INTERNAL_COMMANDS_TO_IGNORE: readonly ["isAppiumClient", "isSafari", "isChrome", "isFirefox", "isEdge", "isMobile", "isAndroid", "isIOS", "session", "sessions", "timeouts", "timeoutsAsyncScript", "timeoutsImplicitWait", "getLog", "getLogTypes", "screenshot", "availableContexts", "currentContext", "setChromeOptions", "setDeviceName", "perform", "execute", "executeAsync", "executeScript", "sessionLog", "sessionLogTypes", "isLogAvailable", "end"];
5
+ export declare const CONSOLE_METHODS: readonly ["log", "info", "warn", "error"];
6
+ export declare const LOG_LEVEL_PATTERNS: ReadonlyArray<{
7
+ level: 'trace' | 'debug' | 'info' | 'warn' | 'error';
8
+ pattern: RegExp;
9
+ }>;
10
+ export declare const LOG_SOURCES: {
11
+ readonly BROWSER: "browser";
12
+ readonly TEST: "test";
13
+ readonly TERMINAL: "terminal";
14
+ };
15
+ export declare const ANSI_REGEX: RegExp;
16
+ export declare const DEFAULTS: {
17
+ readonly CID: "0-0";
18
+ readonly TEST_NAME: "unknown";
19
+ readonly FILE_NAME: "unknown";
20
+ readonly RETRIES: 0;
21
+ readonly DURATION: 0;
22
+ };
23
+ /** Timing constants (in milliseconds) */
24
+ export declare const TIMING: {
25
+ readonly UI_RENDER_DELAY: 150;
26
+ readonly TEST_START_DELAY: 100;
27
+ readonly SUITE_COMPLETE_DELAY: 200;
28
+ readonly UI_CONNECTION_WAIT: 10000;
29
+ readonly BROWSER_CLOSE_WAIT: 2000;
30
+ readonly INITIAL_CONNECTION_WAIT: 500;
31
+ readonly BROWSER_POLL_INTERVAL: 1000;
32
+ };
33
+ export declare const TEST_STATE: {
34
+ readonly PENDING: "pending";
35
+ readonly RUNNING: "running";
36
+ readonly PASSED: "passed";
37
+ readonly FAILED: "failed";
38
+ readonly SKIPPED: "skipped";
39
+ };
40
+ /**
41
+ * Generic pattern matching Nightwatch commands whose result is a boolean.
42
+ */
43
+ export declare const BOOLEAN_COMMAND_PATTERN: RegExp;
44
+ export declare const NAVIGATION_COMMANDS: readonly ["url", "navigate", "navigateTo"];
45
+ /** Spinner progress frames — suppress from UI Console output. */
46
+ export declare const SPINNER_RE: RegExp;
47
+ /** Matches a path segment that indicates a test/spec directory (e.g. /tests/, /spec/, /nightwatch/examples/, /features/). */
48
+ export declare const TEST_PATH_PATTERN: RegExp;
49
+ /** Matches file names that follow the *.test.ts / *.spec.js naming convention. */
50
+ export declare const TEST_FILE_PATTERN: RegExp;
51
+ /** Nightwatch config file names to search for, in priority order. */
52
+ export declare const CONFIG_FILENAMES: readonly ["nightwatch.conf.cjs", "nightwatch.conf.js", "nightwatch.conf.ts", "nightwatch.conf.mjs", "nightwatch.json"];
53
+ /**
54
+ * Global key used to share the plugin instance with Cucumber hooks.
55
+ * Must match across index.ts and cucumberHooks.cts.
56
+ */
57
+ export declare const PLUGIN_GLOBAL_KEY = "__nightwatchDevtoolsPlugin";
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Internal Nightwatch commands to exclude from capture
3
+ */
4
+ export const INTERNAL_COMMANDS_TO_IGNORE = [
5
+ 'isAppiumClient',
6
+ 'isSafari',
7
+ 'isChrome',
8
+ 'isFirefox',
9
+ 'isEdge',
10
+ 'isMobile',
11
+ 'isAndroid',
12
+ 'isIOS',
13
+ 'session',
14
+ 'sessions',
15
+ 'timeouts',
16
+ 'timeoutsAsyncScript',
17
+ 'timeoutsImplicitWait',
18
+ 'getLog',
19
+ 'getLogTypes',
20
+ 'screenshot',
21
+ 'availableContexts',
22
+ 'currentContext',
23
+ 'setChromeOptions',
24
+ 'setDeviceName',
25
+ 'perform',
26
+ 'execute',
27
+ 'executeAsync',
28
+ 'executeScript',
29
+ // Internal Nightwatch transport commands (used for log capture, not user actions)
30
+ 'sessionLog',
31
+ 'sessionLogTypes',
32
+ 'isLogAvailable',
33
+ 'end'
34
+ ];
35
+ export const CONSOLE_METHODS = ['log', 'info', 'warn', 'error'];
36
+ export const LOG_LEVEL_PATTERNS = [
37
+ { level: 'trace', pattern: /\btrace\b/i },
38
+ { level: 'debug', pattern: /\bdebug\b/i },
39
+ { level: 'info', pattern: /\binfo\b/i },
40
+ { level: 'warn', pattern: /\bwarn(ing)?\b/i },
41
+ { level: 'error', pattern: /\berror\b/i }
42
+ ];
43
+ export const LOG_SOURCES = {
44
+ BROWSER: 'browser',
45
+ TEST: 'test',
46
+ TERMINAL: 'terminal'
47
+ };
48
+ export const ANSI_REGEX = /\x1b\[[?]?[0-9;]*[A-Za-z]/g;
49
+ export const DEFAULTS = {
50
+ CID: '0-0',
51
+ TEST_NAME: 'unknown',
52
+ FILE_NAME: 'unknown',
53
+ RETRIES: 0,
54
+ DURATION: 0
55
+ };
56
+ /** Timing constants (in milliseconds) */
57
+ export const TIMING = {
58
+ UI_RENDER_DELAY: 150,
59
+ TEST_START_DELAY: 100,
60
+ SUITE_COMPLETE_DELAY: 200,
61
+ UI_CONNECTION_WAIT: 10000,
62
+ BROWSER_CLOSE_WAIT: 2000,
63
+ INITIAL_CONNECTION_WAIT: 500,
64
+ BROWSER_POLL_INTERVAL: 1000
65
+ };
66
+ export const TEST_STATE = {
67
+ PENDING: 'pending',
68
+ RUNNING: 'running',
69
+ PASSED: 'passed',
70
+ FAILED: 'failed',
71
+ SKIPPED: 'skipped'
72
+ };
73
+ /**
74
+ * Generic pattern matching Nightwatch commands whose result is a boolean.
75
+ */
76
+ export const BOOLEAN_COMMAND_PATTERN = /^waitFor|^is[A-Z]|^has[A-Z]|(Visible|Present|Enabled|Selected|NotVisible|NotPresent)$/;
77
+ export const NAVIGATION_COMMANDS = ['url', 'navigate', 'navigateTo'];
78
+ /** Spinner progress frames — suppress from UI Console output. */
79
+ export const SPINNER_RE = /^[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏]/u;
80
+ /** Matches a path segment that indicates a test/spec directory (e.g. /tests/, /spec/, /nightwatch/examples/, /features/). */
81
+ export const TEST_PATH_PATTERN = /\/(test|spec|tests|nightwatch|examples?|features|step-definitions)\//i;
82
+ /** Matches file names that follow the *.test.ts / *.spec.js naming convention. */
83
+ export const TEST_FILE_PATTERN = /\.(?:test|spec)\.[cm]?[jt]sx?$/i;
84
+ /** Nightwatch config file names to search for, in priority order. */
85
+ export const CONFIG_FILENAMES = [
86
+ 'nightwatch.conf.cjs',
87
+ 'nightwatch.conf.js',
88
+ 'nightwatch.conf.ts',
89
+ 'nightwatch.conf.mjs',
90
+ 'nightwatch.json'
91
+ ];
92
+ /**
93
+ * Global key used to share the plugin instance with Cucumber hooks.
94
+ * Must match across index.ts and cucumberHooks.cts.
95
+ */
96
+ export const PLUGIN_GLOBAL_KEY = '__nightwatchDevtoolsPlugin';
97
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,gBAAgB;IAChB,UAAU;IACV,UAAU;IACV,WAAW;IACX,QAAQ;IACR,UAAU;IACV,WAAW;IACX,OAAO;IACP,SAAS;IACT,UAAU;IACV,UAAU;IACV,qBAAqB;IACrB,sBAAsB;IACtB,QAAQ;IACR,aAAa;IACb,YAAY;IACZ,mBAAmB;IACnB,gBAAgB;IAChB,kBAAkB;IAClB,eAAe;IACf,SAAS;IACT,SAAS;IACT,cAAc;IACd,eAAe;IACf,kFAAkF;IAClF,YAAY;IACZ,iBAAiB;IACjB,gBAAgB;IAChB,KAAK;CACG,CAAA;AAEV,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAU,CAAA;AAExE,MAAM,CAAC,MAAM,kBAAkB,GAG1B;IACH,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE;IACzC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE;IACzC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE;IACvC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE;IAC7C,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE;CACjC,CAAA;AAEV,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;CACZ,CAAA;AAEV,MAAM,CAAC,MAAM,UAAU,GAAG,4BAA4B,CAAA;AAEtD,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,GAAG,EAAE,KAAK;IACV,SAAS,EAAE,SAAS;IACpB,SAAS,EAAE,SAAS;IACpB,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE,CAAC;CACH,CAAA;AAEV,yCAAyC;AACzC,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,eAAe,EAAE,GAAG;IACpB,gBAAgB,EAAE,GAAG;IACrB,oBAAoB,EAAE,GAAG;IACzB,kBAAkB,EAAE,KAAK;IACzB,kBAAkB,EAAE,IAAI;IACxB,uBAAuB,EAAE,GAAG;IAC5B,qBAAqB,EAAE,IAAI;CACnB,CAAA;AAEV,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;CACV,CAAA;AAEV;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAClC,uFAAuF,CAAA;AAEzF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,YAAY,CAAU,CAAA;AAE7E,iEAAiE;AACjE,MAAM,CAAC,MAAM,UAAU,GAAG,gBAAgB,CAAA;AAE1C,6HAA6H;AAC7H,MAAM,CAAC,MAAM,iBAAiB,GAC5B,uEAAuE,CAAA;AAEzE,kFAAkF;AAClF,MAAM,CAAC,MAAM,iBAAiB,GAAG,iCAAiC,CAAA;AAElE,qEAAqE;AACrE,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,qBAAqB;IACrB,oBAAoB;IACpB,oBAAoB;IACpB,qBAAqB;IACrB,iBAAiB;CACT,CAAA;AAEV;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,4BAA4B,CAAA"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Browser Proxy
3
+ * Handles browser command interception and tracking
4
+ */
5
+ import type { SessionCapturer } from '../session.js';
6
+ import type { TestManager } from './testManager.js';
7
+ import type { NightwatchBrowser } from '../types.js';
8
+ export declare class BrowserProxy {
9
+ private sessionCapturer;
10
+ private testManager;
11
+ private getCurrentTest;
12
+ /** Tracks which browser *instances* have already been proxied to avoid double-wrapping. */
13
+ private proxiedBrowsers;
14
+ private commandStack;
15
+ private lastCommandSig;
16
+ private currentTestFullPath;
17
+ /**
18
+ * Tracks the last captured command so that consecutive retries of the same
19
+ * command (e.g. getText inside a waitFor loop) overwrite the previous entry
20
+ * rather than appending, showing only the final execution result.
21
+ */
22
+ private lastCapturedSig;
23
+ private lastCapturedId;
24
+ constructor(sessionCapturer: SessionCapturer, testManager: TestManager, getCurrentTest: () => any);
25
+ /**
26
+ * Update the session capturer reference after a WebDriver session change.
27
+ * Does NOT re-wrap browser methods — wrapping is permanent per browser object.
28
+ */
29
+ updateSessionCapturer(capturer: SessionCapturer): void;
30
+ resetCommandTracking(): void;
31
+ getCurrentTestFullPath(): string | null;
32
+ setCurrentTestFullPath(path: string | null): void;
33
+ /**
34
+ * Wrap browser navigation methods (url / navigate / navigateTo) to inject
35
+ * the DevTools script after every navigation.
36
+ *
37
+ * Uses `browser` from the closure (not `this` inside perform) so it works
38
+ * for both standard Nightwatch (chainable API) and Cucumber async/await mode
39
+ * where `this` inside a perform callback is not the browser.
40
+ */
41
+ wrapUrlMethod(browser: NightwatchBrowser): void;
42
+ wrapBrowserCommands(browser: NightwatchBrowser): void;
43
+ private handleCommandExecution;
44
+ private captureCommandError;
45
+ isProxied(browser: NightwatchBrowser): boolean;
46
+ }
@@ -0,0 +1,314 @@
1
+ /**
2
+ * Browser Proxy
3
+ * Handles browser command interception and tracking
4
+ */
5
+ import logger from '@wdio/logger';
6
+ import { INTERNAL_COMMANDS_TO_IGNORE, BOOLEAN_COMMAND_PATTERN, NAVIGATION_COMMANDS } from '../constants.js';
7
+ import { getCallSourceFromStack } from './utils.js';
8
+ const log = logger('@wdio/nightwatch-devtools:browserProxy');
9
+ export class BrowserProxy {
10
+ sessionCapturer;
11
+ testManager;
12
+ getCurrentTest;
13
+ /** Tracks which browser *instances* have already been proxied to avoid double-wrapping. */
14
+ proxiedBrowsers = new WeakSet();
15
+ commandStack = [];
16
+ lastCommandSig = null;
17
+ currentTestFullPath = null;
18
+ /**
19
+ * Tracks the last captured command so that consecutive retries of the same
20
+ * command (e.g. getText inside a waitFor loop) overwrite the previous entry
21
+ * rather than appending, showing only the final execution result.
22
+ */
23
+ lastCapturedSig = null;
24
+ lastCapturedId = null;
25
+ constructor(sessionCapturer, testManager, getCurrentTest) {
26
+ this.sessionCapturer = sessionCapturer;
27
+ this.testManager = testManager;
28
+ this.getCurrentTest = getCurrentTest;
29
+ }
30
+ /**
31
+ * Update the session capturer reference after a WebDriver session change.
32
+ * Does NOT re-wrap browser methods — wrapping is permanent per browser object.
33
+ */
34
+ updateSessionCapturer(capturer) {
35
+ this.sessionCapturer = capturer;
36
+ }
37
+ resetCommandTracking() {
38
+ this.commandStack = [];
39
+ this.lastCommandSig = null;
40
+ this.lastCapturedSig = null;
41
+ this.lastCapturedId = null;
42
+ }
43
+ getCurrentTestFullPath() {
44
+ return this.currentTestFullPath;
45
+ }
46
+ setCurrentTestFullPath(path) {
47
+ this.currentTestFullPath = path;
48
+ }
49
+ /**
50
+ * Wrap browser navigation methods (url / navigate / navigateTo) to inject
51
+ * the DevTools script after every navigation.
52
+ *
53
+ * Uses `browser` from the closure (not `this` inside perform) so it works
54
+ * for both standard Nightwatch (chainable API) and Cucumber async/await mode
55
+ * where `this` inside a perform callback is not the browser.
56
+ */
57
+ wrapUrlMethod(browser) {
58
+ const sessionCapturer = this.sessionCapturer;
59
+ const wrapNav = (methodName) => {
60
+ if (typeof browser[methodName] !== 'function') {
61
+ return;
62
+ }
63
+ const original = browser[methodName].bind(browser);
64
+ browser[methodName] = function (...args) {
65
+ const result = original(...args);
66
+ const injectAndCapture = () => {
67
+ log.info(`[nav] ${methodName}(${args[0] ?? ''}) — injecting script`);
68
+ return sessionCapturer
69
+ .injectScript(browser)
70
+ .then(() => sessionCapturer.captureTrace(browser))
71
+ .catch((err) => log.error(`Failed to inject script: ${err.message}`));
72
+ };
73
+ if (result && typeof result.perform === 'function') {
74
+ // Standard Nightwatch (chained API): queue inside perform so it
75
+ // runs after navigation completes. Always pass `done` so the
76
+ // command queue is unblocked even if injection fails.
77
+ result.perform((done) => {
78
+ injectAndCapture().finally(() => done && done());
79
+ });
80
+ return result;
81
+ }
82
+ // Cucumber async/await: result is a Promise (or thenable).
83
+ // Return the AUGMENTED promise so that `await browser.url(...)` in
84
+ // the step definition waits for injectAndCapture to finish before
85
+ // Cucumber moves to the next step. Without this the injection races
86
+ // with the next step's commands (e.g. setValue), causing stale-element
87
+ // errors because the script-tag insertion mutates the DOM mid-form.
88
+ return Promise.resolve(result)
89
+ .then(injectAndCapture)
90
+ .catch(() => { });
91
+ };
92
+ };
93
+ wrapNav('url');
94
+ wrapNav('navigate');
95
+ wrapNav('navigateTo');
96
+ log.info('✓ Script injection wrapped');
97
+ }
98
+ wrapBrowserCommands(browser) {
99
+ if (this.proxiedBrowsers.has(browser)) {
100
+ return;
101
+ }
102
+ const browserAny = browser;
103
+ const allMethods = new Set([
104
+ ...Object.keys(browser),
105
+ ...Object.getOwnPropertyNames(Object.getPrototypeOf(browser))
106
+ ]);
107
+ const wrappedMethods = [];
108
+ allMethods.forEach((methodName) => {
109
+ if (methodName === 'constructor' ||
110
+ typeof browserAny[methodName] !== 'function') {
111
+ return;
112
+ }
113
+ if (INTERNAL_COMMANDS_TO_IGNORE.includes(methodName) ||
114
+ methodName.startsWith('__')) {
115
+ return;
116
+ }
117
+ const originalMethod = browserAny[methodName].bind(browser);
118
+ browserAny[methodName] = (...args) => {
119
+ return this.handleCommandExecution(browser, browserAny, methodName, originalMethod, args);
120
+ };
121
+ wrappedMethods.push(methodName);
122
+ });
123
+ this.proxiedBrowsers.add(browser);
124
+ log.info(`✓ Wrapped ${wrappedMethods.length} browser methods`);
125
+ }
126
+ handleCommandExecution(browser, browserAny, methodName, originalMethod, args) {
127
+ const currentNightwatchTest = browserAny.currentTest;
128
+ const currentTestName = this.testManager.detectTestBoundary(currentNightwatchTest);
129
+ this.testManager.startTestIfPending(currentTestName);
130
+ const callInfo = getCallSourceFromStack();
131
+ if (callInfo.filePath && !this.currentTestFullPath) {
132
+ this.currentTestFullPath = callInfo.filePath;
133
+ }
134
+ const lastArg = args[args.length - 1];
135
+ const hasUserCallback = typeof lastArg === 'function';
136
+ const userCallback = hasUserCallback ? lastArg : null;
137
+ const logArgs = hasUserCallback ? args.slice(0, -1) : args;
138
+ // Check for duplicate commands (based on method + logical args)
139
+ const cmdSig = JSON.stringify({
140
+ command: methodName,
141
+ args: logArgs,
142
+ src: callInfo.callSource
143
+ });
144
+ const isDuplicate = this.lastCommandSig === cmdSig;
145
+ if (!isDuplicate) {
146
+ this.commandStack.push({
147
+ command: methodName,
148
+ callSource: callInfo.callSource,
149
+ signature: cmdSig
150
+ });
151
+ this.lastCommandSig = cmdSig;
152
+ }
153
+ const testAtCallTime = this.getCurrentTest();
154
+ const testUid = testAtCallTime?.uid;
155
+ const callSource = callInfo.callSource;
156
+ const commandTimestamp = Date.now();
157
+ /**
158
+ * Result-capturing callback — called by Nightwatch's async queue when the
159
+ * command completes. This is where we get the *actual* result value.
160
+ */
161
+ const captureCallback = (callbackResult) => {
162
+ const stackFrame = this.commandStack[this.commandStack.length - 1];
163
+ if (stackFrame?.command === methodName &&
164
+ stackFrame.signature === cmdSig) {
165
+ this.commandStack.pop();
166
+ }
167
+ const isBooleanCommand = BOOLEAN_COMMAND_PATTERN.test(methodName);
168
+ let serializedResult = undefined;
169
+ if (callbackResult !== null && callbackResult !== undefined) {
170
+ if (typeof callbackResult === 'object' && 'passed' in callbackResult) {
171
+ // Nightwatch assertion object {passed, actual, expected, message}
172
+ serializedResult = callbackResult.passed
173
+ ? true
174
+ : {
175
+ passed: false,
176
+ actual: callbackResult.actual,
177
+ expected: callbackResult.expected,
178
+ message: callbackResult.message
179
+ };
180
+ }
181
+ else if (typeof callbackResult === 'object' &&
182
+ 'value' in callbackResult) {
183
+ const raw = callbackResult.value;
184
+ // Boolean-semantic command returning null → timed out / not found → false
185
+ serializedResult = raw === null && isBooleanCommand ? false : raw;
186
+ }
187
+ else if (typeof callbackResult !== 'function') {
188
+ try {
189
+ serializedResult = JSON.parse(JSON.stringify(callbackResult));
190
+ }
191
+ catch {
192
+ serializedResult = String(callbackResult);
193
+ }
194
+ }
195
+ }
196
+ const currentTest = this.getCurrentTest();
197
+ const effectiveUid = currentTest?.uid ?? testUid;
198
+ if (effectiveUid) {
199
+ const isRetry = cmdSig === this.lastCapturedSig && this.lastCapturedId !== null;
200
+ if (isRetry) {
201
+ // Same command fired again (internal retry) — replace the previous
202
+ // entry so only the final result appears in the UI.
203
+ const { entry, oldTimestamp } = this.sessionCapturer.replaceCommand(this.lastCapturedId, methodName, logArgs, serializedResult, undefined, effectiveUid, callSource, commandTimestamp);
204
+ this.lastCapturedId = entry._id ?? null;
205
+ this.sessionCapturer.sendReplaceCommand(oldTimestamp, entry);
206
+ const entryToScreenshot = entry;
207
+ const ts = entryToScreenshot.timestamp;
208
+ this.sessionCapturer
209
+ .takeScreenshotViaHttp(browser)
210
+ .then((screenshot) => {
211
+ if (screenshot) {
212
+ ;
213
+ entryToScreenshot.screenshot = screenshot;
214
+ this.sessionCapturer.sendReplaceCommand(ts, entryToScreenshot);
215
+ log.info(`[screenshot] Attached to ${methodName} (retry)`);
216
+ }
217
+ })
218
+ .catch(() => { });
219
+ }
220
+ else {
221
+ // New command — capture and track.
222
+ // captureCommand() pushes the entry to commandsLog synchronously
223
+ // before any async work (navigation perf capture), so we can grab
224
+ // the ID immediately after the call — before any microtask fires.
225
+ // This avoids the race where a Nightwatch retry callback executes
226
+ // before .then() sets lastCapturedId, causing missed dedup.
227
+ this.lastCapturedSig = cmdSig;
228
+ this.lastCapturedId = null;
229
+ this.sessionCapturer
230
+ .captureCommand(methodName, logArgs, serializedResult, undefined, effectiveUid, callSource, commandTimestamp)
231
+ .catch((err) => log.error(`Failed to capture ${methodName}: ${err.message}`));
232
+ const lastCommand = this.sessionCapturer.commandsLog[this.sessionCapturer.commandsLog.length - 1];
233
+ if (lastCommand) {
234
+ this.lastCapturedId = lastCommand._id ?? null;
235
+ this.sessionCapturer.sendCommand(lastCommand);
236
+ log.info(`[command] ${methodName}`);
237
+ }
238
+ const entryToScreenshot = lastCommand;
239
+ if (entryToScreenshot) {
240
+ const ts = entryToScreenshot.timestamp;
241
+ this.sessionCapturer
242
+ .takeScreenshotViaHttp(browser)
243
+ .then((screenshot) => {
244
+ if (screenshot) {
245
+ ;
246
+ entryToScreenshot.screenshot = screenshot;
247
+ this.sessionCapturer.sendReplaceCommand(ts, entryToScreenshot);
248
+ log.info(`[screenshot] Attached to ${methodName}`);
249
+ }
250
+ })
251
+ .catch(() => { });
252
+ }
253
+ // After DOM-mutating commands, re-poll mutations from the injected
254
+ // script so the browser preview stays in sync. Use setTimeout to
255
+ // run OUTSIDE Nightwatch's current callback stack (safer queue-wise).
256
+ const isDomMutating = NAVIGATION_COMMANDS.includes(methodName) ||
257
+ [
258
+ 'click',
259
+ 'doubleClick',
260
+ 'rightClick',
261
+ 'setValue',
262
+ 'clearValue',
263
+ 'sendKeys',
264
+ 'submitForm',
265
+ 'back',
266
+ 'forward',
267
+ 'refresh'
268
+ ].includes(methodName);
269
+ if (isDomMutating) {
270
+ setTimeout(() => {
271
+ this.sessionCapturer.captureTrace(browser).catch(() => { });
272
+ }, 200);
273
+ }
274
+ }
275
+ }
276
+ if (userCallback) {
277
+ return userCallback(callbackResult);
278
+ }
279
+ };
280
+ const modifiedArgs = [...logArgs, captureCallback];
281
+ try {
282
+ const result = originalMethod(...modifiedArgs);
283
+ return result;
284
+ }
285
+ catch (error) {
286
+ const stackFrame = this.commandStack[this.commandStack.length - 1];
287
+ if (stackFrame?.command === methodName &&
288
+ stackFrame.signature === cmdSig) {
289
+ this.commandStack.pop();
290
+ }
291
+ this.captureCommandError(methodName, logArgs, error, callSource);
292
+ throw error;
293
+ }
294
+ }
295
+ captureCommandError(methodName, args, error, callSource) {
296
+ const currentTest = this.getCurrentTest();
297
+ if (!currentTest) {
298
+ return;
299
+ }
300
+ const errMsg = error instanceof Error ? error.message : String(error);
301
+ log.error(`[command error] ${methodName}: ${errMsg}`);
302
+ this.sessionCapturer
303
+ .captureCommand(methodName, args, undefined, error instanceof Error ? error : new Error(String(error)), currentTest.uid, callSource)
304
+ .catch((err) => log.error(`Failed to capture ${methodName}: ${err.message}`));
305
+ const lastCommand = this.sessionCapturer.commandsLog[this.sessionCapturer.commandsLog.length - 1];
306
+ if (lastCommand) {
307
+ this.sessionCapturer.sendCommand(lastCommand);
308
+ }
309
+ }
310
+ isProxied(browser) {
311
+ return this.proxiedBrowsers.has(browser);
312
+ }
313
+ }
314
+ //# sourceMappingURL=browserProxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browserProxy.js","sourceRoot":"","sources":["../../src/helpers/browserProxy.ts"],"names":[],"mappings":"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"}