@wdio/selenium-devtools 0.0.1

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.
Files changed (56) hide show
  1. package/README.md +411 -0
  2. package/dist/assertPatcher.d.ts +11 -0
  3. package/dist/assertPatcher.js +123 -0
  4. package/dist/assertPatcher.js.map +1 -0
  5. package/dist/bidi.d.ts +6 -0
  6. package/dist/bidi.js +222 -0
  7. package/dist/bidi.js.map +1 -0
  8. package/dist/constants.d.ts +75 -0
  9. package/dist/constants.js +146 -0
  10. package/dist/constants.js.map +1 -0
  11. package/dist/driverPatcher.d.ts +4 -0
  12. package/dist/driverPatcher.js +256 -0
  13. package/dist/driverPatcher.js.map +1 -0
  14. package/dist/helpers/detachedBackend.d.ts +7 -0
  15. package/dist/helpers/detachedBackend.js +34 -0
  16. package/dist/helpers/detachedBackend.js.map +1 -0
  17. package/dist/helpers/runtime.d.ts +3 -0
  18. package/dist/helpers/runtime.js +47 -0
  19. package/dist/helpers/runtime.js.map +1 -0
  20. package/dist/helpers/suiteManager.d.ts +19 -0
  21. package/dist/helpers/suiteManager.js +131 -0
  22. package/dist/helpers/suiteManager.js.map +1 -0
  23. package/dist/helpers/testManager.d.ts +47 -0
  24. package/dist/helpers/testManager.js +158 -0
  25. package/dist/helpers/testManager.js.map +1 -0
  26. package/dist/helpers/utils.d.ts +26 -0
  27. package/dist/helpers/utils.js +187 -0
  28. package/dist/helpers/utils.js.map +1 -0
  29. package/dist/helpers/videoEncoder.d.ts +2 -0
  30. package/dist/helpers/videoEncoder.js +89 -0
  31. package/dist/helpers/videoEncoder.js.map +1 -0
  32. package/dist/index.d.ts +15 -0
  33. package/dist/index.js +801 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/reporter.d.ts +18 -0
  36. package/dist/reporter.js +72 -0
  37. package/dist/reporter.js.map +1 -0
  38. package/dist/rerunManager.d.ts +8 -0
  39. package/dist/rerunManager.js +78 -0
  40. package/dist/rerunManager.js.map +1 -0
  41. package/dist/runnerHooks.d.ts +6 -0
  42. package/dist/runnerHooks.js +594 -0
  43. package/dist/runnerHooks.js.map +1 -0
  44. package/dist/screencast.d.ts +11 -0
  45. package/dist/screencast.js +179 -0
  46. package/dist/screencast.js.map +1 -0
  47. package/dist/session.d.ts +48 -0
  48. package/dist/session.js +480 -0
  49. package/dist/session.js.map +1 -0
  50. package/dist/setupConsole.d.ts +1 -0
  51. package/dist/setupConsole.js +13 -0
  52. package/dist/setupConsole.js.map +1 -0
  53. package/dist/types.d.ts +235 -0
  54. package/dist/types.js +5 -0
  55. package/dist/types.js.map +1 -0
  56. package/package.json +68 -0
