@wdio/selenium-devtools 1.0.0 → 1.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.
- package/dist/assertPatcher.d.ts +11 -0
- package/dist/assertPatcher.js +123 -0
- package/dist/assertPatcher.js.map +1 -0
- package/dist/bidi.d.ts +6 -0
- package/dist/bidi.js +222 -0
- package/dist/bidi.js.map +1 -0
- package/dist/constants.d.ts +75 -0
- package/dist/constants.js +146 -0
- package/dist/constants.js.map +1 -0
- package/dist/driverPatcher.d.ts +4 -0
- package/dist/driverPatcher.js +256 -0
- package/dist/driverPatcher.js.map +1 -0
- package/dist/helpers/detachedBackend.d.ts +7 -0
- package/dist/helpers/detachedBackend.js +34 -0
- package/dist/helpers/detachedBackend.js.map +1 -0
- package/dist/helpers/runtime.d.ts +3 -0
- package/dist/helpers/runtime.js +47 -0
- package/dist/helpers/runtime.js.map +1 -0
- package/dist/helpers/suiteManager.d.ts +19 -0
- package/dist/helpers/suiteManager.js +131 -0
- package/dist/helpers/suiteManager.js.map +1 -0
- package/dist/helpers/testManager.d.ts +47 -0
- package/dist/helpers/testManager.js +158 -0
- package/dist/helpers/testManager.js.map +1 -0
- package/dist/helpers/utils.d.ts +26 -0
- package/dist/helpers/utils.js +187 -0
- package/dist/helpers/utils.js.map +1 -0
- package/dist/helpers/videoEncoder.d.ts +2 -0
- package/dist/helpers/videoEncoder.js +89 -0
- package/dist/helpers/videoEncoder.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +801 -0
- package/dist/index.js.map +1 -0
- package/dist/reporter.d.ts +18 -0
- package/dist/reporter.js +72 -0
- package/dist/reporter.js.map +1 -0
- package/dist/rerunManager.d.ts +8 -0
- package/dist/rerunManager.js +78 -0
- package/dist/rerunManager.js.map +1 -0
- package/dist/runnerHooks.d.ts +6 -0
- package/dist/runnerHooks.js +594 -0
- package/dist/runnerHooks.js.map +1 -0
- package/dist/screencast.d.ts +11 -0
- package/dist/screencast.js +179 -0
- package/dist/screencast.js.map +1 -0
- package/dist/session.d.ts +48 -0
- package/dist/session.js +480 -0
- package/dist/session.js.map +1 -0
- package/dist/setupConsole.d.ts +1 -0
- package/dist/setupConsole.js +13 -0
- package/dist/setupConsole.js.map +1 -0
- package/dist/types.d.ts +235 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +3 -3
|
@@ -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,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,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
|
+
}
|