@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.
- package/build/envDetector.d.ts +3 -3
- package/build/envDetector.d.ts.map +1 -1
- package/build/index.d.ts +2 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1902 -24
- package/build/initializeServices.d.ts +3 -3
- package/build/initializeServices.d.ts.map +1 -1
- package/build/monad.d.ts.map +1 -1
- package/build/node/manager.d.ts +2 -2
- package/build/node/manager.d.ts.map +1 -1
- package/build/node/startWebDriver.d.ts +2 -3
- package/build/node/startWebDriver.d.ts.map +1 -1
- package/build/node/utils.d.ts.map +1 -1
- package/build/node.js +473 -0
- package/build/pIteration.d.ts.map +1 -1
- package/build/shim.d.ts.map +1 -1
- package/build/startWebDriver.d.ts +2 -3
- package/build/startWebDriver.d.ts.map +1 -1
- package/build/test-framework/errorHandler.d.ts.map +1 -1
- package/build/test-framework/testFnWrapper.d.ts.map +1 -1
- package/build/test-framework/testInterfaceWrapper.d.ts.map +1 -1
- package/build/utils.d.ts +11 -2
- package/build/utils.d.ts.map +1 -1
- package/package.json +10 -11
- package/build/constants.js +0 -114
- package/build/envDetector.js +0 -251
- package/build/initializePlugin.js +0 -38
- package/build/initializeServices.js +0 -159
- package/build/monad.js +0 -196
- package/build/node/index.js +0 -3
- package/build/node/manager.js +0 -106
- package/build/node/startWebDriver.js +0 -140
- package/build/node/utils.js +0 -285
- package/build/pIteration.js +0 -347
- package/build/shim.js +0 -293
- package/build/startWebDriver.js +0 -20
- package/build/test-framework/errorHandler.js +0 -33
- package/build/test-framework/index.js +0 -4
- package/build/test-framework/testFnWrapper.js +0 -97
- package/build/test-framework/testInterfaceWrapper.js +0 -162
- package/build/test-framework/types.js +0 -1
- package/build/utils.js +0 -320
- /package/{LICENSE-MIT → LICENSE} +0 -0
package/build/monad.js
DELETED
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'node:events';
|
|
2
|
-
import logger from '@wdio/logger';
|
|
3
|
-
import { MESSAGE_TYPES } from '@wdio/types';
|
|
4
|
-
import { commandCallStructure, overwriteElementCommands } from './utils.js';
|
|
5
|
-
const SCOPE_TYPES = {
|
|
6
|
-
browser: /* istanbul ignore next */ function Browser() { },
|
|
7
|
-
element: /* istanbul ignore next */ function Element() { }
|
|
8
|
-
};
|
|
9
|
-
export default function WebDriver(options, modifier, propertiesObject = {}) {
|
|
10
|
-
/**
|
|
11
|
-
* In order to allow named scopes for elements we have to propagate that
|
|
12
|
-
* info within the `propertiesObject` object. This doesn't have any functional
|
|
13
|
-
* advantages just provides better description of objects when debugging them
|
|
14
|
-
*/
|
|
15
|
-
const scopeType = SCOPE_TYPES[propertiesObject.scope?.value || 'browser'];
|
|
16
|
-
delete propertiesObject.scope;
|
|
17
|
-
const prototype = Object.create(scopeType.prototype);
|
|
18
|
-
const log = logger('webdriver');
|
|
19
|
-
const eventHandler = new EventEmitter();
|
|
20
|
-
const EVENTHANDLER_FUNCTIONS = Object.getPrototypeOf(eventHandler);
|
|
21
|
-
/**
|
|
22
|
-
* WebDriver monad
|
|
23
|
-
*/
|
|
24
|
-
function unit(sessionId, commandWrapper) {
|
|
25
|
-
/**
|
|
26
|
-
* capabilities attached to the instance prototype not being shown if
|
|
27
|
-
* logging the instance
|
|
28
|
-
*/
|
|
29
|
-
propertiesObject.commandList = { value: Object.keys(propertiesObject) };
|
|
30
|
-
propertiesObject.options = { value: options };
|
|
31
|
-
propertiesObject.requestedCapabilities = { value: options.requestedCapabilities };
|
|
32
|
-
/**
|
|
33
|
-
* allow to wrap commands if necessary
|
|
34
|
-
* e.g. in wdio-cli to allow element chaining
|
|
35
|
-
*/
|
|
36
|
-
if (typeof commandWrapper === 'function') {
|
|
37
|
-
for (const [commandName, { value }] of Object.entries(propertiesObject)) {
|
|
38
|
-
if (typeof value !== 'function') {
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
propertiesObject[commandName].value = commandWrapper(commandName, value, propertiesObject);
|
|
42
|
-
propertiesObject[commandName].configurable = true;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* overwrite native element commands with user defined
|
|
47
|
-
*/
|
|
48
|
-
overwriteElementCommands.call(this, propertiesObject);
|
|
49
|
-
/**
|
|
50
|
-
* assign propertiesObject to itself so the client can be recreated
|
|
51
|
-
*/
|
|
52
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
53
|
-
const { puppeteer, ...propertiesObjectWithoutPuppeteer } = propertiesObject;
|
|
54
|
-
propertiesObject.__propertiesObject__ = { value: propertiesObjectWithoutPuppeteer };
|
|
55
|
-
let client = Object.create(prototype, propertiesObject);
|
|
56
|
-
client.sessionId = sessionId;
|
|
57
|
-
/**
|
|
58
|
-
* register capabilities only to browser scope
|
|
59
|
-
*/
|
|
60
|
-
if (scopeType.name === 'Browser') {
|
|
61
|
-
client.capabilities = options.capabilities;
|
|
62
|
-
}
|
|
63
|
-
if (typeof modifier === 'function') {
|
|
64
|
-
client = modifier(client, options);
|
|
65
|
-
}
|
|
66
|
-
client.addCommand = function (name, func, attachToElement = false, proto, instances) {
|
|
67
|
-
const customCommand = typeof commandWrapper === 'function'
|
|
68
|
-
? commandWrapper(name, func)
|
|
69
|
-
: func;
|
|
70
|
-
if (attachToElement) {
|
|
71
|
-
/**
|
|
72
|
-
* add command to every multiremote instance
|
|
73
|
-
*/
|
|
74
|
-
if (instances) {
|
|
75
|
-
Object.values(instances).forEach(instance => {
|
|
76
|
-
instance.__propertiesObject__[name] = {
|
|
77
|
-
value: customCommand
|
|
78
|
-
};
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
this.__propertiesObject__[name] = { value: customCommand };
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
unit.lift(name, customCommand, proto);
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* When running component tests, custom commands might not be recognised when services attach them to the browser.
|
|
88
|
-
* This is because the `addCommand` function is called within the Node.js environment and not the browser.
|
|
89
|
-
* As a workaround, we check here if we are in a worker process and if so we send a message to the parent process
|
|
90
|
-
* to add the command to the browser.
|
|
91
|
-
*
|
|
92
|
-
* @todo(Christian): this won't be sufficient, e.g. in cases where the page is reloaded and the command is not re-added.
|
|
93
|
-
*/
|
|
94
|
-
if (typeof process.send === 'function' && process.env.WDIO_WORKER_ID) {
|
|
95
|
-
const message = {
|
|
96
|
-
origin: 'worker',
|
|
97
|
-
name: 'workerEvent',
|
|
98
|
-
args: {
|
|
99
|
-
type: MESSAGE_TYPES.customCommand,
|
|
100
|
-
value: {
|
|
101
|
-
commandName: name,
|
|
102
|
-
cid: process.env.WDIO_WORKER_ID,
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
process.send(message);
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
/**
|
|
110
|
-
* overwriteCommand
|
|
111
|
-
* @param {string} name command name to be overwritten
|
|
112
|
-
* @param {Function} func function to replace original command with;
|
|
113
|
-
* takes original function as first argument.
|
|
114
|
-
* @param {boolean=} attachToElement overwrite browser command (false) or element command (true)
|
|
115
|
-
* @param {Object=} proto prototype to add function to (optional)
|
|
116
|
-
* @param {Object=} instances multiremote instances
|
|
117
|
-
*/
|
|
118
|
-
client.overwriteCommand = function (name, func, attachToElement = false, proto, instances) {
|
|
119
|
-
const customCommand = typeof commandWrapper === 'function'
|
|
120
|
-
? commandWrapper(name, func)
|
|
121
|
-
: func;
|
|
122
|
-
if (attachToElement) {
|
|
123
|
-
if (instances) {
|
|
124
|
-
/**
|
|
125
|
-
* add command to every multiremote instance
|
|
126
|
-
*/
|
|
127
|
-
Object.values(instances).forEach(instance => {
|
|
128
|
-
instance.__propertiesObject__.__elementOverrides__.value[name] = customCommand;
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
/**
|
|
133
|
-
* regular mode
|
|
134
|
-
*/
|
|
135
|
-
this.__propertiesObject__.__elementOverrides__.value[name] = customCommand;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
else if (client[name]) {
|
|
139
|
-
const origCommand = client[name];
|
|
140
|
-
delete client[name];
|
|
141
|
-
unit.lift(name, customCommand, proto, (...args) => origCommand.apply(this, args));
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
throw new Error('overwriteCommand: no command to be overwritten: ' + name);
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
return client;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Enhance monad prototype with function
|
|
151
|
-
* @param {string} name name of function to attach to prototype
|
|
152
|
-
* @param {Function} func function to be added to prototype
|
|
153
|
-
* @param {Object} proto prototype to add function to (optional)
|
|
154
|
-
* @param {Function} origCommand original command to be passed to custom command as first argument
|
|
155
|
-
*/
|
|
156
|
-
unit.lift = function (name, func, proto, origCommand) {
|
|
157
|
-
(proto || prototype)[name] = function next(...args) {
|
|
158
|
-
log.info('COMMAND', commandCallStructure(name, args));
|
|
159
|
-
/**
|
|
160
|
-
* set name of function for better error stack
|
|
161
|
-
*/
|
|
162
|
-
Object.defineProperty(func, 'name', {
|
|
163
|
-
value: name,
|
|
164
|
-
writable: false,
|
|
165
|
-
});
|
|
166
|
-
const result = func.apply(this, origCommand ? [origCommand, ...args] : args);
|
|
167
|
-
/**
|
|
168
|
-
* always transform result into promise
|
|
169
|
-
*/
|
|
170
|
-
Promise.resolve(result).then((res) => {
|
|
171
|
-
const elem = res;
|
|
172
|
-
let resultLog = res;
|
|
173
|
-
if (elem instanceof SCOPE_TYPES.element) {
|
|
174
|
-
resultLog = `WebdriverIO.Element<${elem.elementId || elem.selector}>`;
|
|
175
|
-
}
|
|
176
|
-
else if (res instanceof SCOPE_TYPES.browser) {
|
|
177
|
-
resultLog = 'WebdriverIO.Browser';
|
|
178
|
-
}
|
|
179
|
-
log.info('RESULT', resultLog);
|
|
180
|
-
this.emit('result', { name, result: res });
|
|
181
|
-
}).catch(() => { });
|
|
182
|
-
return result;
|
|
183
|
-
};
|
|
184
|
-
};
|
|
185
|
-
/**
|
|
186
|
-
* register event emitter
|
|
187
|
-
*/
|
|
188
|
-
for (const eventCommand in EVENTHANDLER_FUNCTIONS) {
|
|
189
|
-
prototype[eventCommand] = function (...args) {
|
|
190
|
-
const method = eventCommand;
|
|
191
|
-
eventHandler[method]?.(...args);
|
|
192
|
-
return this;
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
return unit;
|
|
196
|
-
}
|
package/build/node/index.js
DELETED
package/build/node/manager.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import logger from '@wdio/logger';
|
|
2
|
-
import { getCacheDir, getDriverOptions, setupChromedriver, setupEdgedriver, setupGeckodriver, setupPuppeteerBrowser } from './utils.js';
|
|
3
|
-
import { definesRemoteDriver, isSafari, isEdge, isFirefox, isChrome } from '../utils.js';
|
|
4
|
-
const log = logger('@wdio/utils');
|
|
5
|
-
const UNDEFINED_BROWSER_VERSION = null;
|
|
6
|
-
var BrowserDriverTaskLabel;
|
|
7
|
-
(function (BrowserDriverTaskLabel) {
|
|
8
|
-
BrowserDriverTaskLabel["BROWSER"] = "browser binaries";
|
|
9
|
-
BrowserDriverTaskLabel["DRIVER"] = "browser driver";
|
|
10
|
-
})(BrowserDriverTaskLabel || (BrowserDriverTaskLabel = {}));
|
|
11
|
-
function mapCapabilities(options, caps, task, taskItemLabel) {
|
|
12
|
-
const capabilitiesToRequireSetup = (Array.isArray(caps)
|
|
13
|
-
? caps.map((cap) => {
|
|
14
|
-
const w3cCaps = cap;
|
|
15
|
-
const multiremoteCaps = cap;
|
|
16
|
-
const isMultiremote = Boolean(multiremoteCaps[Object.keys(cap)[0]].capabilities);
|
|
17
|
-
if (isMultiremote) {
|
|
18
|
-
return Object.values(multiremoteCaps).map((c) => c.capabilities);
|
|
19
|
-
}
|
|
20
|
-
else if (w3cCaps.alwaysMatch) {
|
|
21
|
-
return w3cCaps.alwaysMatch;
|
|
22
|
-
}
|
|
23
|
-
return cap;
|
|
24
|
-
}).flat()
|
|
25
|
-
: Object.values(caps).map((mrOpts) => {
|
|
26
|
-
const w3cCaps = mrOpts.capabilities;
|
|
27
|
-
if (w3cCaps.alwaysMatch) {
|
|
28
|
-
return w3cCaps.alwaysMatch;
|
|
29
|
-
}
|
|
30
|
-
return mrOpts.capabilities;
|
|
31
|
-
})).flat().filter((cap) => (
|
|
32
|
-
/**
|
|
33
|
-
* only set up driver if
|
|
34
|
-
*/
|
|
35
|
-
// - capabilities are defined and not empty
|
|
36
|
-
cap &&
|
|
37
|
-
// - browserName is defined so we know it is a browser session
|
|
38
|
-
cap.browserName &&
|
|
39
|
-
// - we are not about to run a cloud session
|
|
40
|
-
!definesRemoteDriver(options) &&
|
|
41
|
-
// - we are not running Safari (driver already installed on macOS)
|
|
42
|
-
!isSafari(cap.browserName) &&
|
|
43
|
-
// - driver options don't define a binary path
|
|
44
|
-
!getDriverOptions(cap).binary));
|
|
45
|
-
/**
|
|
46
|
-
* nothing to setup
|
|
47
|
-
*/
|
|
48
|
-
if (capabilitiesToRequireSetup.length === 0) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* get all browser names and versions that need driver setup
|
|
53
|
-
*/
|
|
54
|
-
const queueByBrowserName = capabilitiesToRequireSetup.reduce((queue, cap) => {
|
|
55
|
-
if (!cap.browserName) {
|
|
56
|
-
return queue;
|
|
57
|
-
}
|
|
58
|
-
if (!queue.has(cap.browserName)) {
|
|
59
|
-
queue.set(cap.browserName, new Map());
|
|
60
|
-
}
|
|
61
|
-
const browserVersion = cap.browserVersion || UNDEFINED_BROWSER_VERSION;
|
|
62
|
-
queue.get(cap.browserName).set(browserVersion, cap);
|
|
63
|
-
return queue;
|
|
64
|
-
}, new Map());
|
|
65
|
-
const driverToSetupString = Array.from(queueByBrowserName.entries())
|
|
66
|
-
.map(([browserName, versions]) => `${browserName}@${Array.from(versions.keys()).map((bv) => bv || 'stable').join(', ')}`)
|
|
67
|
-
.join(' - ');
|
|
68
|
-
log.info(`Setting up ${taskItemLabel} for: ${driverToSetupString}`);
|
|
69
|
-
return Promise.all(Array.from(queueByBrowserName.entries()).map(([browserName, queueByBrowserVersion]) => {
|
|
70
|
-
return Array.from(queueByBrowserVersion).map(([browserVersion, cap]) => task({
|
|
71
|
-
...cap,
|
|
72
|
-
browserName,
|
|
73
|
-
...(browserVersion !== UNDEFINED_BROWSER_VERSION ? { browserVersion } : {})
|
|
74
|
-
}));
|
|
75
|
-
}).flat());
|
|
76
|
-
}
|
|
77
|
-
export async function setupDriver(options, caps) {
|
|
78
|
-
return mapCapabilities(options, caps, async (cap) => {
|
|
79
|
-
const cacheDir = getCacheDir(options, cap);
|
|
80
|
-
if (isEdge(cap.browserName)) {
|
|
81
|
-
return setupEdgedriver(cacheDir, cap.browserVersion);
|
|
82
|
-
}
|
|
83
|
-
else if (isFirefox(cap.browserName)) {
|
|
84
|
-
// "latest" works for setting up browser only but not geckodriver
|
|
85
|
-
const version = cap.browserVersion === 'latest' ? undefined : cap.browserVersion;
|
|
86
|
-
return setupGeckodriver(cacheDir, version);
|
|
87
|
-
}
|
|
88
|
-
else if (isChrome(cap.browserName)) {
|
|
89
|
-
return setupChromedriver(cacheDir, cap.browserVersion);
|
|
90
|
-
}
|
|
91
|
-
return Promise.resolve();
|
|
92
|
-
}, BrowserDriverTaskLabel.DRIVER);
|
|
93
|
-
}
|
|
94
|
-
export function setupBrowser(options, caps) {
|
|
95
|
-
return mapCapabilities(options, caps, async (cap) => {
|
|
96
|
-
const cacheDir = getCacheDir(options, cap);
|
|
97
|
-
if (isEdge(cap.browserName)) {
|
|
98
|
-
// not yet implemented
|
|
99
|
-
return Promise.resolve();
|
|
100
|
-
}
|
|
101
|
-
else if (isChrome(cap.browserName) || isFirefox(cap.browserName)) {
|
|
102
|
-
return setupPuppeteerBrowser(cacheDir, cap);
|
|
103
|
-
}
|
|
104
|
-
return Promise.resolve();
|
|
105
|
-
}, BrowserDriverTaskLabel.BROWSER);
|
|
106
|
-
}
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import os from 'node:os';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import cp from 'node:child_process';
|
|
5
|
-
import getPort from 'get-port';
|
|
6
|
-
import waitPort from 'wait-port';
|
|
7
|
-
import logger from '@wdio/logger';
|
|
8
|
-
import split2 from 'split2';
|
|
9
|
-
import { deepmerge } from 'deepmerge-ts';
|
|
10
|
-
import { start as startSafaridriver } from 'safaridriver';
|
|
11
|
-
import { start as startGeckodriver } from 'geckodriver';
|
|
12
|
-
import { start as startEdgedriver, findEdgePath } from 'edgedriver';
|
|
13
|
-
import { parseParams, setupPuppeteerBrowser, setupChromedriver, getCacheDir } from './utils.js';
|
|
14
|
-
import { isChrome, isFirefox, isEdge, isSafari, isAppiumCapability } from '../utils.js';
|
|
15
|
-
import { SUPPORTED_BROWSERNAMES } from '../constants.js';
|
|
16
|
-
const log = logger('@wdio/utils');
|
|
17
|
-
const DRIVER_WAIT_TIMEOUT = 10 * 1000; // 10s
|
|
18
|
-
export async function startWebDriver(options) {
|
|
19
|
-
/**
|
|
20
|
-
* in case we are running unit tests, just return
|
|
21
|
-
*/
|
|
22
|
-
if (process.env.WDIO_SKIP_DRIVER_SETUP) {
|
|
23
|
-
options.hostname = 'localhost';
|
|
24
|
-
options.port = 4321;
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
let driverProcess;
|
|
28
|
-
let driver = '';
|
|
29
|
-
const start = Date.now();
|
|
30
|
-
const caps = options.capabilities.alwaysMatch || options.capabilities;
|
|
31
|
-
/**
|
|
32
|
-
* session might be a mobile session so don't do anything
|
|
33
|
-
*/
|
|
34
|
-
if (isAppiumCapability(caps)) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (!caps.browserName) {
|
|
38
|
-
throw new Error('No "browserName" defined in capabilities nor hostname or port found!\n' +
|
|
39
|
-
'If you like to run a local browser session make sure to pick from one of ' +
|
|
40
|
-
`the following browser names: ${Object.values(SUPPORTED_BROWSERNAMES).flat(Infinity)}`);
|
|
41
|
-
}
|
|
42
|
-
const port = await getPort();
|
|
43
|
-
const cacheDir = getCacheDir(options, caps);
|
|
44
|
-
if (isChrome(caps.browserName)) {
|
|
45
|
-
/**
|
|
46
|
-
* Chrome
|
|
47
|
-
*/
|
|
48
|
-
const chromedriverOptions = caps['wdio:chromedriverOptions'] || {};
|
|
49
|
-
const { executablePath: chromeExecuteablePath, browserVersion } = await setupPuppeteerBrowser(cacheDir, caps);
|
|
50
|
-
const { executablePath: chromedriverExcecuteablePath } = chromedriverOptions.binary
|
|
51
|
-
? { executablePath: chromedriverOptions.binary }
|
|
52
|
-
: await setupChromedriver(cacheDir, browserVersion);
|
|
53
|
-
caps['goog:chromeOptions'] = deepmerge({ binary: chromeExecuteablePath }, caps['goog:chromeOptions'] || {});
|
|
54
|
-
chromedriverOptions.allowedOrigins = chromedriverOptions.allowedOrigins || ['*'];
|
|
55
|
-
chromedriverOptions.allowedIps = chromedriverOptions.allowedIps || ['0.0.0.0'];
|
|
56
|
-
const driverParams = parseParams({ port, ...chromedriverOptions });
|
|
57
|
-
driverProcess = cp.spawn(chromedriverExcecuteablePath, driverParams);
|
|
58
|
-
driver = `Chromedriver v${browserVersion} with params ${driverParams.join(' ')}`;
|
|
59
|
-
}
|
|
60
|
-
else if (isSafari(caps.browserName)) {
|
|
61
|
-
const safaridriverOptions = caps['wdio:safaridriverOptions'] || {};
|
|
62
|
-
/**
|
|
63
|
-
* Safari
|
|
64
|
-
*/
|
|
65
|
-
driver = 'SafariDriver';
|
|
66
|
-
driverProcess = startSafaridriver({
|
|
67
|
-
useTechnologyPreview: Boolean(caps.browserName.match(/preview/i)),
|
|
68
|
-
...safaridriverOptions,
|
|
69
|
-
port
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
else if (isFirefox(caps.browserName)) {
|
|
73
|
-
/**
|
|
74
|
-
* Firefox
|
|
75
|
-
*/
|
|
76
|
-
const { executablePath } = await setupPuppeteerBrowser(cacheDir, caps);
|
|
77
|
-
caps['moz:firefoxOptions'] = deepmerge({ binary: executablePath }, caps['moz:firefoxOptions'] || {});
|
|
78
|
-
/**
|
|
79
|
-
* the "binary" parameter refers to the driver binary in the WebdriverIO.GeckodriverOptions and
|
|
80
|
-
* to the Firefox binary in the driver option
|
|
81
|
-
*/
|
|
82
|
-
delete caps.browserVersion;
|
|
83
|
-
const { binary, ...geckodriverOptions } = caps['wdio:geckodriverOptions'] || {};
|
|
84
|
-
if (binary) {
|
|
85
|
-
geckodriverOptions.customGeckoDriverPath = binary;
|
|
86
|
-
}
|
|
87
|
-
driver = 'GeckoDriver';
|
|
88
|
-
driverProcess = await startGeckodriver({ ...geckodriverOptions, cacheDir, port, allowHosts: ['localhost'] });
|
|
89
|
-
}
|
|
90
|
-
else if (isEdge(caps.browserName)) {
|
|
91
|
-
/**
|
|
92
|
-
* Microsoft Edge
|
|
93
|
-
*/
|
|
94
|
-
const { binary, ...edgedriverOptions } = caps['wdio:edgedriverOptions'] || {};
|
|
95
|
-
if (binary) {
|
|
96
|
-
edgedriverOptions.customEdgeDriverPath = binary;
|
|
97
|
-
}
|
|
98
|
-
driver = 'EdgeDriver';
|
|
99
|
-
driverProcess = await startEdgedriver({ ...edgedriverOptions, cacheDir, port, allowedIps: ['0.0.0.0'] }).catch((err) => {
|
|
100
|
-
log.warn(`Couldn't start EdgeDriver: ${err.message}, retry ...`);
|
|
101
|
-
return startEdgedriver({ ...edgedriverOptions, cacheDir, port });
|
|
102
|
-
});
|
|
103
|
-
/**
|
|
104
|
-
* Microsoft Edge is very particular when it comes to browser names
|
|
105
|
-
*/
|
|
106
|
-
caps.browserName = 'MicrosoftEdge';
|
|
107
|
-
/**
|
|
108
|
-
* on Linux set the path to the Edge binary if not already set
|
|
109
|
-
*/
|
|
110
|
-
if (!caps['ms:edgeOptions']?.binary && os.platform() !== 'darwin' && os.platform() !== 'win32') {
|
|
111
|
-
caps['ms:edgeOptions'] = caps['ms:edgeOptions'] || {};
|
|
112
|
-
caps['ms:edgeOptions'].binary = findEdgePath();
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
throw new Error(`Unknown browser name "${caps.browserName}". Make sure to pick from one of the following ` +
|
|
117
|
-
Object.values(SUPPORTED_BROWSERNAMES).flat(Infinity));
|
|
118
|
-
}
|
|
119
|
-
const logIdentifier = driver.split(' ').shift()?.toLowerCase() || 'driver';
|
|
120
|
-
if (options.outputDir) {
|
|
121
|
-
const logFileName = process.env.WDIO_WORKER_ID
|
|
122
|
-
? `wdio-${process.env.WDIO_WORKER_ID}-${logIdentifier}.log`
|
|
123
|
-
: `wdio-${logIdentifier}-${port}.log`;
|
|
124
|
-
const logFile = path.resolve(options.outputDir, logFileName);
|
|
125
|
-
const logStream = fs.createWriteStream(logFile, { flags: 'w' });
|
|
126
|
-
driverProcess.stdout?.pipe(logStream);
|
|
127
|
-
driverProcess.stderr?.pipe(logStream);
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
const driverLog = logger(logIdentifier);
|
|
131
|
-
driverProcess.stdout?.pipe(split2()).on('data', driverLog.info.bind(driverLog));
|
|
132
|
-
driverProcess.stderr?.pipe(split2()).on('data', driverLog.warn.bind(driverLog));
|
|
133
|
-
}
|
|
134
|
-
await waitPort({ port, output: 'silent', timeout: DRIVER_WAIT_TIMEOUT })
|
|
135
|
-
.catch((e) => { throw new Error(`Timed out to connect to ${driver}: ${e.message}`); });
|
|
136
|
-
options.hostname = 'localhost';
|
|
137
|
-
options.port = port;
|
|
138
|
-
log.info(`Started ${driver} in ${Date.now() - start}ms on port ${port}`);
|
|
139
|
-
return driverProcess;
|
|
140
|
-
}
|