@wdio/utils 9.0.0-alpha.9 → 9.0.4

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 (43) hide show
  1. package/build/envDetector.d.ts +3 -3
  2. package/build/envDetector.d.ts.map +1 -1
  3. package/build/index.d.ts +2 -2
  4. package/build/index.d.ts.map +1 -1
  5. package/build/index.js +1902 -24
  6. package/build/initializeServices.d.ts +3 -3
  7. package/build/initializeServices.d.ts.map +1 -1
  8. package/build/monad.d.ts.map +1 -1
  9. package/build/node/manager.d.ts +2 -2
  10. package/build/node/manager.d.ts.map +1 -1
  11. package/build/node/startWebDriver.d.ts +2 -3
  12. package/build/node/startWebDriver.d.ts.map +1 -1
  13. package/build/node/utils.d.ts.map +1 -1
  14. package/build/node.js +473 -0
  15. package/build/pIteration.d.ts.map +1 -1
  16. package/build/shim.d.ts.map +1 -1
  17. package/build/startWebDriver.d.ts +2 -3
  18. package/build/startWebDriver.d.ts.map +1 -1
  19. package/build/test-framework/errorHandler.d.ts.map +1 -1
  20. package/build/test-framework/testFnWrapper.d.ts.map +1 -1
  21. package/build/test-framework/testInterfaceWrapper.d.ts.map +1 -1
  22. package/build/utils.d.ts +11 -2
  23. package/build/utils.d.ts.map +1 -1
  24. package/package.json +10 -11
  25. package/build/constants.js +0 -114
  26. package/build/envDetector.js +0 -251
  27. package/build/initializePlugin.js +0 -38
  28. package/build/initializeServices.js +0 -159
  29. package/build/monad.js +0 -196
  30. package/build/node/index.js +0 -3
  31. package/build/node/manager.js +0 -106
  32. package/build/node/startWebDriver.js +0 -140
  33. package/build/node/utils.js +0 -285
  34. package/build/pIteration.js +0 -347
  35. package/build/shim.js +0 -293
  36. package/build/startWebDriver.js +0 -20
  37. package/build/test-framework/errorHandler.js +0 -33
  38. package/build/test-framework/index.js +0 -4
  39. package/build/test-framework/testFnWrapper.js +0 -97
  40. package/build/test-framework/testInterfaceWrapper.js +0 -162
  41. package/build/test-framework/types.js +0 -1
  42. package/build/utils.js +0 -320
  43. /package/{LICENSE-MIT → LICENSE} +0 -0