@@ -0,0 +1,256 @@
1
+ import { createRequire } from 'node:module';
2
+ import logger from '@wdio/logger';
3
+ import { INTERNAL_DRIVER_METHODS, PATCHED_SYMBOL, TRACKED_ELEMENT_METHODS } from './constants.js';
4
+ import { getCallSourceFromStack } from './helpers/utils.js';
5
+ const log = logger('@wdio/selenium-devtools:driverPatcher');
6
+ const originals = {};
7
+ const elementOriginals = {};
8
+ export function getDriverOriginals() {
9
+ return originals;
10
+ }
11
+ export function getElementOriginals() {
12
+ return elementOriginals;
13
+ }
14
+ // Resolve user's selenium-webdriver first, then fall back to our own.
15
+ function loadSeleniumWebdriver() {
16
+ try {
17
+ const userRequire = createRequire(`${process.cwd()}/`);
18
+ return userRequire('selenium-webdriver');
19
+ }
20
+ catch {
21
+ try {
22
+ const localRequire = createRequire(import.meta.url);
23
+ return localRequire('selenium-webdriver');
24
+ }
25
+ catch (err) {
26
+ log.warn(`selenium-webdriver not found — devtools auto-attach disabled. (${err.message})`);
27
+ return null;
28
+ }
29
+ }
30
+ }
31
+ function isWebElementLike(v) {
32
+ return (v &&
33
+ typeof v === 'object' &&
34
+ typeof v.getId === 'function' &&
35
+ typeof v.click === 'function');
36
+ }
37
+ function safeSerialize(value) {
38
+ if (value === null || value === undefined) {
39
+ return value;
40
+ }
41
+ if (typeof value === 'function') {
42
+ return '[Function]';
43
+ }
44
+ if (isWebElementLike(value)) {
45
+ return webElementSummary(value);
46
+ }
47
+ if (typeof value === 'object' &&
48
+ 'using' in value &&
49
+ 'value' in value &&
50
+ Object.keys(value).length === 2) {
51
+ return `By.${value.using}(${JSON.stringify(value.value)})`;
52
+ }
53
+ if (Array.isArray(value)) {
54
+ if (value.length > 0 && value.every(isWebElementLike)) {
55
+ return `<WebElement[]> (count: ${value.length})`;
56
+ }
57
+ return value.map(safeSerialize);
58
+ }
59
+ if (typeof value === 'object') {
60
+ try {
61
+ return JSON.parse(JSON.stringify(value));
62
+ }
63
+ catch {
64
+ return String(value);
65
+ }
66
+ }
67
+ return value;
68
+ }
69
+ function webElementSummary(el) {
70
+ // `id_` is a Promise; some selenium versions stash the resolved value sync.
71
+ const peek = el?.id_?._value ?? el?.id_?.value ?? null;
72
+ return peek ? `<WebElement id=${peek}>` : '<WebElement>';
73
+ }
74
+ function wrapPrototype(proto, methodNames, fromElement, hooks) {
75
+ if (proto[PATCHED_SYMBOL]) {
76
+ return [];
77
+ }
78
+ ;
79
+ proto[PATCHED_SYMBOL] = true;
80
+ const wrapped = [];
81
+ for (const methodName of methodNames) {
82
+ const original = proto[methodName];
83
+ if (typeof original !== 'function') {
84
+ continue;
85
+ }
86
+ if (methodName === 'constructor' || methodName.startsWith('__')) {
87
+ continue;
88
+ }
89
+ ;
90
+ proto[methodName] = function (...args) {
91
+ const callInfo = getCallSourceFromStack();
92
+ const startedAt = Date.now();
93
+ const sanitizedArgs = args.map(safeSerialize);
94
+ const settle = (result, error) => {
95
+ try {
96
+ hooks.onCommand({
97
+ command: methodName,
98
+ args: sanitizedArgs,
99
+ result: error ? undefined : safeSerialize(result),
100
+ rawResult: error ? undefined : result,
101
+ error,
102
+ callSource: callInfo.callSource,
103
+ timestamp: startedAt,
104
+ fromElement
105
+ });
106
+ }
107
+ catch (hookErr) {
108
+ log.warn(`onCommand hook threw for ${methodName}: ${hookErr.message}`);
109
+ }
110
+ };
111
+ let result;
112
+ try {
113
+ result = original.apply(this, args);
114
+ }
115
+ catch (err) {
116
+ settle(undefined, err);
117
+ throw err;
118
+ }
119
+ // CRITICAL: return the original thenable. findElement returns a
120
+ // WebElementPromise that carries sendKeys/click for chaining; a plain
121
+ // Promise from `.then(...)` would break `findElement(...).sendKeys(...)`.
122
+ if (result && typeof result.then === 'function') {
123
+ result.then((v) => settle(v, undefined), (err) => settle(undefined, err));
124
+ return result;
125
+ }
126
+ settle(result, undefined);
127
+ return result;
128
+ };
129
+ wrapped.push(methodName);
130
+ }
131
+ return wrapped;
132
+ }
133
+ export function patchSelenium(hooks) {
134
+ const sw = loadSeleniumWebdriver();
135
+ if (!sw) {
136
+ return false;
137
+ }
138
+ const Builder = sw.Builder;
139
+ const WebDriver = sw.WebDriver;
140
+ const WebElement = sw.WebElement;
141
+ if (!Builder || !WebDriver) {
142
+ log.warn('selenium-webdriver loaded but Builder/WebDriver missing — version unsupported?');
143
+ return false;
144
+ }
145
+ // Stash unwrapped originals before any patching.
146
+ const driverProto = WebDriver.prototype;
147
+ if (typeof driverProto.takeScreenshot === 'function') {
148
+ const orig = driverProto.takeScreenshot;
149
+ originals.takeScreenshot = (driver) => orig.call(driver);
150
+ }
151
+ if (typeof driverProto.executeScript === 'function') {
152
+ const orig = driverProto.executeScript;
153
+ originals.executeScript = (driver, script, ...args) => orig.call(driver, script, ...args);
154
+ }
155
+ if (typeof driverProto.manage === 'function') {
156
+ const orig = driverProto.manage;
157
+ originals.manage = (driver) => orig.call(driver);
158
+ }
159
+ const driverMethods = collectMethodNames(WebDriver.prototype);
160
+ const tracked = driverMethods.filter((m) => !INTERNAL_DRIVER_METHODS.includes(m));
161
+ const wrappedDriver = wrapPrototype(WebDriver.prototype, tracked,
162
+ /* fromElement */ false, hooks);
163
+ log.info(`Wrapped ${wrappedDriver.length} WebDriver method(s)`);
164
+ // Lets onBeforeQuit flush async cleanup before runners that `process.exit()`
165
+ // tear down (those bypass node's beforeExit).
166
+ if (typeof driverProto.quit === 'function') {
167
+ const originalQuit = driverProto.quit;
168
+ driverProto.quit = async function patchedQuit() {
169
+ if (hooks.onBeforeQuit) {
170
+ try {
171
+ await hooks.onBeforeQuit(this);
172
+ }
173
+ catch (err) {
174
+ log.warn(`onBeforeQuit hook threw: ${err.message}`);
175
+ }
176
+ }
177
+ return originalQuit.call(this);
178
+ };
179
+ log.info('Wrapped WebDriver.quit (cleanup hook)');
180
+ }
181
+ if (WebElement) {
182
+ const elProto = WebElement.prototype;
183
+ if (typeof elProto.getText === 'function') {
184
+ const orig = elProto.getText;
185
+ elementOriginals.getText = (el) => orig.call(el);
186
+ }
187
+ if (typeof elProto.getTagName === 'function') {
188
+ const orig = elProto.getTagName;
189
+ elementOriginals.getTagName = (el) => orig.call(el);
190
+ }
191
+ const wrappedEl = wrapPrototype(WebElement.prototype, TRACKED_ELEMENT_METHODS,
192
+ /* fromElement */ true, hooks);
193
+ log.info(`Wrapped ${wrappedEl.length} WebElement method(s)`);
194
+ }
195
+ if (!Builder.prototype[PATCHED_SYMBOL]) {
196
+ ;
197
+ Builder.prototype[PATCHED_SYMBOL] = true;
198
+ const originalBuild = Builder.prototype.build;
199
+ Builder.prototype.build = function patchedBuild(...args) {
200
+ if (hooks.onBeforeBuild) {
201
+ try {
202
+ hooks.onBeforeBuild(this);
203
+ }
204
+ catch (err) {
205
+ log.warn(`onBeforeBuild hook threw: ${err.message}`);
206
+ }
207
+ }
208
+ const driver = originalBuild.apply(this, args);
209
+ try {
210
+ const result = hooks.onDriverCreated(driver);
211
+ if (result && typeof result.then === 'function') {
212
+ ;
213
+ result.catch((err) => log.warn(`onDriverCreated hook rejected: ${err.message}`));
214
+ }
215
+ }
216
+ catch (err) {
217
+ log.warn(`onDriverCreated hook threw: ${err.message}`);
218
+ }
219
+ // Selenium 4: WebDriver is thenable. Extend `.then` so `await Builder.build()`
220
+ // also waits for the dashboard to connect.
221
+ const isThenable = driver && typeof driver.then === 'function';
222
+ if (isThenable && hooks.waitForReady) {
223
+ const originalThen = driver.then.bind(driver);
224
+ driver.then = function patchedThen(onFulfilled, onRejected) {
225
+ return originalThen(async (resolved) => {
226
+ try {
227
+ await hooks.waitForReady();
228
+ }
229
+ catch {
230
+ /* fall through — don't block forever on UI failures */
231
+ }
232
+ return onFulfilled ? onFulfilled(resolved) : resolved;
233
+ }, onRejected);
234
+ };
235
+ }
236
+ return driver;
237
+ };
238
+ log.info('Patched Builder.prototype.build');
239
+ }
240
+ return true;
241
+ }
242
+ function collectMethodNames(proto) {
243
+ const names = new Set();
244
+ let current = proto;
245
+ while (current && current !== Object.prototype) {
246
+ for (const name of Object.getOwnPropertyNames(current)) {
247
+ const desc = Object.getOwnPropertyDescriptor(current, name);
248
+ if (desc && typeof desc.value === 'function') {
249
+ names.add(name);
250
+ }
251
+ }
252
+ current = Object.getPrototypeOf(current);
253
+ }
254
+ return [...names];
255
+ }
256
+ //# sourceMappingURL=driverPatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driverPatcher.js","sourceRoot":"","sources":["../src/driverPatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare function startDetachedBackend(opts: {
2
+ port: number;
3
+ hostname: string;
4
+ readyTimeoutMs?: number;
5
+ }): Promise<{
6
+ port: number;
7
+ }>;
@@ -0,0 +1,34 @@
1
+ import net from 'node:net';
2
+ import { spawn } from 'node:child_process';
3
+ import { createRequire } from 'node:module';
4
+ const require = createRequire(import.meta.url);
5
+ export async function startDetachedBackend(opts) {
6
+ const backendPath = require.resolve('@wdio/devtools-backend');
7
+ const code = `import(${JSON.stringify(backendPath)}).then(m => m.start({ port: ${opts.port}, hostname: ${JSON.stringify(opts.hostname)} })).catch(err => { console.error(err); process.exit(1) })`;
8
+ spawn(process.execPath, ['-e', code], {
9
+ detached: true,
10
+ stdio: 'ignore'
11
+ }).unref();
12
+ const deadline = Date.now() + (opts.readyTimeoutMs ?? 10000);
13
+ while (Date.now() < deadline) {
14
+ if (await canConnect(opts.port, opts.hostname)) {
15
+ return { port: opts.port };
16
+ }
17
+ await new Promise((resolve) => setTimeout(resolve, 100));
18
+ }
19
+ throw new Error(`Detached backend never came up on ${opts.hostname}:${opts.port}`);
20
+ }
21
+ function canConnect(port, host) {
22
+ return new Promise((resolve) => {
23
+ const sock = net.connect(port, host);
24
+ sock.once('connect', () => {
25
+ sock.destroy();
26
+ resolve(true);
27
+ });
28
+ sock.once('error', () => {
29
+ sock.destroy();
30
+ resolve(false);
31
+ });
32
+ });
33
+ }
34
+ //# sourceMappingURL=detachedBackend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detachedBackend.js","sourceRoot":"","sources":["../../src/helpers/detachedBackend.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAA;AAC1B,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE9C,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAI1C;IACC,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAA;IAC7D,MAAM,IAAI,GAAG,UAAU,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,+BAA+B,IAAI,CAAC,IAAI,eAAe,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,4DAA4D,CAAA;IAClM,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE;QACpC,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,QAAQ;KAChB,CAAC,CAAC,KAAK,EAAE,CAAA;IAEV,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC,CAAA;IAC5D,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/C,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAA;QAC5B,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAA;IAC1D,CAAC;IACD,MAAM,IAAI,KAAK,CACb,qCAAqC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAClE,CAAA;AACH,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,IAAY;IAC5C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QACpC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;YACxB,IAAI,CAAC,OAAO,EAAE,CAAA;YACd,OAAO,CAAC,IAAI,CAAC,CAAA;QACf,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;YACtB,IAAI,CAAC,OAAO,EAAE,CAAA;YACd,OAAO,CAAC,KAAK,CAAC,CAAA;QAChB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function detectOwnVersion(): string;
2
+ export declare function detectRunner(): string;
3
+ export declare function detectSeleniumVersion(): string | undefined;
@@ -0,0 +1,47 @@
1
+ import { createRequire } from 'node:module';
2
+ export function detectOwnVersion() {
3
+ try {
4
+ return createRequire(import.meta.url)('../../package.json').version;
5
+ }
6
+ catch {
7
+ return 'unknown';
8
+ }
9
+ }
10
+ export function detectRunner() {
11
+ const argv = (process.argv[1] || '').toLowerCase();
12
+ if (argv.includes('mocha')) {
13
+ return 'mocha';
14
+ }
15
+ if (argv.includes('jest')) {
16
+ return 'jest';
17
+ }
18
+ if (argv.includes('jasmine')) {
19
+ return 'jasmine';
20
+ }
21
+ if (argv.includes('vitest')) {
22
+ return 'vitest';
23
+ }
24
+ if (argv.includes('cucumber')) {
25
+ return 'cucumber';
26
+ }
27
+ if (argv.endsWith('node') || argv.endsWith('node.exe')) {
28
+ return 'node';
29
+ }
30
+ return 'unknown';
31
+ }
32
+ export function detectSeleniumVersion() {
33
+ const tryRead = (req) => {
34
+ try {
35
+ return req('selenium-webdriver/package.json').version;
36
+ }
37
+ catch {
38
+ return undefined;
39
+ }
40
+ };
41
+ const fromUser = tryRead(createRequire(`${process.cwd()}/`));
42
+ if (fromUser) {
43
+ return fromUser;
44
+ }
45
+ return tryRead(createRequire(import.meta.url));
46
+ }
47
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/helpers/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC;QACH,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAA;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAA;IAClD,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAA;IAChB,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,MAAM,CAAA;IACf,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,OAAO,QAAQ,CAAA;IACjB,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,OAAO,UAAU,CAAA;IACnB,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACvD,OAAO,MAAM,CAAA;IACf,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,MAAM,OAAO,GAAG,CAAC,GAAgB,EAAsB,EAAE;QACvD,IAAI,CAAC;YACH,OAAO,GAAG,CAAC,iCAAiC,CAAC,CAAC,OAAO,CAAA;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC,CAAA;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;IAC5D,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,CAAA;IACjB,CAAC;IACD,OAAO,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAChD,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { SuiteStats, TestStats } from '../types.js';
2
+ import type { TestReporter } from '../reporter.js';
3
+ export declare class SuiteManager {
4
+ private testReporter;
5
+ private rootSuite;
6
+ private currentParent;
7
+ constructor(testReporter: TestReporter);
8
+ getOrCreateRootSuite(file: string, title: string): SuiteStats;
9
+ getRootSuite(): SuiteStats | null;
10
+ /** Where new tests are appended — root suite, or the open scenario sub-suite. */
11
+ getCurrentParent(): SuiteStats | null;
12
+ /** Open a Cucumber scenario as a sub-suite; steps attach until endScenarioSuite. */
13
+ startScenarioSuite(name: string, file: string, callSource?: string): SuiteStats | null;
14
+ endScenarioSuite(state: SuiteStats['state']): void;
15
+ setRootSuiteTitle(title: string, callSource?: string): void;
16
+ addTest(test: TestStats): void;
17
+ finalize(): void;
18
+ reset(): void;
19
+ }
@@ -0,0 +1,131 @@
1
+ import { DEFAULTS, TEST_STATE } from '../constants.js';
2
+ import { generateStableUid } from './utils.js';
3
+ // rootSuite = describe block (Mocha/Jest) or feature (Cucumber).
4
+ // currentParent points at the in-progress scenario sub-suite for Cucumber,
5
+ // or at rootSuite otherwise. Tests append to currentParent.
6
+ export class SuiteManager {
7
+ testReporter;
8
+ rootSuite = null;
9
+ currentParent = null;
10
+ constructor(testReporter) {
11
+ this.testReporter = testReporter;
12
+ }
13
+ getOrCreateRootSuite(file, title) {
14
+ if (this.rootSuite) {
15
+ return this.rootSuite;
16
+ }
17
+ const suite = {
18
+ uid: generateStableUid(file, title),
19
+ cid: DEFAULTS.CID,
20
+ title,
21
+ fullTitle: title,
22
+ file,
23
+ type: 'suite',
24
+ start: new Date(),
25
+ state: TEST_STATE.RUNNING,
26
+ end: null,
27
+ tests: [],
28
+ suites: [],
29
+ hooks: [],
30
+ _duration: DEFAULTS.DURATION
31
+ };
32
+ this.rootSuite = suite;
33
+ this.currentParent = suite;
34
+ this.testReporter.onSuiteStart(suite);
35
+ return suite;
36
+ }
37
+ getRootSuite() {
38
+ return this.rootSuite;
39
+ }
40
+ /** Where new tests are appended — root suite, or the open scenario sub-suite. */
41
+ getCurrentParent() {
42
+ return this.currentParent ?? this.rootSuite;
43
+ }
44
+ /** Open a Cucumber scenario as a sub-suite; steps attach until endScenarioSuite. */
45
+ startScenarioSuite(name, file, callSource) {
46
+ if (!this.rootSuite) {
47
+ return null;
48
+ }
49
+ const sub = {
50
+ uid: generateStableUid(file, `${this.rootSuite.uid}::${name}`),
51
+ cid: DEFAULTS.CID,
52
+ title: name,
53
+ fullTitle: name,
54
+ file,
55
+ type: 'suite',
56
+ start: new Date(),
57
+ state: TEST_STATE.RUNNING,
58
+ end: null,
59
+ tests: [],
60
+ suites: [],
61
+ hooks: [],
62
+ _duration: DEFAULTS.DURATION,
63
+ callSource,
64
+ // Without `parent`, the dashboard's `!suite.parent` filter renders this
65
+ // sub-suite at the root too, duplicating it next to the feature.
66
+ parent: this.rootSuite.uid
67
+ };
68
+ this.rootSuite.suites = this.rootSuite.suites ?? [];
69
+ this.rootSuite.suites.push(sub);
70
+ this.currentParent = sub;
71
+ this.testReporter.onSuiteStart(sub);
72
+ return sub;
73
+ }
74
+ endScenarioSuite(state) {
75
+ const cur = this.currentParent;
76
+ if (!cur || cur === this.rootSuite || cur.end) {
77
+ return;
78
+ }
79
+ cur.end = new Date();
80
+ cur._duration =
81
+ cur.end.getTime() - (cur.start?.getTime() || cur.end.getTime());
82
+ cur.state = state;
83
+ this.testReporter.onSuiteEnd(cur);
84
+ this.currentParent = this.rootSuite;
85
+ }
86
+ setRootSuiteTitle(title, callSource) {
87
+ if (!this.rootSuite) {
88
+ return;
89
+ }
90
+ let changed = false;
91
+ if (title && this.rootSuite.title !== title) {
92
+ this.rootSuite.title = title;
93
+ this.rootSuite.fullTitle = title;
94
+ changed = true;
95
+ }
96
+ if (callSource && this.rootSuite.callSource !== callSource) {
97
+ this.rootSuite.callSource = callSource;
98
+ changed = true;
99
+ }
100
+ if (changed) {
101
+ this.testReporter.updateSuites();
102
+ }
103
+ }
104
+ addTest(test) {
105
+ const parent = this.getCurrentParent();
106
+ if (!parent) {
107
+ return;
108
+ }
109
+ parent.tests.push(test);
110
+ this.testReporter.updateSuites();
111
+ }
112
+ finalize() {
113
+ if (!this.rootSuite || this.rootSuite.end) {
114
+ return;
115
+ }
116
+ this.rootSuite.end = new Date();
117
+ this.rootSuite._duration =
118
+ this.rootSuite.end.getTime() -
119
+ (this.rootSuite.start?.getTime() || this.rootSuite.end.getTime());
120
+ const failedDirect = this.rootSuite.tests.some((t) => typeof t !== 'string' && t.state === TEST_STATE.FAILED);
121
+ const failedNested = (this.rootSuite.suites ?? []).some((s) => s.state === TEST_STATE.FAILED);
122
+ this.rootSuite.state =
123
+ failedDirect || failedNested ? TEST_STATE.FAILED : TEST_STATE.PASSED;
124
+ this.testReporter.onSuiteEnd(this.rootSuite);
125
+ }
126
+ reset() {
127
+ this.rootSuite = null;
128
+ this.currentParent = null;
129
+ }
130
+ }
131
+ //# sourceMappingURL=suiteManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suiteManager.js","sourceRoot":"","sources":["../../src/helpers/suiteManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { SuiteStats, TestStats } from '../types.js';
2
+ import type { TestReporter } from '../reporter.js';
3
+ import type { SuiteManager } from './suiteManager.js';
4
+ /**
5
+ * Tracks the currently-active test inside the session suite. Two modes:
6
+ * - `session` (default): one synthetic test wraps the entire driver session.
7
+ * - `marked`: user calls startTest(name)/endTest(state); each pair adds a test.
8
+ *
9
+ * The proxy reads `getCurrentTest()` to tag each captured command with a uid.
10
+ */
11
+ export declare class TestManager {
12
+ #private;
13
+ private rootSuite;
14
+ private testReporter;
15
+ private suiteManager;
16
+ constructor(rootSuite: SuiteStats, testReporter: TestReporter, suiteManager: SuiteManager);
17
+ /** Where new tests attach — current scenario sub-suite (Cucumber) or root. */
18
+ private get suite();
19
+ /**
20
+ * Returns the test that captured commands should attach to. Order:
21
+ * 1. The currently-running marked test, if any.
22
+ * 2. (only if the user has NOT yet used startMarkedTest) the synthetic
23
+ * session-wide test, lazily created on first command.
24
+ * 3. The most-recently-ended marked test (handles commands that fire
25
+ * between the user's it() blocks — chromedriver retries, hooks, etc).
26
+ */
27
+ getOrEnsureTest(): TestStats | null;
28
+ /**
29
+ * Public alias retained for callers that want to force the synthetic test
30
+ * to exist. The internal code path uses `getOrEnsureTest()` instead.
31
+ */
32
+ ensureSessionTest(): TestStats;
33
+ /**
34
+ * Switch into marked mode and start a new test. The first time this is
35
+ * called, any pre-existing synthetic session test is removed from the suite
36
+ * (along with any commands that referenced it) — once the user takes over
37
+ * the test boundaries, the synthetic just adds noise.
38
+ */
39
+ startMarkedTest(name: string, opts?: {
40
+ file?: string;
41
+ callSource?: string;
42
+ }): TestStats;
43
+ endCurrent(state: TestStats['state']): void;
44
+ getCurrentTest(): TestStats | null;
45
+ /** Called when the driver session is closing (process exit / quit). */
46
+ finalizeSession(): void;
47
+ }