package/build/index.js CHANGED
@@ -1,24 +1,1902 @@
1
- /* istanbul ignore file */
2
- import webdriverMonad from './monad.js';
3
- import initializePlugin from './initializePlugin.js';
4
- import { startWebDriver } from './startWebDriver.js';
5
- import { initializeWorkerService, initializeLauncherService } from './initializeServices.js';
6
- import { commandCallStructure, isValidParameter, getArgumentType, safeImport, isFunctionAsync, transformCommandLogResult, sleep, isAppiumCapability, userImport } from './utils.js';
7
- import { wrapCommand, executeHooksWithArgs, executeAsync } from './shim.js';
8
- import * as asyncIterators from './pIteration.js';
9
- import { testFnWrapper, wrapGlobalTestMethod } from './test-framework/index.js';
10
- import { isW3C, capabilitiesEnvironmentDetector, sessionEnvironmentDetector } from './envDetector.js';
11
- import { UNICODE_CHARACTERS, HOOK_DEFINITION } from './constants.js';
12
- export { startWebDriver, initializePlugin, initializeLauncherService, initializeWorkerService, isFunctionAsync, transformCommandLogResult, webdriverMonad, commandCallStructure, isValidParameter, getArgumentType, safeImport, sleep, isAppiumCapability, userImport, asyncIterators,
13
- /**
14
- * runner shim
15
- */
16
- wrapCommand, executeAsync, wrapGlobalTestMethod, testFnWrapper, executeHooksWithArgs,
17
- /**
18
- * environmentDetector
19
- */
20
- isW3C, sessionEnvironmentDetector, capabilitiesEnvironmentDetector,
21
- /**
22
- * constants
23
- */
24
- UNICODE_CHARACTERS, HOOK_DEFINITION };
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // src/constants.ts
12
+ var UNICODE_CHARACTERS, SUPPORTED_BROWSERNAMES, DEFAULT_HOSTNAME, DEFAULT_PROTOCOL, DEFAULT_PATH, HOOK_DEFINITION;
13
+ var init_constants = __esm({
14
+ "src/constants.ts"() {
15
+ "use strict";
16
+ UNICODE_CHARACTERS = {
17
+ "NULL": "\uE000",
18
+ "Unidentified": "\uE000",
19
+ "Cancel": "\uE001",
20
+ "Help": "\uE002",
21
+ "Backspace": "\uE003",
22
+ "Back space": "\uE003",
23
+ "Tab": "\uE004",
24
+ "Clear": "\uE005",
25
+ "Return": "\uE006",
26
+ "Enter": "\uE007",
27
+ "Shift": "\uE008",
28
+ "Control": "\uE009",
29
+ "Control Left": "\uE009",
30
+ "Control Right": "\uE051",
31
+ "Alt": "\uE00A",
32
+ "Pause": "\uE00B",
33
+ "Escape": "\uE00C",
34
+ "Space": "\uE00D",
35
+ " ": "\uE00D",
36
+ "PageUp": "\uE00E",
37
+ "Pageup": "\uE00E",
38
+ "Page_Up": "\uE00E",
39
+ "PageDown": "\uE00F",
40
+ "Pagedown": "\uE00F",
41
+ "Page_Down": "\uE00F",
42
+ "End": "\uE010",
43
+ "Home": "\uE011",
44
+ "ArrowLeft": "\uE012",
45
+ "Left arrow": "\uE012",
46
+ "Arrow_Left": "\uE012",
47
+ "ArrowUp": "\uE013",
48
+ "Up arrow": "\uE013",
49
+ "Arrow_Up": "\uE013",
50
+ "ArrowRight": "\uE014",
51
+ "Right arrow": "\uE014",
52
+ "Arrow_Right": "\uE014",
53
+ "ArrowDown": "\uE015",
54
+ "Down arrow": "\uE015",
55
+ "Arrow_Down": "\uE015",
56
+ "Insert": "\uE016",
57
+ "Delete": "\uE017",
58
+ "Semicolon": "\uE018",
59
+ "Equals": "\uE019",
60
+ "Numpad 0": "\uE01A",
61
+ "Numpad 1": "\uE01B",
62
+ "Numpad 2": "\uE01C",
63
+ "Numpad 3": "\uE01D",
64
+ "Numpad 4": "\uE01E",
65
+ "Numpad 5": "\uE01F",
66
+ "Numpad 6": "\uE020",
67
+ "Numpad 7": "\uE021",
68
+ "Numpad 8": "\uE022",
69
+ "Numpad 9": "\uE023",
70
+ "Multiply": "\uE024",
71
+ "Add": "\uE025",
72
+ "Separator": "\uE026",
73
+ "Subtract": "\uE027",
74
+ "Decimal": "\uE028",
75
+ "Divide": "\uE029",
76
+ "F1": "\uE031",
77
+ "F2": "\uE032",
78
+ "F3": "\uE033",
79
+ "F4": "\uE034",
80
+ "F5": "\uE035",
81
+ "F6": "\uE036",
82
+ "F7": "\uE037",
83
+ "F8": "\uE038",
84
+ "F9": "\uE039",
85
+ "F10": "\uE03A",
86
+ "F11": "\uE03B",
87
+ "F12": "\uE03C",
88
+ "Command": "\uE03D",
89
+ "Meta": "\uE03D",
90
+ "ZenkakuHankaku": "\uE040",
91
+ "Zenkaku_Hankaku": "\uE040"
92
+ };
93
+ SUPPORTED_BROWSERNAMES = {
94
+ chrome: ["chrome", "googlechrome", "chromium", "chromium-browser"],
95
+ firefox: ["firefox", "ff", "mozilla", "mozilla firefox"],
96
+ edge: ["edge", "microsoftedge", "msedge"],
97
+ safari: ["safari", "safari technology preview"]
98
+ };
99
+ DEFAULT_HOSTNAME = "localhost";
100
+ DEFAULT_PROTOCOL = "http";
101
+ DEFAULT_PATH = "/";
102
+ HOOK_DEFINITION = {
103
+ type: "object",
104
+ validate: (param) => {
105
+ if (!Array.isArray(param)) {
106
+ throw new Error("a hook option needs to be a list of functions");
107
+ }
108
+ for (const option of param) {
109
+ if (typeof option === "function") {
110
+ continue;
111
+ }
112
+ throw new Error("expected hook to be type of function");
113
+ }
114
+ }
115
+ };
116
+ }
117
+ });
118
+
119
+ // src/utils.ts
120
+ import fs from "node:fs/promises";
121
+ import url from "node:url";
122
+ import path from "node:path";
123
+ function assertPath(path4) {
124
+ if (typeof path4 !== "string") {
125
+ throw new TypeError("Path must be a string. Received " + JSON.stringify(path4));
126
+ }
127
+ }
128
+ function isAbsolute(p) {
129
+ assertPath(p);
130
+ return p.length > 0 && p.charCodeAt(0) === SLASH.codePointAt(0);
131
+ }
132
+ function overwriteElementCommands(propertiesObject) {
133
+ const elementOverrides = propertiesObject.__elementOverrides__ ? propertiesObject.__elementOverrides__.value : {};
134
+ for (const [commandName, userDefinedCommand] of Object.entries(elementOverrides)) {
135
+ if (typeof userDefinedCommand !== "function") {
136
+ throw new Error("overwriteCommand: commands be overwritten only with functions, command: " + commandName);
137
+ }
138
+ if (!propertiesObject[commandName]) {
139
+ throw new Error("overwriteCommand: no command to be overwritten: " + commandName);
140
+ }
141
+ if (typeof propertiesObject[commandName].value !== "function") {
142
+ throw new Error("overwriteCommand: only functions can be overwritten, command: " + commandName);
143
+ }
144
+ const origCommand = propertiesObject[commandName].value;
145
+ delete propertiesObject[commandName];
146
+ const newCommand = function(...args) {
147
+ const element = this;
148
+ return userDefinedCommand.apply(element, [
149
+ function origCommandFunction() {
150
+ const context = this || element;
151
+ return origCommand.apply(context, arguments);
152
+ },
153
+ ...args
154
+ ]);
155
+ };
156
+ propertiesObject[commandName] = {
157
+ value: newCommand,
158
+ configurable: true
159
+ };
160
+ }
161
+ delete propertiesObject.__elementOverrides__;
162
+ propertiesObject.__elementOverrides__ = { value: {} };
163
+ }
164
+ function commandCallStructure(commandName, args, unfurl = false) {
165
+ const callArgs = args.map((arg) => {
166
+ if (typeof arg === "string" && (arg.startsWith("!function(") || arg.startsWith("return (function") || arg.startsWith("return (async function"))) {
167
+ arg = "<fn>";
168
+ } else if (typeof arg === "string" && /**
169
+ * the isBase64 method returns for xPath values like
170
+ * "/html/body/a" a true value which is why we should
171
+ * include a command check in here.
172
+ */
173
+ !commandName.startsWith("findElement") && isBase64(arg)) {
174
+ arg = SCREENSHOT_REPLACEMENT;
175
+ } else if (typeof arg === "string") {
176
+ arg = `"${arg}"`;
177
+ } else if (typeof arg === "function") {
178
+ arg = "<fn>";
179
+ } else if (arg === null) {
180
+ arg = "null";
181
+ } else if (typeof arg === "object") {
182
+ arg = unfurl ? JSON.stringify(arg) : "<object>";
183
+ } else if (typeof arg === "undefined") {
184
+ arg = typeof arg;
185
+ }
186
+ return arg;
187
+ }).join(", ");
188
+ return `${commandName}(${callArgs})`;
189
+ }
190
+ function transformCommandLogResult(result) {
191
+ if (typeof result.file === "string" && isBase64(result.file)) {
192
+ return SCREENSHOT_REPLACEMENT;
193
+ } else if (typeof result.script === "string" && isBase64(result.script)) {
194
+ return SCRIPT_PLACEHOLDER;
195
+ } else if (typeof result.script === "string" && result.script.match(REGEX_SCRIPT_NAME)) {
196
+ const newScript = result.script.match(REGEX_SCRIPT_NAME)[2];
197
+ return { ...result, script: `${newScript}(...) [${Buffer.byteLength(result.script, "utf-8")} bytes]` };
198
+ } else if (typeof result.script === "string" && result.script.startsWith("!function(")) {
199
+ return { ...result, script: `<minified function> [${Buffer.byteLength(result.script, "utf-8")} bytes]` };
200
+ }
201
+ return result;
202
+ }
203
+ function isValidParameter(arg, expectedType) {
204
+ let shouldBeArray = false;
205
+ if (expectedType.slice(-2) === "[]") {
206
+ expectedType = expectedType.slice(0, -2);
207
+ shouldBeArray = true;
208
+ }
209
+ if (shouldBeArray) {
210
+ if (!Array.isArray(arg)) {
211
+ return false;
212
+ }
213
+ } else {
214
+ arg = [arg];
215
+ }
216
+ for (const argEntity of arg) {
217
+ const argEntityType = getArgumentType(argEntity);
218
+ if (!argEntityType.match(expectedType)) {
219
+ return false;
220
+ }
221
+ }
222
+ return true;
223
+ }
224
+ function getArgumentType(arg) {
225
+ return arg === null ? "null" : typeof arg;
226
+ }
227
+ async function userImport(moduleName, namedImport = "default") {
228
+ try {
229
+ const mod = await import(
230
+ /* @vite-ignore */
231
+ moduleName
232
+ );
233
+ if (namedImport in mod) {
234
+ return mod[namedImport];
235
+ }
236
+ } catch (err) {
237
+ throw new Error(`Couldn't import "${moduleName}"! Do you have it installed? If not run "npm install ${moduleName}"!`);
238
+ }
239
+ throw new Error(`Couldn't find "${namedImport}" in module "${moduleName}"`);
240
+ }
241
+ async function safeImport(name) {
242
+ let importPath = name;
243
+ try {
244
+ if (!globalThis.window) {
245
+ const { resolve } = await import("import-meta-resolve");
246
+ try {
247
+ importPath = await resolve(name, import.meta.url);
248
+ } catch (err) {
249
+ const localNodeModules = path.join(process.cwd(), "node_modules");
250
+ try {
251
+ importPath = await resolve(name, url.pathToFileURL(localNodeModules).toString());
252
+ } catch (err2) {
253
+ return null;
254
+ }
255
+ }
256
+ }
257
+ } catch (err) {
258
+ return null;
259
+ }
260
+ try {
261
+ const pkg = await import(
262
+ /* @vite-ignore */
263
+ importPath
264
+ );
265
+ if (pkg.default && pkg.default.default) {
266
+ return pkg.default;
267
+ }
268
+ return pkg;
269
+ } catch (e) {
270
+ throw new Error(`Couldn't initialize "${name}".
271
+ ${e.stack}`);
272
+ }
273
+ }
274
+ function isFunctionAsync(fn) {
275
+ return fn.constructor && fn.constructor.name === "AsyncFunction" || fn.name === "async";
276
+ }
277
+ function filterSpecArgs(args) {
278
+ return args.filter((arg) => typeof arg !== "function");
279
+ }
280
+ function isBase64(str) {
281
+ if (typeof str !== "string") {
282
+ throw new Error("Expected string but received invalid type.");
283
+ }
284
+ const len = str.length;
285
+ const notBase64 = /[^A-Z0-9+/=]/i;
286
+ if (!len || len % 4 !== 0 || notBase64.test(str)) {
287
+ return false;
288
+ }
289
+ const firstPaddingChar = str.indexOf("=");
290
+ return firstPaddingChar === -1 || firstPaddingChar === len - 1 || firstPaddingChar === len - 2 && str[len - 1] === "=";
291
+ }
292
+ function isAppiumCapability(caps) {
293
+ return Boolean(
294
+ caps && // @ts-expect-error outdated jsonwp cap
295
+ (caps.automationName || caps["appium:automationName"] || caps.deviceName || caps.appiumVersion)
296
+ );
297
+ }
298
+ function definesRemoteDriver(options) {
299
+ return Boolean(
300
+ options.protocol && options.protocol !== DEFAULT_PROTOCOL || options.hostname && options.hostname !== DEFAULT_HOSTNAME || Boolean(options.port) || options.path && options.path !== DEFAULT_PATH || Boolean(options.user && options.key)
301
+ );
302
+ }
303
+ function isChrome(browserName) {
304
+ return Boolean(browserName && SUPPORTED_BROWSERNAMES.chrome.includes(browserName.toLowerCase()));
305
+ }
306
+ function isSafari(browserName) {
307
+ return Boolean(browserName && SUPPORTED_BROWSERNAMES.safari.includes(browserName.toLowerCase()));
308
+ }
309
+ function isFirefox(browserName) {
310
+ return Boolean(browserName && SUPPORTED_BROWSERNAMES.firefox.includes(browserName.toLowerCase()));
311
+ }
312
+ function isEdge(browserName) {
313
+ return Boolean(browserName && SUPPORTED_BROWSERNAMES.edge.includes(browserName.toLowerCase()));
314
+ }
315
+ function getBrowserObject(elem) {
316
+ const elemObject = elem;
317
+ return elemObject.parent ? getBrowserObject(elemObject.parent) : elem;
318
+ }
319
+ async function enableFileLogging(outputDir) {
320
+ if (!outputDir) {
321
+ return;
322
+ }
323
+ await fs.mkdir(path.join(outputDir), { recursive: true });
324
+ process.env.WDIO_LOG_PATH = path.join(outputDir, "wdio.log");
325
+ }
326
+ var SCREENSHOT_REPLACEMENT, SCRIPT_PLACEHOLDER, REGEX_SCRIPT_NAME, SLASH, sleep;
327
+ var init_utils = __esm({
328
+ "src/utils.ts"() {
329
+ "use strict";
330
+ init_constants();
331
+ SCREENSHOT_REPLACEMENT = '"<Screenshot[base64]>"';
332
+ SCRIPT_PLACEHOLDER = '"<Script[base64]>"';
333
+ REGEX_SCRIPT_NAME = /return \((async )?function (\w+)/;
334
+ SLASH = "/";
335
+ sleep = (ms = 0) => new Promise((r) => setTimeout(r, ms));
336
+ }
337
+ });
338
+
339
+ // src/node/utils.ts
340
+ import os from "node:os";
341
+ import fs2 from "node:fs";
342
+ import fsp from "node:fs/promises";
343
+ import path2 from "node:path";
344
+ import cp from "node:child_process";
345
+ import decamelize from "decamelize";
346
+ import logger2 from "@wdio/logger";
347
+ import {
348
+ install,
349
+ canDownload,
350
+ resolveBuildId,
351
+ detectBrowserPlatform,
352
+ Browser as Browser2,
353
+ ChromeReleaseChannel,
354
+ computeExecutablePath
355
+ } from "@puppeteer/browsers";
356
+ import { download as downloadGeckodriver } from "geckodriver";
357
+ import { download as downloadEdgedriver } from "edgedriver";
358
+ import { locateChrome, locateFirefox, locateApp } from "locate-app";
359
+ function parseParams(params) {
360
+ return Object.entries(params).filter(([key]) => !EXCLUDED_PARAMS.includes(key)).map(([key, val]) => {
361
+ if (typeof val === "boolean" && !val) {
362
+ return "";
363
+ }
364
+ const vals = Array.isArray(val) ? val : [val];
365
+ return vals.map((v) => `--${decamelize(key, { separator: "-" })}${typeof v === "boolean" ? "" : `=${v}`}`);
366
+ }).flat().filter(Boolean);
367
+ }
368
+ function getBuildIdByChromePath(chromePath) {
369
+ if (!chromePath) {
370
+ return;
371
+ }
372
+ if (os.platform() === "win32") {
373
+ const versionPath = path2.dirname(chromePath);
374
+ const contents = fs2.readdirSync(versionPath);
375
+ const versions = contents.filter((a) => /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/g.test(a));
376
+ const oldest = versions.sort((a, b) => a > b ? -1 : 1)[0];
377
+ return oldest;
378
+ }
379
+ const versionString = cp.execSync(`"${chromePath}" --version --no-sandbox`).toString();
380
+ const versionSanitized = versionString.trim().split(" ").find((s) => s.split(".").length === 4);
381
+ if (!versionSanitized) {
382
+ throw new Error(`Couldn't find valid Chrome version from "${versionString}", please raise an issue in the WebdriverIO project (https://github.com/webdriverio/webdriverio/issues/new/choose)`);
383
+ }
384
+ return versionSanitized;
385
+ }
386
+ async function getBuildIdByFirefoxPath(firefoxPath) {
387
+ if (!firefoxPath) {
388
+ return;
389
+ }
390
+ if (os.platform() === "win32") {
391
+ const appPath = path2.dirname(firefoxPath);
392
+ const contents = (await fsp.readFile(path2.join(appPath, "application.ini"))).toString("utf-8");
393
+ return contents.split("\n").filter((line) => line.startsWith("Version=")).map((line) => line.replace("Version=", "").replace(/\r/, "")).pop();
394
+ }
395
+ const versionString = cp.execSync(`"${firefoxPath}" --version`).toString();
396
+ return versionString.trim().split(" ").pop()?.trim();
397
+ }
398
+ function locateChromeSafely() {
399
+ return locateChrome().catch(() => void 0);
400
+ }
401
+ async function setupPuppeteerBrowser(cacheDir, caps) {
402
+ caps.browserName = caps.browserName?.toLowerCase();
403
+ const browserName = caps.browserName === Browser2.FIREFOX ? Browser2.FIREFOX : caps.browserName === Browser2.CHROMIUM ? Browser2.CHROMIUM : Browser2.CHROME;
404
+ const exist = await fsp.access(cacheDir).then(() => true, () => false);
405
+ const isChromeOrChromium = browserName === Browser2.CHROME || caps.browserName === Browser2.CHROMIUM;
406
+ if (!exist) {
407
+ await fsp.mkdir(cacheDir, { recursive: true });
408
+ }
409
+ if (browserName === Browser2.CHROMIUM) {
410
+ caps.browserName = Browser2.CHROME;
411
+ }
412
+ const browserOptions = (isChromeOrChromium ? caps["goog:chromeOptions"] : caps["moz:firefoxOptions"]) || {};
413
+ if (typeof browserOptions.binary === "string") {
414
+ return {
415
+ executablePath: browserOptions.binary,
416
+ browserVersion: caps.browserVersion || (isChromeOrChromium ? getBuildIdByChromePath(browserOptions.binary) : await getBuildIdByFirefoxPath(browserOptions.binary))
417
+ };
418
+ }
419
+ const platform = detectBrowserPlatform();
420
+ if (!platform) {
421
+ throw new Error("The current platform is not supported.");
422
+ }
423
+ if (!caps.browserVersion) {
424
+ const executablePath2 = browserName === Browser2.CHROME ? await locateChromeSafely() : browserName === Browser2.CHROMIUM ? await locateApp({
425
+ appName: Browser2.CHROMIUM,
426
+ macOsName: Browser2.CHROMIUM,
427
+ linuxWhich: "chromium-browser"
428
+ }).catch(() => void 0) : await locateFirefox().catch(() => void 0);
429
+ const browserVersion2 = isChromeOrChromium ? getBuildIdByChromePath(executablePath2) : await getBuildIdByFirefoxPath(executablePath2);
430
+ if (browserVersion2) {
431
+ return {
432
+ executablePath: executablePath2,
433
+ browserVersion: browserVersion2
434
+ };
435
+ }
436
+ }
437
+ const tag = browserName === Browser2.CHROME ? caps.browserVersion || ChromeReleaseChannel.STABLE : caps.browserVersion || "latest";
438
+ const buildId = await resolveBuildId(browserName, platform, tag);
439
+ const installOptions = {
440
+ unpack: true,
441
+ cacheDir,
442
+ platform,
443
+ buildId,
444
+ browser: browserName,
445
+ downloadProgressCallback: (downloadedBytes, totalBytes) => downloadProgressCallback(`${browserName} (${buildId})`, downloadedBytes, totalBytes)
446
+ };
447
+ const isCombinationAvailable = await canDownload(installOptions);
448
+ if (!isCombinationAvailable) {
449
+ throw new Error(`Couldn't find a matching ${browserName} browser for tag "${buildId}" on platform "${platform}"`);
450
+ }
451
+ log.info(`Setting up ${browserName} v${buildId}`);
452
+ await _install(installOptions);
453
+ const executablePath = computeExecutablePath(installOptions);
454
+ let browserVersion = buildId;
455
+ if (browserName === Browser2.CHROMIUM) {
456
+ browserVersion = await resolveBuildId(Browser2.CHROME, platform, tag);
457
+ }
458
+ return { executablePath, browserVersion };
459
+ }
460
+ function getDriverOptions(caps) {
461
+ return caps["wdio:chromedriverOptions"] || caps["wdio:geckodriverOptions"] || caps["wdio:edgedriverOptions"] || // Safaridriver does not have any options as it already
462
+ // is installed on macOS
463
+ {};
464
+ }
465
+ function getCacheDir(options, caps) {
466
+ const driverOptions = getDriverOptions(caps);
467
+ return driverOptions.cacheDir || options.cacheDir || os.tmpdir();
468
+ }
469
+ function getMajorVersionFromString(fullVersion) {
470
+ let prefix;
471
+ if (fullVersion) {
472
+ prefix = fullVersion.match(/^[+-]?([0-9]+)/);
473
+ }
474
+ return prefix && prefix.length > 0 ? prefix[0] : "";
475
+ }
476
+ async function setupChromedriver(cacheDir, driverVersion) {
477
+ const platform = detectBrowserPlatform();
478
+ if (!platform) {
479
+ throw new Error("The current platform is not supported.");
480
+ }
481
+ const version = driverVersion || getBuildIdByChromePath(await locateChromeSafely()) || ChromeReleaseChannel.STABLE;
482
+ const buildId = await resolveBuildId(Browser2.CHROMEDRIVER, platform, version);
483
+ let executablePath = computeExecutablePath({
484
+ browser: Browser2.CHROMEDRIVER,
485
+ buildId,
486
+ platform,
487
+ cacheDir
488
+ });
489
+ const hasChromedriverInstalled = await fsp.access(executablePath).then(() => true, () => false);
490
+ if (!hasChromedriverInstalled) {
491
+ log.info(`Downloading Chromedriver v${buildId}`);
492
+ const chromedriverInstallOpts = {
493
+ cacheDir,
494
+ buildId,
495
+ platform,
496
+ browser: Browser2.CHROMEDRIVER,
497
+ unpack: true,
498
+ downloadProgressCallback: (downloadedBytes, totalBytes) => downloadProgressCallback("Chromedriver", downloadedBytes, totalBytes)
499
+ };
500
+ let knownBuild = buildId;
501
+ if (await canDownload(chromedriverInstallOpts)) {
502
+ await _install({ ...chromedriverInstallOpts, buildId });
503
+ log.info(`Download of Chromedriver v${buildId} was successful`);
504
+ } else {
505
+ log.warn(`Chromedriver v${buildId} don't exist, trying to find known good version...`);
506
+ knownBuild = await resolveBuildId(Browser2.CHROMEDRIVER, platform, getMajorVersionFromString(version));
507
+ if (knownBuild) {
508
+ await _install({ ...chromedriverInstallOpts, buildId: knownBuild });
509
+ log.info(`Download of Chromedriver v${knownBuild} was successful`);
510
+ } else {
511
+ throw new Error(`Couldn't download any known good version from Chromedriver major v${getMajorVersionFromString(version)}, requested full version - v${version}`);
512
+ }
513
+ }
514
+ executablePath = computeExecutablePath({
515
+ browser: Browser2.CHROMEDRIVER,
516
+ buildId: knownBuild,
517
+ platform,
518
+ cacheDir
519
+ });
520
+ } else {
521
+ log.info(`Using Chromedriver v${buildId} from cache directory ${cacheDir}`);
522
+ }
523
+ return { executablePath };
524
+ }
525
+ function setupGeckodriver(cacheDir, driverVersion) {
526
+ return downloadGeckodriver(driverVersion, cacheDir);
527
+ }
528
+ function setupEdgedriver(cacheDir, driverVersion) {
529
+ return downloadEdgedriver(driverVersion, cacheDir);
530
+ }
531
+ var log, EXCLUDED_PARAMS, canAccess, lastTimeCalled, downloadProgressCallback, _install;
532
+ var init_utils2 = __esm({
533
+ "src/node/utils.ts"() {
534
+ "use strict";
535
+ log = logger2("webdriver");
536
+ EXCLUDED_PARAMS = ["version", "help"];
537
+ canAccess = (file) => {
538
+ if (!file) {
539
+ return false;
540
+ }
541
+ try {
542
+ fs2.accessSync(file);
543
+ return true;
544
+ } catch (err) {
545
+ return false;
546
+ }
547
+ };
548
+ lastTimeCalled = Date.now();
549
+ downloadProgressCallback = (artifact, downloadedBytes, totalBytes) => {
550
+ if (Date.now() - lastTimeCalled < 1e3) {
551
+ return;
552
+ }
553
+ const percentage = (downloadedBytes / totalBytes * 100).toFixed(2);
554
+ log.progress(`Downloading ${artifact} ${percentage}%`);
555
+ lastTimeCalled = Date.now();
556
+ };
557
+ _install = async (args, retry = false) => {
558
+ await install(args).catch((err) => {
559
+ const error = `Failed downloading ${args.browser} v${args.buildId} using ${JSON.stringify(args)}: ${err.message}, retrying ...`;
560
+ if (retry) {
561
+ err.message += "\n" + error.replace(", retrying ...", "");
562
+ throw new Error(err);
563
+ }
564
+ log.error(error);
565
+ return _install(args, true);
566
+ });
567
+ log.progress("");
568
+ };
569
+ }
570
+ });
571
+
572
+ // src/node/startWebDriver.ts
573
+ import fs3 from "node:fs";
574
+ import path3 from "node:path";
575
+ import cp2 from "node:child_process";
576
+ import getPort from "get-port";
577
+ import waitPort from "wait-port";
578
+ import logger3 from "@wdio/logger";
579
+ import split2 from "split2";
580
+ import { deepmerge } from "deepmerge-ts";
581
+ import { start as startSafaridriver } from "safaridriver";
582
+ import { start as startGeckodriver } from "geckodriver";
583
+ import { start as startEdgedriver, findEdgePath } from "edgedriver";
584
+ async function startWebDriver(options) {
585
+ if (process.env.WDIO_SKIP_DRIVER_SETUP) {
586
+ options.hostname = "localhost";
587
+ options.port = 4321;
588
+ return;
589
+ }
590
+ let driverProcess;
591
+ let driver = "";
592
+ const start = Date.now();
593
+ const caps = options.capabilities.alwaysMatch || options.capabilities;
594
+ if (isAppiumCapability(caps)) {
595
+ return;
596
+ }
597
+ if (!caps.browserName) {
598
+ throw new Error(
599
+ `No "browserName" defined in capabilities nor hostname or port found!
600
+ If you like to run a local browser session make sure to pick from one of the following browser names: ${Object.values(SUPPORTED_BROWSERNAMES).flat(Infinity)}`
601
+ );
602
+ }
603
+ const port = await getPort();
604
+ const cacheDir = getCacheDir(options, caps);
605
+ if (isChrome(caps.browserName)) {
606
+ const chromedriverOptions = caps["wdio:chromedriverOptions"] || {};
607
+ const chromedriverBinary = chromedriverOptions.binary || process.env.CHROMEDRIVER_PATH;
608
+ const { executablePath: chromeExecuteablePath, browserVersion } = await setupPuppeteerBrowser(cacheDir, caps);
609
+ const { executablePath: chromedriverExcecuteablePath } = chromedriverBinary ? { executablePath: chromedriverBinary } : await setupChromedriver(cacheDir, browserVersion);
610
+ caps["goog:chromeOptions"] = deepmerge(
611
+ { binary: chromeExecuteablePath },
612
+ caps["goog:chromeOptions"] || {}
613
+ );
614
+ chromedriverOptions.allowedOrigins = chromedriverOptions.allowedOrigins || ["*"];
615
+ chromedriverOptions.allowedIps = chromedriverOptions.allowedIps || ["0.0.0.0"];
616
+ const driverParams = parseParams({ port, ...chromedriverOptions });
617
+ driverProcess = cp2.spawn(chromedriverExcecuteablePath, driverParams);
618
+ driver = `Chromedriver v${browserVersion} with params ${driverParams.join(" ")}`;
619
+ } else if (isSafari(caps.browserName)) {
620
+ const safaridriverOptions = caps["wdio:safaridriverOptions"] || {};
621
+ driver = "SafariDriver";
622
+ driverProcess = startSafaridriver({
623
+ useTechnologyPreview: Boolean(caps.browserName.match(/preview/i)),
624
+ ...safaridriverOptions,
625
+ port
626
+ });
627
+ } else if (isFirefox(caps.browserName)) {
628
+ const { executablePath } = await setupPuppeteerBrowser(cacheDir, caps);
629
+ caps["moz:firefoxOptions"] = deepmerge(
630
+ { binary: executablePath },
631
+ caps["moz:firefoxOptions"] || {}
632
+ );
633
+ delete caps.browserVersion;
634
+ const { binary, ...geckodriverOptions } = caps["wdio:geckodriverOptions"] || {};
635
+ if (binary) {
636
+ geckodriverOptions.customGeckoDriverPath = binary;
637
+ }
638
+ driver = "GeckoDriver";
639
+ driverProcess = await startGeckodriver({ ...geckodriverOptions, cacheDir, port, allowHosts: ["localhost"] });
640
+ } else if (isEdge(caps.browserName)) {
641
+ const { binary, ...edgedriverOptions } = caps["wdio:edgedriverOptions"] || {};
642
+ if (binary) {
643
+ edgedriverOptions.customEdgeDriverPath = binary;
644
+ }
645
+ driver = "EdgeDriver";
646
+ driverProcess = await startEdgedriver({ ...edgedriverOptions, cacheDir, port, allowedIps: ["0.0.0.0"] }).catch((err) => {
647
+ log2.warn(`Couldn't start EdgeDriver: ${err.message}, retry ...`);
648
+ return startEdgedriver({ ...edgedriverOptions, cacheDir, port });
649
+ });
650
+ caps.browserName = "MicrosoftEdge";
651
+ if (!caps["ms:edgeOptions"]?.binary) {
652
+ caps["ms:edgeOptions"] = caps["ms:edgeOptions"] || {};
653
+ caps["ms:edgeOptions"].binary = findEdgePath();
654
+ log2.info(`Found Edge binary at ${caps["ms:edgeOptions"].binary}`);
655
+ }
656
+ } else {
657
+ throw new Error(
658
+ `Unknown browser name "${caps.browserName}". Make sure to pick from one of the following ` + Object.values(SUPPORTED_BROWSERNAMES).flat(Infinity)
659
+ );
660
+ }
661
+ const logIdentifier = driver.split(" ").shift()?.toLowerCase() || "driver";
662
+ if (options.outputDir) {
663
+ const logFileName = process.env.WDIO_WORKER_ID ? `wdio-${process.env.WDIO_WORKER_ID}-${logIdentifier}.log` : `wdio-${logIdentifier}-${port}.log`;
664
+ const logFile = path3.resolve(options.outputDir, logFileName);
665
+ const logStream = fs3.createWriteStream(logFile, { flags: "w" });
666
+ driverProcess.stdout?.pipe(logStream);
667
+ driverProcess.stderr?.pipe(logStream);
668
+ } else {
669
+ const driverLog = logger3(logIdentifier);
670
+ driverProcess.stdout?.pipe(split2()).on("data", driverLog.info.bind(driverLog));
671
+ driverProcess.stderr?.pipe(split2()).on("data", driverLog.warn.bind(driverLog));
672
+ }
673
+ await waitPort({ port, output: "silent", timeout: DRIVER_WAIT_TIMEOUT }).catch((e) => {
674
+ throw new Error(`Timed out to connect to ${driver}: ${e.message}`);
675
+ });
676
+ options.hostname = "localhost";
677
+ options.port = port;
678
+ log2.info(`Started ${driver} in ${Date.now() - start}ms on port ${port}`);
679
+ return driverProcess;
680
+ }
681
+ var log2, DRIVER_WAIT_TIMEOUT;
682
+ var init_startWebDriver = __esm({
683
+ "src/node/startWebDriver.ts"() {
684
+ "use strict";
685
+ init_utils2();
686
+ init_utils();
687
+ init_constants();
688
+ log2 = logger3("@wdio/utils");
689
+ DRIVER_WAIT_TIMEOUT = 10 * 1e3;
690
+ }
691
+ });
692
+
693
+ // src/node/manager.ts
694
+ import logger4 from "@wdio/logger";
695
+ function mapCapabilities(options, caps, task, taskItemLabel) {
696
+ const capabilitiesToRequireSetup = (Array.isArray(caps) ? caps.map((cap) => {
697
+ const w3cCaps = cap;
698
+ const multiremoteCaps = cap;
699
+ const multiremoteInstanceNames = Object.keys(multiremoteCaps);
700
+ if (typeof multiremoteCaps[multiremoteInstanceNames[0]] === "object" && "capabilities" in multiremoteCaps[multiremoteInstanceNames[0]]) {
701
+ return Object.values(multiremoteCaps).map((c) => "alwaysMatch" in c.capabilities ? c.capabilities.alwaysMatch : c.capabilities);
702
+ }
703
+ if (w3cCaps.alwaysMatch) {
704
+ return w3cCaps.alwaysMatch;
705
+ }
706
+ return cap;
707
+ }).flat() : Object.values(caps).map((mrOpts) => {
708
+ const w3cCaps = mrOpts.capabilities;
709
+ if (w3cCaps.alwaysMatch) {
710
+ return w3cCaps.alwaysMatch;
711
+ }
712
+ return mrOpts.capabilities;
713
+ })).flat().filter((cap) => (
714
+ /**
715
+ * only set up driver if
716
+ */
717
+ // - capabilities are defined and not empty
718
+ cap && // - browserName is defined so we know it is a browser session
719
+ cap.browserName && // - we are not about to run a cloud session
720
+ !definesRemoteDriver(options) && // - we are not running Safari (driver already installed on macOS)
721
+ !isSafari(cap.browserName) && // - driver options don't define a binary path
722
+ !getDriverOptions(cap).binary && // - environment does not define a binary path
723
+ !(process.env.CHROMEDRIVER_PATH && isChrome(cap.browserName))
724
+ ));
725
+ if (capabilitiesToRequireSetup.length === 0) {
726
+ return;
727
+ }
728
+ const queueByBrowserName = capabilitiesToRequireSetup.reduce((queue, cap) => {
729
+ if (!cap.browserName) {
730
+ return queue;
731
+ }
732
+ if (!queue.has(cap.browserName)) {
733
+ queue.set(cap.browserName, /* @__PURE__ */ new Map());
734
+ }
735
+ const browserVersion = cap.browserVersion || UNDEFINED_BROWSER_VERSION;
736
+ queue.get(cap.browserName).set(browserVersion, cap);
737
+ return queue;
738
+ }, /* @__PURE__ */ new Map());
739
+ const driverToSetupString = Array.from(queueByBrowserName.entries()).map(([browserName, versions]) => `${browserName}@${Array.from(versions.keys()).map((bv) => bv || "stable").join(", ")}`).join(" - ");
740
+ log3.info(`Setting up ${taskItemLabel} for: ${driverToSetupString}`);
741
+ return Promise.all(
742
+ Array.from(queueByBrowserName.entries()).map(([browserName, queueByBrowserVersion]) => {
743
+ return Array.from(queueByBrowserVersion).map(([browserVersion, cap]) => task({
744
+ ...cap,
745
+ browserName,
746
+ ...browserVersion !== UNDEFINED_BROWSER_VERSION ? { browserVersion } : {}
747
+ }));
748
+ }).flat()
749
+ );
750
+ }
751
+ async function setupDriver(options, caps) {
752
+ return mapCapabilities(options, caps, async (cap) => {
753
+ const cacheDir = getCacheDir(options, cap);
754
+ if (isEdge(cap.browserName)) {
755
+ return setupEdgedriver(cacheDir, cap.browserVersion);
756
+ } else if (isFirefox(cap.browserName)) {
757
+ const version = cap.browserVersion === "latest" ? void 0 : cap.browserVersion;
758
+ return setupGeckodriver(cacheDir, version);
759
+ } else if (isChrome(cap.browserName)) {
760
+ return setupChromedriver(cacheDir, cap.browserVersion);
761
+ }
762
+ return Promise.resolve();
763
+ }, "browser driver" /* DRIVER */);
764
+ }
765
+ function setupBrowser(options, caps) {
766
+ return mapCapabilities(options, caps, async (cap) => {
767
+ const cacheDir = getCacheDir(options, cap);
768
+ if (isEdge(cap.browserName)) {
769
+ return Promise.resolve();
770
+ } else if (isChrome(cap.browserName) || isFirefox(cap.browserName)) {
771
+ return setupPuppeteerBrowser(cacheDir, cap);
772
+ }
773
+ return Promise.resolve();
774
+ }, "browser binaries" /* BROWSER */);
775
+ }
776
+ var log3, UNDEFINED_BROWSER_VERSION;
777
+ var init_manager = __esm({
778
+ "src/node/manager.ts"() {
779
+ "use strict";
780
+ init_utils2();
781
+ init_utils();
782
+ log3 = logger4("@wdio/utils");
783
+ UNDEFINED_BROWSER_VERSION = null;
784
+ }
785
+ });
786
+
787
+ // src/node/index.ts
788
+ var node_exports = {};
789
+ __export(node_exports, {
790
+ canAccess: () => canAccess,
791
+ setupBrowser: () => setupBrowser,
792
+ setupDriver: () => setupDriver,
793
+ startWebDriver: () => startWebDriver
794
+ });
795
+ var init_node = __esm({
796
+ "src/node/index.ts"() {
797
+ "use strict";
798
+ init_startWebDriver();
799
+ init_manager();
800
+ init_utils2();
801
+ }
802
+ });
803
+
804
+ // src/monad.ts
805
+ init_utils();
806
+ import { EventEmitter } from "node:events";
807
+ import logger from "@wdio/logger";
808
+ import { MESSAGE_TYPES } from "@wdio/types";
809
+ var SCOPE_TYPES = {
810
+ browser: (
811
+ /* istanbul ignore next */
812
+ function Browser() {
813
+ }
814
+ ),
815
+ element: (
816
+ /* istanbul ignore next */
817
+ function Element() {
818
+ }
819
+ )
820
+ };
821
+ function WebDriver(options, modifier, propertiesObject = {}) {
822
+ const scopeType = SCOPE_TYPES[propertiesObject.scope?.value || "browser"];
823
+ delete propertiesObject.scope;
824
+ const prototype = Object.create(scopeType.prototype);
825
+ const log7 = logger("webdriver");
826
+ const eventHandler = new EventEmitter();
827
+ const EVENTHANDLER_FUNCTIONS = Object.getPrototypeOf(eventHandler);
828
+ function unit(sessionId, commandWrapper) {
829
+ propertiesObject.commandList = { value: Object.keys(propertiesObject) };
830
+ propertiesObject.options = { value: options };
831
+ propertiesObject.requestedCapabilities = { value: options.requestedCapabilities };
832
+ if (typeof commandWrapper === "function") {
833
+ for (const [commandName, { value }] of Object.entries(propertiesObject)) {
834
+ if (typeof value !== "function" || Object.keys(EVENTHANDLER_FUNCTIONS).includes(commandName)) {
835
+ continue;
836
+ }
837
+ propertiesObject[commandName].value = commandWrapper(commandName, value, propertiesObject);
838
+ propertiesObject[commandName].configurable = true;
839
+ }
840
+ }
841
+ overwriteElementCommands.call(this, propertiesObject);
842
+ const { puppeteer, ...propertiesObjectWithoutPuppeteer } = propertiesObject;
843
+ propertiesObject.__propertiesObject__ = { value: propertiesObjectWithoutPuppeteer };
844
+ let client = Object.create(prototype, propertiesObject);
845
+ client.sessionId = sessionId;
846
+ if (scopeType.name === "Browser") {
847
+ client.capabilities = options.capabilities;
848
+ }
849
+ if (typeof modifier === "function") {
850
+ client = modifier(client, options);
851
+ }
852
+ client.addCommand = function(name, func, attachToElement = false, proto, instances) {
853
+ const customCommand = typeof commandWrapper === "function" ? commandWrapper(name, func) : func;
854
+ if (attachToElement) {
855
+ if (instances) {
856
+ Object.values(instances).forEach((instance) => {
857
+ instance.__propertiesObject__[name] = {
858
+ value: customCommand
859
+ };
860
+ });
861
+ }
862
+ this.__propertiesObject__[name] = { value: customCommand };
863
+ } else {
864
+ unit.lift(name, customCommand, proto);
865
+ }
866
+ if (typeof process.send === "function" && process.env.WDIO_WORKER_ID) {
867
+ const message = {
868
+ origin: "worker",
869
+ name: "workerEvent",
870
+ args: {
871
+ type: MESSAGE_TYPES.customCommand,
872
+ value: {
873
+ commandName: name,
874
+ cid: process.env.WDIO_WORKER_ID
875
+ }
876
+ }
877
+ };
878
+ process.send(message);
879
+ }
880
+ };
881
+ client.overwriteCommand = function(name, func, attachToElement = false, proto, instances) {
882
+ const customCommand = typeof commandWrapper === "function" ? commandWrapper(name, func) : func;
883
+ if (attachToElement) {
884
+ if (instances) {
885
+ Object.values(instances).forEach((instance) => {
886
+ instance.__propertiesObject__.__elementOverrides__.value[name] = customCommand;
887
+ });
888
+ } else {
889
+ this.__propertiesObject__.__elementOverrides__.value[name] = customCommand;
890
+ }
891
+ } else if (client[name]) {
892
+ const origCommand = client[name];
893
+ delete client[name];
894
+ unit.lift(name, customCommand, proto, (...args) => origCommand.apply(this, args));
895
+ } else {
896
+ throw new Error("overwriteCommand: no command to be overwritten: " + name);
897
+ }
898
+ };
899
+ return client;
900
+ }
901
+ unit.lift = function(name, func, proto, origCommand) {
902
+ (proto || prototype)[name] = function next(...args) {
903
+ log7.info("COMMAND", commandCallStructure(name, args));
904
+ Object.defineProperty(func, "name", {
905
+ value: name,
906
+ writable: false
907
+ });
908
+ const result = func.apply(this, origCommand ? [origCommand, ...args] : args);
909
+ Promise.resolve(result).then((res) => {
910
+ const elem = res;
911
+ let resultLog = res;
912
+ if (elem instanceof SCOPE_TYPES.element) {
913
+ resultLog = `WebdriverIO.Element<${elem.elementId || elem.selector}>`;
914
+ } else if (res instanceof SCOPE_TYPES.browser) {
915
+ resultLog = "WebdriverIO.Browser";
916
+ }
917
+ log7.info("RESULT", resultLog);
918
+ this.emit("result", { name, result: res });
919
+ }).catch(() => {
920
+ });
921
+ return result;
922
+ };
923
+ };
924
+ for (const eventCommand in EVENTHANDLER_FUNCTIONS) {
925
+ prototype[eventCommand] = function(...args) {
926
+ const method = eventCommand;
927
+ if (method === "on" && args[0] === "dialog") {
928
+ eventHandler.emit("_dialogListenerRegistered");
929
+ }
930
+ if (method === "off" && args[0] === "dialog") {
931
+ eventHandler.emit("_dialogListenerRemoved");
932
+ }
933
+ eventHandler[method]?.(...args);
934
+ return this;
935
+ };
936
+ }
937
+ return unit;
938
+ }
939
+
940
+ // src/initializePlugin.ts
941
+ init_utils();
942
+ async function initializePlugin(name, type) {
943
+ if (name[0] === "@" || isAbsolute(name)) {
944
+ const service = await safeImport(name);
945
+ if (service) {
946
+ return service;
947
+ }
948
+ }
949
+ if (typeof type !== "string") {
950
+ throw new Error("No plugin type provided");
951
+ }
952
+ const scopedPlugin = await safeImport(`@wdio/${name.toLowerCase()}-${type}`);
953
+ if (scopedPlugin) {
954
+ return scopedPlugin;
955
+ }
956
+ const plugin = await safeImport(`wdio-${name.toLowerCase()}-${type}`);
957
+ if (plugin) {
958
+ return plugin;
959
+ }
960
+ throw new Error(
961
+ `Couldn't find plugin "${name}" ${type}, neither as wdio scoped package "@wdio/${name.toLowerCase()}-${type}" nor as community package "wdio-${name.toLowerCase()}-${type}". Please make sure you have it installed!`
962
+ );
963
+ }
964
+
965
+ // src/startWebDriver.ts
966
+ init_utils();
967
+ import logger5 from "@wdio/logger";
968
+ var log4 = logger5("@wdio/utils");
969
+ async function startWebDriver2(options) {
970
+ if (definesRemoteDriver(options)) {
971
+ log4.info(`Connecting to existing driver at ${options.protocol}://${options.hostname}:${options.port}${options.path}`);
972
+ return;
973
+ }
974
+ if (globalThis.process) {
975
+ const { startWebDriver: startWebDriver3 } = await Promise.resolve().then(() => (init_node(), node_exports));
976
+ return startWebDriver3(options);
977
+ }
978
+ throw new Error("Please provide a valid `hostname` and `port` to start WebDriver sessions in the browser!");
979
+ }
980
+
981
+ // src/initializeServices.ts
982
+ import logger6 from "@wdio/logger";
983
+ var log5 = logger6("@wdio/utils:initializeServices");
984
+ async function initializeServices(services) {
985
+ const initializedServices = [];
986
+ for (const [serviceName, serviceConfig = {}] of services) {
987
+ if (typeof serviceName === "object") {
988
+ log5.debug("initialize custom initiated service");
989
+ initializedServices.push([serviceName, {}]);
990
+ continue;
991
+ }
992
+ if (typeof serviceName === "function") {
993
+ log5.debug(`initialize custom service "${serviceName.name}"`);
994
+ initializedServices.push([serviceName, serviceConfig]);
995
+ continue;
996
+ }
997
+ log5.debug(`initialize service "${serviceName}" as NPM package`);
998
+ const service = await initializePlugin(serviceName, "service");
999
+ initializedServices.push([service, serviceConfig, serviceName]);
1000
+ }
1001
+ return initializedServices;
1002
+ }
1003
+ function sanitizeServiceArray(service) {
1004
+ return Array.isArray(service) ? service : [service, {}];
1005
+ }
1006
+ async function initializeLauncherService(config, caps) {
1007
+ const ignoredWorkerServices = [];
1008
+ const launcherServices = [];
1009
+ let serviceLabelToBeInitialised = "unknown";
1010
+ try {
1011
+ const services = await initializeServices(config.services.map(sanitizeServiceArray));
1012
+ for (const [service, serviceConfig, serviceName] of services) {
1013
+ if (typeof service === "object" && !serviceName) {
1014
+ serviceLabelToBeInitialised = "object";
1015
+ launcherServices.push(service);
1016
+ continue;
1017
+ }
1018
+ const Launcher = service.launcher;
1019
+ if (typeof Launcher === "function" && serviceName) {
1020
+ serviceLabelToBeInitialised = `"${serviceName}"`;
1021
+ launcherServices.push(new Launcher(serviceConfig, caps, config));
1022
+ }
1023
+ if (typeof service === "function" && !serviceName) {
1024
+ serviceLabelToBeInitialised = `"${service.constructor?.name || service.toString()}"`;
1025
+ launcherServices.push(new service(serviceConfig, caps, config));
1026
+ }
1027
+ if (serviceName && typeof service.default !== "function" && typeof service !== "function") {
1028
+ ignoredWorkerServices.push(serviceName);
1029
+ }
1030
+ }
1031
+ } catch (err) {
1032
+ throw new Error(`Failed to initialise launcher service ${serviceLabelToBeInitialised}: ${err.stack}`);
1033
+ }
1034
+ return { ignoredWorkerServices, launcherServices };
1035
+ }
1036
+ async function initializeWorkerService(config, caps, ignoredWorkerServices = []) {
1037
+ let serviceLabelToBeInitialised = "unknown";
1038
+ const initializedServices = [];
1039
+ const workerServices = config.services.map(sanitizeServiceArray).filter(([serviceName]) => !ignoredWorkerServices.includes(serviceName));
1040
+ try {
1041
+ const services = await initializeServices(workerServices);
1042
+ for (const [service, serviceConfig, serviceName] of services) {
1043
+ if (typeof service === "object" && !serviceName) {
1044
+ serviceLabelToBeInitialised = "object";
1045
+ initializedServices.push(service);
1046
+ continue;
1047
+ }
1048
+ const Service = service.default || service;
1049
+ if (typeof Service === "function") {
1050
+ serviceLabelToBeInitialised = serviceName || Service.constructor?.name || Service.toString();
1051
+ initializedServices.push(new Service(serviceConfig, caps, config));
1052
+ continue;
1053
+ }
1054
+ }
1055
+ return initializedServices;
1056
+ } catch (err) {
1057
+ throw new Error(`Failed to initialise service ${serviceLabelToBeInitialised}: ${err.stack}`);
1058
+ }
1059
+ }
1060
+
1061
+ // src/index.ts
1062
+ init_utils();
1063
+
1064
+ // src/shim.ts
1065
+ import logger7 from "@wdio/logger";
1066
+
1067
+ // src/pIteration.ts
1068
+ var pIteration_exports = {};
1069
+ __export(pIteration_exports, {
1070
+ every: () => every,
1071
+ everySeries: () => everySeries,
1072
+ filter: () => filter,
1073
+ filterSeries: () => filterSeries,
1074
+ find: () => find,
1075
+ findIndex: () => findIndex,
1076
+ findIndexSeries: () => findIndexSeries,
1077
+ findSeries: () => findSeries,
1078
+ forEach: () => forEach,
1079
+ forEachSeries: () => forEachSeries,
1080
+ map: () => map,
1081
+ mapSeries: () => mapSeries,
1082
+ reduce: () => reduce,
1083
+ some: () => some,
1084
+ someSeries: () => someSeries
1085
+ });
1086
+ var forEach = async (array, callback, thisArg) => {
1087
+ const promiseArray = [];
1088
+ for (let i = 0; i < array.length; i++) {
1089
+ if (i in array) {
1090
+ const p = Promise.resolve(array[i]).then((currentValue) => {
1091
+ return callback.call(thisArg || void 0, currentValue, i, array);
1092
+ });
1093
+ promiseArray.push(p);
1094
+ }
1095
+ }
1096
+ await Promise.all(promiseArray);
1097
+ };
1098
+ var forEachSeries = async (array, callback, thisArg) => {
1099
+ for (let i = 0; i < array.length; i++) {
1100
+ if (i in array) {
1101
+ await callback.call(thisArg || void 0, await array[i], i, array);
1102
+ }
1103
+ }
1104
+ };
1105
+ var map = async (array, callback, thisArg) => {
1106
+ const promiseArray = [];
1107
+ for (let i = 0; i < array.length; i++) {
1108
+ if (i in array) {
1109
+ promiseArray[i] = Promise.resolve(array[i]).then((currentValue) => {
1110
+ return callback.call(thisArg || void 0, currentValue, i, array);
1111
+ });
1112
+ }
1113
+ }
1114
+ return Promise.all(promiseArray);
1115
+ };
1116
+ var mapSeries = async (array, callback, thisArg) => {
1117
+ const result = [];
1118
+ for (let i = 0; i < array.length; i++) {
1119
+ if (i in array) {
1120
+ result[i] = await callback.call(thisArg || void 0, await array[i], i, array);
1121
+ }
1122
+ }
1123
+ return result;
1124
+ };
1125
+ var find = (array, callback, thisArg) => {
1126
+ return new Promise((resolve, reject) => {
1127
+ if (array.length === 0) {
1128
+ return resolve(void 0);
1129
+ }
1130
+ let counter = 1;
1131
+ for (let i = 0; i < array.length; i++) {
1132
+ const check = (found) => {
1133
+ if (found) {
1134
+ resolve(array[i]);
1135
+ } else if (counter === array.length) {
1136
+ resolve(void 0);
1137
+ }
1138
+ counter++;
1139
+ };
1140
+ Promise.resolve(array[i]).then((elem) => callback.call(thisArg || void 0, elem, i, array)).then(check).catch(reject);
1141
+ }
1142
+ });
1143
+ };
1144
+ var findSeries = async (array, callback, thisArg) => {
1145
+ for (let i = 0; i < array.length; i++) {
1146
+ if (await callback.call(thisArg || void 0, await array[i], i, array)) {
1147
+ return array[i];
1148
+ }
1149
+ }
1150
+ };
1151
+ var findIndex = (array, callback, thisArg) => {
1152
+ return new Promise((resolve, reject) => {
1153
+ if (array.length === 0) {
1154
+ return resolve(-1);
1155
+ }
1156
+ let counter = 1;
1157
+ for (let i = 0; i < array.length; i++) {
1158
+ const check = (found) => {
1159
+ if (found) {
1160
+ resolve(i);
1161
+ } else if (counter === array.length) {
1162
+ resolve(-1);
1163
+ }
1164
+ counter++;
1165
+ };
1166
+ Promise.resolve(array[i]).then((elem) => callback.call(thisArg || void 0, elem, i, array)).then(check).catch(reject);
1167
+ }
1168
+ });
1169
+ };
1170
+ var findIndexSeries = async (array, callback, thisArg) => {
1171
+ for (let i = 0; i < array.length; i++) {
1172
+ if (await callback.call(thisArg || void 0, await array[i], i, array)) {
1173
+ return i;
1174
+ }
1175
+ }
1176
+ };
1177
+ var some = (array, callback, thisArg) => {
1178
+ return new Promise((resolve, reject) => {
1179
+ if (array.length === 0) {
1180
+ return resolve(false);
1181
+ }
1182
+ let counter = 1;
1183
+ for (let i = 0; i < array.length; i++) {
1184
+ if (!(i in array)) {
1185
+ counter++;
1186
+ continue;
1187
+ }
1188
+ const check = (found) => {
1189
+ if (found) {
1190
+ resolve(true);
1191
+ } else if (counter === array.length) {
1192
+ resolve(false);
1193
+ }
1194
+ counter++;
1195
+ };
1196
+ Promise.resolve(array[i]).then((elem) => callback.call(thisArg || void 0, elem, i, array)).then(check).catch(reject);
1197
+ }
1198
+ });
1199
+ };
1200
+ var someSeries = async (array, callback, thisArg) => {
1201
+ for (let i = 0; i < array.length; i++) {
1202
+ if (i in array && await callback.call(thisArg || void 0, await array[i], i, array)) {
1203
+ return true;
1204
+ }
1205
+ }
1206
+ return false;
1207
+ };
1208
+ var every = (array, callback, thisArg) => {
1209
+ return new Promise((resolve, reject) => {
1210
+ if (array.length === 0) {
1211
+ return resolve(true);
1212
+ }
1213
+ let counter = 1;
1214
+ for (let i = 0; i < array.length; i++) {
1215
+ if (!(i in array)) {
1216
+ counter++;
1217
+ continue;
1218
+ }
1219
+ const check = (found) => {
1220
+ if (!found) {
1221
+ resolve(false);
1222
+ } else if (counter === array.length) {
1223
+ resolve(true);
1224
+ }
1225
+ counter++;
1226
+ };
1227
+ Promise.resolve(array[i]).then((elem) => callback.call(thisArg || void 0, elem, i, array)).then(check).catch(reject);
1228
+ }
1229
+ });
1230
+ };
1231
+ var everySeries = async (array, callback, thisArg) => {
1232
+ for (let i = 0; i < array.length; i++) {
1233
+ if (i in array && !await callback.call(thisArg || void 0, await array[i], i, array)) {
1234
+ return false;
1235
+ }
1236
+ }
1237
+ return true;
1238
+ };
1239
+ var filter = (array, callback, thisArg) => {
1240
+ return new Promise((resolve, reject) => {
1241
+ const promiseArray = [];
1242
+ for (let i = 0; i < array.length; i++) {
1243
+ if (i in array) {
1244
+ promiseArray[i] = Promise.resolve(array[i]).then((currentValue) => {
1245
+ return callback.call(thisArg || void 0, currentValue, i, array);
1246
+ }).catch(reject);
1247
+ }
1248
+ }
1249
+ return Promise.all(
1250
+ promiseArray.map(async (p, i) => {
1251
+ if (await p) {
1252
+ return await array[i];
1253
+ }
1254
+ return void 0;
1255
+ })
1256
+ ).then(
1257
+ (result) => result.filter((val) => typeof val !== "undefined")
1258
+ ).then(resolve, reject);
1259
+ });
1260
+ };
1261
+ var filterSeries = async (array, callback, thisArg) => {
1262
+ const result = [];
1263
+ for (let i = 0; i < array.length; i++) {
1264
+ if (i in array && await callback.call(thisArg || void 0, await array[i], i, array)) {
1265
+ result.push(await array[i]);
1266
+ }
1267
+ }
1268
+ return result;
1269
+ };
1270
+ var reduce = async (array, callback, initialValue) => {
1271
+ if (array.length === 0 && initialValue === void 0) {
1272
+ throw TypeError("Reduce of empty array with no initial value");
1273
+ }
1274
+ let i;
1275
+ let previousValue;
1276
+ if (initialValue !== void 0) {
1277
+ previousValue = initialValue;
1278
+ i = 0;
1279
+ } else {
1280
+ previousValue = array[0];
1281
+ i = 1;
1282
+ }
1283
+ for (i; i < array.length; i++) {
1284
+ if (i in array) {
1285
+ previousValue = await callback(await previousValue, await array[i], i, array);
1286
+ }
1287
+ }
1288
+ return previousValue;
1289
+ };
1290
+
1291
+ // src/shim.ts
1292
+ init_utils();
1293
+ var log6 = logger7("@wdio/utils:shim");
1294
+ var inCommandHook = false;
1295
+ var ELEMENT_QUERY_COMMANDS = [
1296
+ "$",
1297
+ "$$",
1298
+ "custom$",
1299
+ "custom$$",
1300
+ "shadow$",
1301
+ "shadow$$",
1302
+ "react$",
1303
+ "react$$",
1304
+ "nextElement",
1305
+ "previousElement",
1306
+ "parentElement"
1307
+ ];
1308
+ var ELEMENT_PROPS = [
1309
+ "elementId",
1310
+ "error",
1311
+ "selector",
1312
+ "parent",
1313
+ "index",
1314
+ "isReactElement",
1315
+ "length"
1316
+ ];
1317
+ var ACTION_COMMANDS = ["action", "actions"];
1318
+ var PROMISE_METHODS = ["then", "catch", "finally"];
1319
+ var ELEMENT_RETURN_COMMANDS = ["getElement", "getElements"];
1320
+ var TIME_BUFFER = 3;
1321
+ async function executeHooksWithArgs(hookName, hooks = [], args = []) {
1322
+ if (!Array.isArray(hooks)) {
1323
+ hooks = [hooks];
1324
+ }
1325
+ if (!Array.isArray(args)) {
1326
+ args = [args];
1327
+ }
1328
+ const hooksPromises = hooks.map((hook) => new Promise((resolve, reject) => {
1329
+ let result2;
1330
+ try {
1331
+ result2 = hook.apply(this, args);
1332
+ } catch (e) {
1333
+ if (/^(sync|async) skip; aborting execution$/.test(e.message)) {
1334
+ return reject();
1335
+ }
1336
+ if (/^=> marked Pending/.test(e)) {
1337
+ return reject(e);
1338
+ }
1339
+ log6.error(e.stack);
1340
+ return resolve(e);
1341
+ }
1342
+ if (result2 && typeof result2.then === "function") {
1343
+ return result2.then(resolve, (e) => {
1344
+ log6.error(e.stack || e.message);
1345
+ resolve(e);
1346
+ });
1347
+ }
1348
+ resolve(result2);
1349
+ }));
1350
+ const start = Date.now();
1351
+ const result = await Promise.all(hooksPromises);
1352
+ if (hooksPromises.length) {
1353
+ log6.debug(`Finished to run "${hookName}" hook in ${Date.now() - start}ms`);
1354
+ }
1355
+ return result;
1356
+ }
1357
+ function wrapCommand(commandName, fn) {
1358
+ async function wrapCommandFn(...args) {
1359
+ const beforeHookArgs = [commandName, args];
1360
+ if (!inCommandHook && this.options.beforeCommand) {
1361
+ inCommandHook = true;
1362
+ await executeHooksWithArgs.call(this, "beforeCommand", this.options.beforeCommand, beforeHookArgs);
1363
+ inCommandHook = false;
1364
+ }
1365
+ let commandResult;
1366
+ let commandError;
1367
+ try {
1368
+ commandResult = await fn.apply(this, args);
1369
+ } catch (err) {
1370
+ commandError = err;
1371
+ }
1372
+ if (!inCommandHook && this.options.afterCommand) {
1373
+ inCommandHook = true;
1374
+ const afterHookArgs = [...beforeHookArgs, commandResult, commandError];
1375
+ await executeHooksWithArgs.call(this, "afterCommand", this.options.afterCommand, afterHookArgs);
1376
+ inCommandHook = false;
1377
+ }
1378
+ if (commandError) {
1379
+ throw commandError;
1380
+ }
1381
+ return commandResult;
1382
+ }
1383
+ function wrapElementFn(promise, cmd, args, prevInnerArgs) {
1384
+ return new Proxy(
1385
+ Promise.resolve(promise).then((ctx) => cmd.call(ctx, ...args)),
1386
+ {
1387
+ get: (target, prop) => {
1388
+ if (typeof prop === "symbol") {
1389
+ return () => ({
1390
+ i: 0,
1391
+ target,
1392
+ async next() {
1393
+ const elems = await this.target;
1394
+ if (!Array.isArray(elems)) {
1395
+ throw new Error("Can not iterate over non array");
1396
+ }
1397
+ if (this.i < elems.length) {
1398
+ return { value: elems[this.i++], done: false };
1399
+ }
1400
+ return { done: true };
1401
+ }
1402
+ });
1403
+ }
1404
+ const numValue = parseInt(prop, 10);
1405
+ if (!isNaN(numValue)) {
1406
+ return wrapElementFn(
1407
+ target,
1408
+ /**
1409
+ * `this` is an array of WebdriverIO elements
1410
+ */
1411
+ function(index) {
1412
+ if (index >= this.length) {
1413
+ const browser = getBrowserObject(this);
1414
+ return browser.waitUntil(async () => {
1415
+ const elems = await this.parent[this.foundWith](this.selector);
1416
+ if (elems.length > index) {
1417
+ return elems[index];
1418
+ }
1419
+ return false;
1420
+ }, {
1421
+ timeout: browser.options.waitforTimeout,
1422
+ timeoutMsg: `Index out of bounds! $$(${this.selector}) returned only ${this.length} elements.`
1423
+ });
1424
+ }
1425
+ return this[index];
1426
+ },
1427
+ [prop],
1428
+ { prop, args }
1429
+ );
1430
+ }
1431
+ if (ELEMENT_QUERY_COMMANDS.includes(prop) || prop.endsWith("$")) {
1432
+ return wrapCommand(prop, function(...args2) {
1433
+ return this[prop].apply(this, args2);
1434
+ });
1435
+ }
1436
+ if (commandName.endsWith("$$") && typeof pIteration_exports[prop] === "function") {
1437
+ return (mapIterator) => wrapElementFn(
1438
+ target,
1439
+ function(mapIterator2) {
1440
+ return pIteration_exports[prop](this, mapIterator2);
1441
+ },
1442
+ [mapIterator]
1443
+ );
1444
+ }
1445
+ if (ELEMENT_PROPS.includes(prop)) {
1446
+ return target.then((res) => res[prop]);
1447
+ }
1448
+ if (PROMISE_METHODS.includes(prop)) {
1449
+ return target[prop].bind(target);
1450
+ }
1451
+ if (ELEMENT_RETURN_COMMANDS.includes(prop)) {
1452
+ return () => target;
1453
+ }
1454
+ return (...args2) => target.then(async (elem) => {
1455
+ if (!elem) {
1456
+ let errMsg = "Element could not be found";
1457
+ const prevElem = await promise;
1458
+ if (Array.isArray(prevElem) && prevInnerArgs && prevInnerArgs.prop === "get") {
1459
+ errMsg = `Index out of bounds! $$(${prevInnerArgs.args[0]}) returned only ${prevElem.length} elements.`;
1460
+ }
1461
+ throw new Error(errMsg);
1462
+ }
1463
+ if (prop === "toJSON") {
1464
+ return { ELEMENT: elem.elementId };
1465
+ }
1466
+ if (typeof elem[prop] !== "function") {
1467
+ throw new Error(`Can't call "${prop}" on element with selector "${elem.selector}", it is not a function`);
1468
+ }
1469
+ return elem[prop](...args2);
1470
+ });
1471
+ }
1472
+ }
1473
+ );
1474
+ }
1475
+ function chainElementQuery(...args) {
1476
+ return wrapElementFn(this, wrapCommandFn, args);
1477
+ }
1478
+ return function(...args) {
1479
+ const command = ELEMENT_QUERY_COMMANDS.includes(commandName) || commandName.endsWith("$") ? chainElementQuery : ACTION_COMMANDS.includes(commandName) ? fn : wrapCommandFn;
1480
+ return command.apply(this, args);
1481
+ };
1482
+ }
1483
+ async function executeAsync(fn, retries, args = [], timeout = 2e4) {
1484
+ this.wdioRetries = retries.attempts;
1485
+ try {
1486
+ const _timeout = (this?._runnable?._timeout || globalThis.jasmine?.DEFAULT_TIMEOUT_INTERVAL || timeout) - TIME_BUFFER;
1487
+ let done = false;
1488
+ const result = await Promise.race([
1489
+ fn.apply(this, args),
1490
+ new Promise((resolve, reject) => {
1491
+ setTimeout(() => {
1492
+ if (done) {
1493
+ resolve();
1494
+ } else {
1495
+ reject(new Error("Timeout"));
1496
+ }
1497
+ }, _timeout);
1498
+ })
1499
+ ]);
1500
+ done = true;
1501
+ if (result !== null && typeof result === "object" && "finally" in result && typeof result.finally === "function") {
1502
+ result.catch((err) => err);
1503
+ }
1504
+ return await result;
1505
+ } catch (err) {
1506
+ if (retries.limit > retries.attempts) {
1507
+ retries.attempts++;
1508
+ return await executeAsync.call(this, fn, retries, args);
1509
+ }
1510
+ throw err;
1511
+ }
1512
+ }
1513
+
1514
+ // src/test-framework/errorHandler.ts
1515
+ var logHookError = (hookName, hookResults = [], cid) => {
1516
+ const result = hookResults.find((result2) => result2 instanceof Error);
1517
+ if (typeof result === "undefined") {
1518
+ return;
1519
+ }
1520
+ const error = { message: result.message };
1521
+ const content = {
1522
+ cid,
1523
+ error,
1524
+ fullTitle: `${hookName} Hook`,
1525
+ type: "hook",
1526
+ state: "fail"
1527
+ };
1528
+ if (globalThis.process && typeof globalThis.process.send === "function") {
1529
+ globalThis.process.send({
1530
+ origin: "reporter",
1531
+ name: "printFailureMessage",
1532
+ content
1533
+ });
1534
+ }
1535
+ };
1536
+
1537
+ // src/test-framework/testFnWrapper.ts
1538
+ var STACKTRACE_FILTER = [
1539
+ "node_modules/webdriver/",
1540
+ "node_modules/webdriverio/",
1541
+ "node_modules/@wdio/",
1542
+ "(internal/process/task",
1543
+ "(node:internal/process/task"
1544
+ ];
1545
+ var testFnWrapper = function(...args) {
1546
+ return testFrameworkFnWrapper.call(this, { executeHooksWithArgs, executeAsync }, ...args);
1547
+ };
1548
+ var testFrameworkFnWrapper = async function({ executeHooksWithArgs: executeHooksWithArgs2, executeAsync: executeAsync2 }, type, { specFn, specFnArgs }, { beforeFn, beforeFnArgs }, { afterFn, afterFnArgs }, cid, repeatTest = 0, hookName, timeout) {
1549
+ const retries = { attempts: 0, limit: repeatTest };
1550
+ const beforeArgs = beforeFnArgs(this);
1551
+ if (type === "Hook" && hookName) {
1552
+ beforeArgs.push(hookName);
1553
+ }
1554
+ await logHookError(`Before${type}`, await executeHooksWithArgs2(`before${type}`, beforeFn, beforeArgs), cid);
1555
+ let result;
1556
+ let error;
1557
+ const testStart = Date.now();
1558
+ try {
1559
+ result = await executeAsync2.call(this, specFn, retries, specFnArgs, timeout);
1560
+ if (globalThis._jasmineTestResult !== void 0) {
1561
+ result = globalThis._jasmineTestResult;
1562
+ globalThis._jasmineTestResult = void 0;
1563
+ }
1564
+ if (globalThis._wdioDynamicJasmineResultErrorList?.length > 0) {
1565
+ globalThis._wdioDynamicJasmineResultErrorList[0].stack = filterStackTrace(globalThis._wdioDynamicJasmineResultErrorList[0].stack);
1566
+ error = globalThis._wdioDynamicJasmineResultErrorList[0];
1567
+ globalThis._wdioDynamicJasmineResultErrorList = void 0;
1568
+ }
1569
+ } catch (err) {
1570
+ if (err.stack) {
1571
+ err.stack = filterStackTrace(err.stack);
1572
+ }
1573
+ error = err;
1574
+ }
1575
+ const duration = Date.now() - testStart;
1576
+ const afterArgs = afterFnArgs(this);
1577
+ afterArgs.push({
1578
+ retries,
1579
+ error,
1580
+ result,
1581
+ duration,
1582
+ passed: !error
1583
+ });
1584
+ if (type === "Hook" && hookName) {
1585
+ afterArgs.push(hookName);
1586
+ }
1587
+ await logHookError(`After${type}`, await executeHooksWithArgs2(`after${type}`, afterFn, [...afterArgs]), cid);
1588
+ if (error && !error.matcherName) {
1589
+ throw error;
1590
+ }
1591
+ return result;
1592
+ };
1593
+ var filterStackTrace = (stack) => {
1594
+ return stack.split("\n").filter((line) => !STACKTRACE_FILTER.some((l) => line.includes(l))).map((line) => line.replace(/\?invalidateCache=(\d\.\d+|\d)/g, "")).join("\n");
1595
+ };
1596
+
1597
+ // src/test-framework/testInterfaceWrapper.ts
1598
+ init_utils();
1599
+ var MOCHA_COMMANDS = ["skip", "only"];
1600
+ var runHook = function(hookFn, origFn, beforeFn, beforeFnArgs, afterFn, afterFnArgs, cid, repeatTest, timeout) {
1601
+ const wrappedHook = function(...hookFnArgs) {
1602
+ return testFnWrapper.call(
1603
+ this,
1604
+ "Hook",
1605
+ {
1606
+ specFn: hookFn,
1607
+ specFnArgs: filterSpecArgs(hookFnArgs)
1608
+ },
1609
+ {
1610
+ beforeFn,
1611
+ beforeFnArgs
1612
+ },
1613
+ {
1614
+ afterFn,
1615
+ afterFnArgs
1616
+ },
1617
+ cid,
1618
+ repeatTest,
1619
+ origFn.name
1620
+ );
1621
+ };
1622
+ wrappedHook.toString = () => hookFn.toString();
1623
+ return origFn(wrappedHook, timeout);
1624
+ };
1625
+ var runSpec = function(specTitle, specFn, origFn, beforeFn, beforeFnArgs, afterFn, afterFnArgs, cid, repeatTest, timeout) {
1626
+ const wrappedFn = function(...specFnArgs) {
1627
+ return testFnWrapper.call(
1628
+ this,
1629
+ "Test",
1630
+ {
1631
+ specFn,
1632
+ specFnArgs: filterSpecArgs(specFnArgs)
1633
+ },
1634
+ {
1635
+ beforeFn,
1636
+ beforeFnArgs
1637
+ },
1638
+ {
1639
+ afterFn,
1640
+ afterFnArgs
1641
+ },
1642
+ cid,
1643
+ repeatTest
1644
+ );
1645
+ };
1646
+ wrappedFn.toString = () => specFn.toString();
1647
+ return origFn(specTitle, wrappedFn, timeout);
1648
+ };
1649
+ var wrapTestFunction = function(origFn, isSpec, beforeFn, beforeArgsFn, afterFn, afterArgsFn, cid) {
1650
+ return function(...specArguments) {
1651
+ let retryCnt = typeof specArguments[specArguments.length - 1] === "number" ? specArguments.pop() : 0;
1652
+ let timeout = globalThis.jasmine?.DEFAULT_TIMEOUT_INTERVAL;
1653
+ if (globalThis.jasmine) {
1654
+ if (typeof specArguments[specArguments.length - 1] === "number") {
1655
+ timeout = specArguments.pop();
1656
+ } else {
1657
+ timeout = retryCnt;
1658
+ retryCnt = 0;
1659
+ }
1660
+ }
1661
+ const specFn = typeof specArguments[0] === "function" ? specArguments.shift() : typeof specArguments[1] === "function" ? specArguments[1] : void 0;
1662
+ const specTitle = specArguments[0];
1663
+ if (isSpec) {
1664
+ if (specFn) {
1665
+ return runSpec(
1666
+ specTitle,
1667
+ specFn,
1668
+ origFn,
1669
+ beforeFn,
1670
+ beforeArgsFn,
1671
+ afterFn,
1672
+ afterArgsFn,
1673
+ cid,
1674
+ retryCnt,
1675
+ timeout
1676
+ );
1677
+ }
1678
+ return origFn(specTitle);
1679
+ }
1680
+ return runHook(
1681
+ specFn,
1682
+ origFn,
1683
+ beforeFn,
1684
+ beforeArgsFn,
1685
+ afterFn,
1686
+ afterArgsFn,
1687
+ cid,
1688
+ retryCnt,
1689
+ timeout
1690
+ );
1691
+ };
1692
+ };
1693
+ var wrapGlobalTestMethod = function(isSpec, beforeFn, beforeArgsFn, afterFn, afterArgsFn, fnName, cid, scope = globalThis) {
1694
+ const origFn = scope[fnName];
1695
+ scope[fnName] = wrapTestFunction(
1696
+ origFn,
1697
+ isSpec,
1698
+ beforeFn,
1699
+ beforeArgsFn,
1700
+ afterFn,
1701
+ afterArgsFn,
1702
+ cid
1703
+ );
1704
+ addMochaCommands(origFn, scope[fnName]);
1705
+ };
1706
+ function addMochaCommands(origFn, newFn) {
1707
+ MOCHA_COMMANDS.forEach((commandName) => {
1708
+ if (typeof origFn[commandName] === "function") {
1709
+ newFn[commandName] = origFn[commandName];
1710
+ }
1711
+ });
1712
+ }
1713
+
1714
+ // src/envDetector.ts
1715
+ init_constants();
1716
+ var MOBILE_BROWSER_NAMES = ["ipad", "iphone", "android"];
1717
+ var MOBILE_CAPABILITIES = [
1718
+ "appium-version",
1719
+ "appiumVersion",
1720
+ "device-type",
1721
+ "deviceType",
1722
+ "app",
1723
+ "appArguments",
1724
+ "device-orientation",
1725
+ "deviceOrientation",
1726
+ "deviceName",
1727
+ "automationName"
1728
+ ];
1729
+ function isW3C(capabilities) {
1730
+ if (!capabilities) {
1731
+ return false;
1732
+ }
1733
+ const isAppium = Boolean(
1734
+ capabilities["appium:automationName"] || capabilities["appium:deviceName"] || capabilities["appium:appiumVersion"]
1735
+ );
1736
+ const hasW3CCaps = Boolean(
1737
+ /**
1738
+ * safari docker image may not provide a platformName therefore
1739
+ * check one of the available "platformName" or "browserVersion"
1740
+ */
1741
+ (capabilities.platformName || capabilities.browserVersion) && /**
1742
+ * local safari and BrowserStack don't provide platformVersion therefore
1743
+ * check also if setWindowRect is provided
1744
+ */
1745
+ (capabilities["appium:platformVersion"] || Object.prototype.hasOwnProperty.call(capabilities, "setWindowRect"))
1746
+ );
1747
+ const hasWebdriverFlag = Boolean(capabilities["ms:experimental-webdriver"]);
1748
+ return Boolean(hasW3CCaps || isAppium || hasWebdriverFlag);
1749
+ }
1750
+ function isChrome2(capabilities) {
1751
+ if (!capabilities) {
1752
+ return false;
1753
+ }
1754
+ return Boolean(capabilities["goog:chromeOptions"] && capabilities.browserName === "chrome");
1755
+ }
1756
+ function isEdge2(capabilities) {
1757
+ if (!capabilities) {
1758
+ return false;
1759
+ }
1760
+ return Boolean(capabilities.browserName && SUPPORTED_BROWSERNAMES.edge.includes(capabilities.browserName.toLowerCase()) || capabilities["ms:edgeOptions"]);
1761
+ }
1762
+ function isFirefox2(capabilities) {
1763
+ if (!capabilities) {
1764
+ return false;
1765
+ }
1766
+ return capabilities.browserName === "firefox" || Boolean(Object.keys(capabilities).find((cap) => cap.startsWith("moz:")));
1767
+ }
1768
+ function isMobile(capabilities) {
1769
+ const browserName = (capabilities.browserName || "").toLowerCase();
1770
+ const bsOptions = capabilities["bstack:options"] || {};
1771
+ const browserstackBrowserName = (bsOptions.browserName || "").toLowerCase();
1772
+ return Boolean(
1773
+ /**
1774
+ * If the device is ios, tvos or android, the device might be mobile.
1775
+ */
1776
+ capabilities.platformName && capabilities.platformName.match(/ios/i) || capabilities.platformName && capabilities.platformName.match(/tvos/i) || capabilities.platformName && capabilities.platformName.match(/android/i) || /ios/i.test(bsOptions.platformName || "") || /tvos/i.test(bsOptions.platformName || "") || /android/i.test(bsOptions.platformName || "") || /**
1777
+ * capabilities contain mobile only specific capabilities
1778
+ */
1779
+ Object.keys(capabilities).find((cap) => MOBILE_CAPABILITIES.includes(cap) || MOBILE_CAPABILITIES.map((c) => `appium:${c}`).includes(cap)) || /**
1780
+ * browserName is empty (and eventually app is defined)
1781
+ */
1782
+ capabilities.browserName === "" || bsOptions.browserName === "" || /**
1783
+ * browserName is a mobile browser
1784
+ */
1785
+ MOBILE_BROWSER_NAMES.includes(browserName) || MOBILE_BROWSER_NAMES.includes(browserstackBrowserName)
1786
+ );
1787
+ }
1788
+ function isIOS(capabilities) {
1789
+ const bsOptions = capabilities?.["bstack:options"] || {};
1790
+ if (!capabilities) {
1791
+ return false;
1792
+ }
1793
+ return Boolean(
1794
+ capabilities.platformName && capabilities.platformName.match(/iOS/i) || capabilities["appium:deviceName"] && capabilities["appium:deviceName"].match(/(iPad|iPhone)/i) || /iOS/i.test(bsOptions.platformName || "") || /(iPad|iPhone)/i.test(bsOptions.deviceName || "")
1795
+ );
1796
+ }
1797
+ function isAndroid(capabilities) {
1798
+ const bsOptions = capabilities?.["bstack:options"] || {};
1799
+ if (!capabilities) {
1800
+ return false;
1801
+ }
1802
+ return Boolean(
1803
+ capabilities.platformName && capabilities.platformName.match(/Android/i) || /Android/i.test(bsOptions.platformName || "") || /Android/i.test(bsOptions.browserName || "") || capabilities.browserName && capabilities.browserName.match(/Android/i)
1804
+ );
1805
+ }
1806
+ function isSauce(capabilities) {
1807
+ if (!capabilities) {
1808
+ return false;
1809
+ }
1810
+ const caps = "alwaysMatch" in capabilities ? capabilities.alwaysMatch : capabilities;
1811
+ return Boolean(
1812
+ caps["sauce:options"] && caps["sauce:options"].extendedDebugging
1813
+ );
1814
+ }
1815
+ function isBidi(capabilities) {
1816
+ if (!capabilities) {
1817
+ return false;
1818
+ }
1819
+ return Boolean(capabilities.webSocketUrl);
1820
+ }
1821
+ function isSeleniumStandalone(capabilities) {
1822
+ if (!capabilities) {
1823
+ return false;
1824
+ }
1825
+ return (
1826
+ /**
1827
+ * Selenium v3 and below
1828
+ */
1829
+ // @ts-expect-error outdated JSONWP capabilities
1830
+ Boolean(capabilities["webdriver.remote.sessionid"]) || /**
1831
+ * Selenium v4 and up
1832
+ */
1833
+ Boolean(capabilities["se:cdp"])
1834
+ );
1835
+ }
1836
+ function isChromium(capabilities) {
1837
+ if (!capabilities) {
1838
+ return false;
1839
+ }
1840
+ return isChrome2(capabilities) || isEdge2(capabilities);
1841
+ }
1842
+ function capabilitiesEnvironmentDetector(capabilities) {
1843
+ return {
1844
+ isChrome: isChrome2(capabilities),
1845
+ isFirefox: isFirefox2(capabilities),
1846
+ isMobile: isMobile(capabilities),
1847
+ isIOS: isIOS(capabilities),
1848
+ isAndroid: isAndroid(capabilities),
1849
+ isSauce: isSauce(capabilities),
1850
+ isBidi: isBidi(capabilities),
1851
+ isChromium: isChromium(capabilities)
1852
+ };
1853
+ }
1854
+ function sessionEnvironmentDetector({
1855
+ capabilities,
1856
+ requestedCapabilities
1857
+ }) {
1858
+ return {
1859
+ isW3C: isW3C(capabilities),
1860
+ isChrome: isChrome2(capabilities),
1861
+ isFirefox: isFirefox2(capabilities),
1862
+ isMobile: isMobile(capabilities),
1863
+ isIOS: isIOS(capabilities),
1864
+ isAndroid: isAndroid(capabilities),
1865
+ isSauce: isSauce(requestedCapabilities),
1866
+ isSeleniumStandalone: isSeleniumStandalone(capabilities),
1867
+ isBidi: isBidi(capabilities),
1868
+ isChromium: isChromium(capabilities)
1869
+ };
1870
+ }
1871
+
1872
+ // src/index.ts
1873
+ init_constants();
1874
+ export {
1875
+ HOOK_DEFINITION,
1876
+ UNICODE_CHARACTERS,
1877
+ pIteration_exports as asyncIterators,
1878
+ capabilitiesEnvironmentDetector,
1879
+ commandCallStructure,
1880
+ enableFileLogging,
1881
+ executeAsync,
1882
+ executeHooksWithArgs,
1883
+ getArgumentType,
1884
+ getBrowserObject,
1885
+ initializeLauncherService,
1886
+ initializePlugin,
1887
+ initializeWorkerService,
1888
+ isAppiumCapability,
1889
+ isFunctionAsync,
1890
+ isValidParameter,
1891
+ isW3C,
1892
+ safeImport,
1893
+ sessionEnvironmentDetector,
1894
+ sleep,
1895
+ startWebDriver2 as startWebDriver,
1896
+ testFnWrapper,
1897
+ transformCommandLogResult,
1898
+ userImport,
1899
+ WebDriver as webdriverMonad,
1900
+ wrapCommand,
1901
+ wrapGlobalTestMethod
1902
+ };