webdriver 8.13.13 → 8.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,12 @@
1
+ /// <reference types="node" />
2
+ import type { ChildProcess } from 'node:child_process';
1
3
  import type { CommandEndpoint, BidiResponse } from '@wdio/protocols';
2
4
  import type { BidiHandler } from './bidi/handler.js';
3
5
  import type { WebDriverResponse } from './request/index.js';
4
6
  import type { BaseClient } from './types.js';
5
7
  interface BaseClientWithEventHandler extends BaseClient {
6
8
  eventMiddleware: BidiHandler;
9
+ _driverProcess?: ChildProcess;
7
10
  }
8
11
  export default function (method: string, endpointUri: string, commandInfo: CommandEndpoint, doubleEncodeVariables?: boolean): (this: BaseClientWithEventHandler, ...args: any[]) => Promise<WebDriverResponse | BidiResponse | void>;
9
12
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAGpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAK5C,UAAU,0BAA2B,SAAQ,UAAU;IACnD,eAAe,EAAE,WAAW,CAAA;CAC/B;AAED,MAAM,CAAC,OAAO,WACV,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,eAAe,EAC5B,qBAAqB,UAAQ,UAIgB,0BAA0B,WAAW,GAAG,EAAE,KAAG,QAAQ,iBAAiB,GAAG,YAAY,GAAG,IAAI,CAAC,CA6G7I"}
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGtD,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAGpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAK5C,UAAU,0BAA2B,SAAQ,UAAU;IACnD,eAAe,EAAE,WAAW,CAAA;IAC5B,cAAc,CAAC,EAAE,YAAY,CAAA;CAChC;AAED,MAAM,CAAC,OAAO,WACV,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,eAAe,EAC5B,qBAAqB,UAAQ,UAIgB,0BAA0B,WAAW,GAAG,EAAE,KAAG,QAAQ,iBAAiB,GAAG,YAAY,GAAG,IAAI,CAAC,CA0I7I"}
package/build/command.js CHANGED
@@ -91,8 +91,35 @@ export default function (method, endpointUri, commandInfo, doubleEncodeVariables
91
91
  log.info('RESULT', resultLog);
92
92
  }
93
93
  this.emit('result', { method, endpoint, body, result });
94
- if (command === 'deleteSession' && !process.env.WDIO_WORKER_ID) {
95
- logger.clearLogger();
94
+ if (command === 'deleteSession') {
95
+ /**
96
+ * kill driver process if there is one
97
+ */
98
+ if (this._driverProcess) {
99
+ log.info(`Kill ${this._driverProcess.spawnfile} driver process with command line: ${this._driverProcess.spawnargs.slice(1).join(' ')}`);
100
+ const killedSuccessfully = this._driverProcess.kill('SIGKILL');
101
+ if (!killedSuccessfully) {
102
+ log.warn('Failed to kill driver process, manully clean-up might be required');
103
+ }
104
+ this._driverProcess = undefined;
105
+ setTimeout(() => {
106
+ /**
107
+ * clear up potential leaked TLS Socket handles
108
+ * see https://github.com/puppeteer/puppeteer/pull/10667
109
+ */
110
+ for (const handle of process._getActiveHandles()) {
111
+ if (handle.servername && handle.servername.includes('edgedl.me')) {
112
+ handle.destroy();
113
+ }
114
+ }
115
+ }, 10);
116
+ }
117
+ /**
118
+ * clear logger stream if session has been terminated
119
+ */
120
+ if (!process.env.WDIO_WORKER_ID) {
121
+ logger.clearLogger();
122
+ }
96
123
  }
97
124
  return result.value;
98
125
  });
@@ -4,4 +4,10 @@ export declare const REG_EXPS: {
4
4
  commandName: RegExp;
5
5
  execFn: RegExp;
6
6
  };
7
+ export declare const SUPPORTED_BROWSERNAMES: {
8
+ chrome: string[];
9
+ firefox: string[];
10
+ edge: string[];
11
+ safari: string[];
12
+ };
7
13
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAE1C,eAAO,MAAM,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CA0IpE,CAAA;AAED,eAAO,MAAM,QAAQ;;;CAGpB,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAE1C,eAAO,MAAM,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAiJpE,CAAA;AAED,eAAO,MAAM,QAAQ;;;CAGpB,CAAA;AAED,eAAO,MAAM,sBAAsB;;;;;CAKlC,CAAA"}
@@ -1,3 +1,4 @@
1
+ import os from 'node:os';
1
2
  export const DEFAULTS = {
2
3
  /**
3
4
  * protocol of automation driver
@@ -12,14 +13,13 @@ export const DEFAULTS = {
12
13
  */
13
14
  hostname: {
14
15
  type: 'string',
15
- default: 'localhost'
16
+ default: '0.0.0.0'
16
17
  },
17
18
  /**
18
19
  * port of automation driver
19
20
  */
20
21
  port: {
21
- type: 'number',
22
- default: 4444
22
+ type: 'number'
23
23
  },
24
24
  /**
25
25
  * path to WebDriver endpoints
@@ -134,9 +134,23 @@ export const DEFAULTS = {
134
134
  strictSSL: {
135
135
  type: 'boolean',
136
136
  default: true
137
+ },
138
+ /**
139
+ * The path to the root of the cache directory. This directory is used to store all drivers that are downloaded
140
+ * when attempting to start a session.
141
+ */
142
+ cacheDir: {
143
+ type: 'string',
144
+ default: process.env.WEBDRIVER_CACHE_DIR || os.tmpdir()
137
145
  }
138
146
  };
139
147
  export const REG_EXPS = {
140
148
  commandName: /.*\/session\/[0-9a-f-]+\/(.*)/,
141
149
  execFn: /return \(([\s\S]*)\)\.apply\(null, arguments\)/
142
150
  };
151
+ export const SUPPORTED_BROWSERNAMES = {
152
+ chrome: ['chrome', 'googlechrome', 'chromium', 'chromium-browser'],
153
+ firefox: ['firefox', 'ff', 'mozilla', 'mozilla firefox'],
154
+ edge: ['edge', 'microsoftedge', 'msedge'],
155
+ safari: ['safari', 'safari technology preview']
156
+ };
@@ -0,0 +1,19 @@
1
+ /// <reference types="node" />
2
+ import cp from 'node:child_process';
3
+ import type { Options } from '@wdio/types';
4
+ import { type SafaridriverOptions } from 'safaridriver';
5
+ import { type GeckodriverParameters } from 'geckodriver';
6
+ import { type EdgedriverParameters } from 'edgedriver';
7
+ import { type InstallOptions } from '@puppeteer/browsers';
8
+ import type { Capabilities } from '@wdio/types';
9
+ export interface ExtendedCapabilities extends Capabilities.Capabilities, WDIODriverOptions {
10
+ }
11
+ export type ChromedriverOptions = InstallOptions & Omit<EdgedriverParameters, 'port' | 'edgeDriverVersion' | 'customEdgeDriverPath'>;
12
+ export interface WDIODriverOptions {
13
+ 'wdio:chromedriverOptions'?: ChromedriverOptions;
14
+ 'wdio:safaridriverOptions'?: Omit<SafaridriverOptions, 'port'>;
15
+ 'wdio:geckodriverOptions'?: Omit<GeckodriverParameters, 'port'>;
16
+ 'wdio:edgedriverOptions'?: Omit<EdgedriverParameters, 'port'>;
17
+ }
18
+ export declare function startWebDriver(options: Options.WebDriver): Promise<cp.ChildProcess | undefined>;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/driver/index.ts"],"names":[],"mappings":";AAIA,OAAO,EAAyB,MAAM,oBAAoB,CAAA;AAM1D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAE1C,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAA;AACnF,OAAO,EAA6B,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACnF,OAAO,EAA4B,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAChF,OAAO,EAA2C,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAElG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAO/C,MAAM,WAAW,oBAAqB,SAAQ,YAAY,CAAC,YAAY,EAAE,iBAAiB;CAAG;AAC7F,MAAM,MAAM,mBAAmB,GAAG,cAAc,GAAG,IAAI,CAAC,oBAAoB,EAAE,MAAM,GAAG,mBAAmB,GAAG,sBAAsB,CAAC,CAAA;AAEpI,MAAM,WAAW,iBAAiB;IAC9B,0BAA0B,CAAC,EAAE,mBAAmB,CAAA;IAChD,0BAA0B,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAA;IAC9D,yBAAyB,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAA;IAC/D,wBAAwB,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAA;CAChE;AAED,wBAAsB,cAAc,CAAE,OAAO,EAAE,OAAO,CAAC,SAAS,wCAqI/D"}
@@ -0,0 +1,138 @@
1
+ import fs from 'node:fs';
2
+ import fsp from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import cp from 'node:child_process';
6
+ import getPort from 'get-port';
7
+ import waitPort from 'wait-port';
8
+ import logger from '@wdio/logger';
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 } from 'edgedriver';
13
+ import { install, computeExecutablePath, Browser } from '@puppeteer/browsers';
14
+ import { parseParams, setupChrome, definesRemoteDriver, downloadProgressCallback } from './utils.js';
15
+ import { SUPPORTED_BROWSERNAMES } from '../constants.js';
16
+ const log = logger('webdriver');
17
+ export async function startWebDriver(options) {
18
+ /**
19
+ * in case we are running unit tests, just return
20
+ */
21
+ if (process.env.WDIO_SKIP_DRIVER_SETUP) {
22
+ options.hostname = '0.0.0.0';
23
+ options.port = 4321;
24
+ return;
25
+ }
26
+ /**
27
+ * if any of the connection parameter are set, don't start any driver
28
+ */
29
+ if (definesRemoteDriver(options)) {
30
+ log.info(`Connecting to existing driver at ${options.protocol}://${options.hostname}:${options.port}${options.path}`);
31
+ return;
32
+ }
33
+ let driverProcess;
34
+ let driver = '';
35
+ const start = Date.now();
36
+ const caps = options.capabilities.alwaysMatch || options.capabilities;
37
+ /**
38
+ * session might be a mobile session so don't do anything
39
+ */
40
+ if (!caps.browserName) {
41
+ throw new Error('No "browserName" defined in capabilities nor hostname or port found!\n' +
42
+ 'If you like to run a mobile session with Appium, make sure to set "hostname" and "port" in your ' +
43
+ 'WebdriverIO options. If you like to run a local browser session make sure to pick from one of ' +
44
+ `the following browser names: ${Object.values(SUPPORTED_BROWSERNAMES).flat(Infinity)}`);
45
+ }
46
+ const port = await getPort();
47
+ if (SUPPORTED_BROWSERNAMES.chrome.includes(caps.browserName.toLowerCase())) {
48
+ /**
49
+ * Chrome
50
+ */
51
+ const chromedriverOptions = caps['wdio:chromedriverOptions'] || {};
52
+ const cacheDir = chromedriverOptions.cacheDir || options.cacheDir || os.tmpdir();
53
+ const exist = await fsp.access(cacheDir).then(() => true, () => false);
54
+ if (!exist) {
55
+ await fsp.mkdir(cacheDir, { recursive: true });
56
+ }
57
+ const { executablePath, buildId, platform } = await setupChrome(caps, cacheDir);
58
+ const chromedriverBinaryPath = computeExecutablePath({
59
+ browser: Browser.CHROMEDRIVER,
60
+ buildId,
61
+ cacheDir
62
+ });
63
+ const hasChromedriverInstalled = await fsp.access(chromedriverBinaryPath).then(() => true, () => false);
64
+ if (!hasChromedriverInstalled) {
65
+ log.info(`Downloading Chromedriver v${buildId}`);
66
+ await install({
67
+ ...chromedriverOptions,
68
+ cacheDir,
69
+ platform,
70
+ buildId,
71
+ browser: Browser.CHROMEDRIVER,
72
+ downloadProgressCallback: (downloadedBytes, totalBytes) => downloadProgressCallback('Chromedriver', downloadedBytes, totalBytes)
73
+ });
74
+ }
75
+ else {
76
+ log.info(`Using Chromedriver v${buildId} from cache directory ${cacheDir}`);
77
+ }
78
+ caps['goog:chromeOptions'] = deepmerge({ binary: executablePath }, caps['goog:chromeOptions'] || {});
79
+ chromedriverOptions.allowedOrigins = chromedriverOptions.allowedOrigins || ['*'];
80
+ chromedriverOptions.allowedIps = chromedriverOptions.allowedIps || [''];
81
+ const driverParams = parseParams({ port, ...chromedriverOptions });
82
+ driverProcess = cp.spawn(chromedriverBinaryPath, driverParams);
83
+ driver = `ChromeDriver v${buildId} with params ${driverParams.join(' ')}`;
84
+ }
85
+ else if (SUPPORTED_BROWSERNAMES.safari.includes(caps.browserName.toLowerCase())) {
86
+ const safaridriverOptions = caps['wdio:safaridriverOptions'] || {};
87
+ /**
88
+ * Safari
89
+ */
90
+ driver = 'SafariDriver';
91
+ driverProcess = startSafaridriver({
92
+ useTechnologyPreview: Boolean(caps.browserName.match(/preview/i)),
93
+ ...safaridriverOptions,
94
+ port
95
+ });
96
+ /**
97
+ * set "Host" header as it is required by Safaridriver
98
+ */
99
+ options.headers = deepmerge({ Host: 'localhost' }, (options.headers || {}));
100
+ }
101
+ else if (SUPPORTED_BROWSERNAMES.firefox.includes(caps.browserName.toLowerCase())) {
102
+ /**
103
+ * Firefox
104
+ */
105
+ const geckodriverOptions = caps['wdio:geckodriverOptions'] || {};
106
+ const cacheDir = geckodriverOptions.cacheDir || options.cacheDir || os.tmpdir();
107
+ driver = 'GeckoDriver';
108
+ driverProcess = await startGeckodriver({ ...geckodriverOptions, cacheDir, port });
109
+ }
110
+ else if (SUPPORTED_BROWSERNAMES.edge.includes(caps.browserName.toLowerCase())) {
111
+ /**
112
+ * Microsoft Edge
113
+ */
114
+ const edgedriverOptions = caps['wdio:edgedriverOptions'] || {};
115
+ const cacheDir = edgedriverOptions.cacheDir || options.cacheDir || os.tmpdir();
116
+ driver = 'EdgeDriver';
117
+ driverProcess = await startEdgedriver({ ...edgedriverOptions, cacheDir, port });
118
+ /**
119
+ * Microsoft Edge is very particular when it comes to browser names
120
+ */
121
+ caps.browserName = 'MicrosoftEdge';
122
+ }
123
+ else {
124
+ throw new Error(`Unknown browser name "${caps.browserName}". Make sure to pick from one of the following ` +
125
+ Object.values(SUPPORTED_BROWSERNAMES).flat(Infinity));
126
+ }
127
+ if (options.outputDir) {
128
+ const logFile = path.resolve(options.outputDir, `wdio-${driver.split(' ').shift()?.toLowerCase()}-${port}.log`);
129
+ const logStream = fs.createWriteStream(logFile, { flags: 'w' });
130
+ driverProcess.stdout?.pipe(logStream);
131
+ driverProcess.stderr?.pipe(logStream);
132
+ }
133
+ await waitPort({ port, output: 'silent' });
134
+ options.hostname = '0.0.0.0';
135
+ options.port = port;
136
+ log.info(`Started ${driver} in ${Date.now() - start}ms on port ${port}`);
137
+ return driverProcess;
138
+ }
@@ -0,0 +1,18 @@
1
+ import type { EdgedriverParameters } from 'edgedriver';
2
+ import type { Capabilities, Options } from '@wdio/types';
3
+ export declare function parseParams(params: EdgedriverParameters): string[];
4
+ export declare function getLocalChromePath(): string | undefined;
5
+ export declare function getBuildIdByPath(chromePath?: string): string | undefined;
6
+ export declare const downloadProgressCallback: (artifact: string, downloadedBytes: number, totalBytes: number) => void;
7
+ export declare function setupChrome(caps: Capabilities.Capabilities, cacheDir: string): Promise<{
8
+ platform: import("@puppeteer/browsers").BrowserPlatform;
9
+ executablePath: string;
10
+ buildId: string;
11
+ }>;
12
+ /**
13
+ * helper method to determine if we need to start a browser driver
14
+ * which is: whenever the user has set connection options that differ from
15
+ * the default, or a port is set
16
+ */
17
+ export declare function definesRemoteDriver(options: Options.WebDriver): boolean;
18
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/driver/utils.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAOxD,wBAAgB,WAAW,CAAC,MAAM,EAAE,oBAAoB,YAYvD;AAED,wBAAgB,kBAAkB,uBAOjC;AAED,wBAAgB,gBAAgB,CAAC,UAAU,CAAC,EAAE,MAAM,sBAenD;AAGD,eAAO,MAAM,wBAAwB,aAAc,MAAM,mBAAmB,MAAM,cAAc,MAAM,SAOrG,CAAA;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,YAAY,EAAE,QAAQ,EAAE,MAAM;;;;GA2ClF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,WAO7D"}
@@ -0,0 +1,108 @@
1
+ import os from 'node:os';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import cp from 'node:child_process';
5
+ import decamelize from 'decamelize';
6
+ import logger from '@wdio/logger';
7
+ import { getChromePath } from 'chrome-launcher';
8
+ import { install, canDownload, resolveBuildId, detectBrowserPlatform, Browser, ChromeReleaseChannel, computeExecutablePath } from '@puppeteer/browsers';
9
+ import { DEFAULTS } from '../constants.js';
10
+ const log = logger('webdriver');
11
+ const EXCLUDED_PARAMS = ['version', 'help'];
12
+ export function parseParams(params) {
13
+ return Object.entries(params)
14
+ .filter(([key,]) => !EXCLUDED_PARAMS.includes(key))
15
+ .map(([key, val]) => {
16
+ if (typeof val === 'boolean' && !val) {
17
+ return '';
18
+ }
19
+ const vals = Array.isArray(val) ? val : [val];
20
+ return vals.map((v) => `--${decamelize(key, { separator: '-' })}${typeof v === 'boolean' ? '' : `=${v}`}`);
21
+ })
22
+ .flat()
23
+ .filter(Boolean);
24
+ }
25
+ export function getLocalChromePath() {
26
+ try {
27
+ const chromePath = getChromePath();
28
+ return chromePath;
29
+ }
30
+ catch (err) {
31
+ return;
32
+ }
33
+ }
34
+ export function getBuildIdByPath(chromePath) {
35
+ if (!chromePath) {
36
+ return;
37
+ }
38
+ else if (os.platform() === 'win32') {
39
+ const versionPath = path.dirname(chromePath);
40
+ const contents = fs.readdirSync(versionPath);
41
+ const versions = contents.filter(a => /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/g.test(a));
42
+ // returning oldest in case there is an updated version and chrome still hasn't relaunched
43
+ const oldest = versions.sort((a, b) => a > b ? -1 : 1)[0];
44
+ return oldest;
45
+ }
46
+ const versionString = cp.execSync(`"${chromePath}" --version`).toString();
47
+ return versionString.split(' ').pop()?.trim();
48
+ }
49
+ let lastTimeCalled = Date.now();
50
+ export const downloadProgressCallback = (artifact, downloadedBytes, totalBytes) => {
51
+ if (Date.now() - lastTimeCalled < 1000) {
52
+ return;
53
+ }
54
+ const percentage = ((downloadedBytes / totalBytes) * 100).toFixed(2);
55
+ log.info(`Downloading ${artifact} ${percentage}%`);
56
+ lastTimeCalled = Date.now();
57
+ };
58
+ export async function setupChrome(caps, cacheDir) {
59
+ const platform = detectBrowserPlatform();
60
+ if (!platform) {
61
+ throw new Error('The current platform is not supported.');
62
+ }
63
+ if (!caps.browserVersion) {
64
+ const executablePath = getLocalChromePath();
65
+ const tag = getBuildIdByPath(executablePath);
66
+ /**
67
+ * verify that we have a valid Chrome browser installed
68
+ */
69
+ if (tag) {
70
+ return {
71
+ platform,
72
+ executablePath,
73
+ buildId: await resolveBuildId(Browser.CHROME, platform, tag)
74
+ };
75
+ }
76
+ }
77
+ /**
78
+ * otherwise download provided Chrome browser version or "stable"
79
+ */
80
+ const tag = caps.browserVersion || ChromeReleaseChannel.STABLE;
81
+ const buildId = await resolveBuildId(Browser.CHROME, platform, tag);
82
+ const installOptions = {
83
+ cacheDir,
84
+ platform,
85
+ buildId,
86
+ browser: Browser.CHROME,
87
+ downloadProgressCallback: (downloadedBytes, totalBytes) => downloadProgressCallback('Chrome', downloadedBytes, totalBytes)
88
+ };
89
+ const isCombinationAvailable = await canDownload(installOptions);
90
+ if (!isCombinationAvailable) {
91
+ throw new Error(`Couldn't find a matching Chrome browser for tag "${buildId}" on platform "${platform}"`);
92
+ }
93
+ log.info(`Setting up Chrome v${buildId}`);
94
+ await install(installOptions);
95
+ const executablePath = computeExecutablePath(installOptions);
96
+ return { executablePath, buildId, platform };
97
+ }
98
+ /**
99
+ * helper method to determine if we need to start a browser driver
100
+ * which is: whenever the user has set connection options that differ from
101
+ * the default, or a port is set
102
+ */
103
+ export function definesRemoteDriver(options) {
104
+ return Boolean((options.protocol && options.protocol !== DEFAULTS.protocol.default) ||
105
+ (options.hostname && options.hostname !== DEFAULTS.hostname.default) ||
106
+ Boolean(options.port) ||
107
+ (options.path && options.path !== DEFAULTS.path.default));
108
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,aAAa,CAAA;AAExD,OAAO,OAAO,MAAM,cAAc,CAAA;AAElC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAyB,YAAY,EAAE,kBAAkB,EAAsB,MAAM,YAAY,CAAA;AACxG,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAgB,MAAM,YAAY,CAAA;AAIrE,MAAM,CAAC,OAAO,OAAO,SAAS;WACb,UAAU,CACnB,OAAO,EAAE,OAAO,CAAC,SAAS,EAC1B,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAClC,aAAa,KAAK,EAClB,oBAAoB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GAC/C,OAAO,CAAC,MAAM,CAAC;IAsDlB;;OAEG;IACH,MAAM,CAAC,eAAe,CAClB,OAAO,CAAC,EAAE,aAAa,EACvB,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAClC,aAAa,KAAK,EAClB,cAAc,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GACzC,MAAM;IA0BT;;;;;;OAMG;WACU,aAAa,CAAC,QAAQ,EAAE,MAAM;IAW3C,MAAM,KAAK,SAAS,qBAEnB;CACJ;AAED;;GAEG;AACH,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAA;AAC9D,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,aAAa,CAAA;AAExD,OAAO,OAAO,MAAM,cAAc,CAAA;AAGlC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAyB,YAAY,EAAE,kBAAkB,EAAsB,MAAM,YAAY,CAAA;AACxG,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAgB,MAAM,YAAY,CAAA;AAIrE,MAAM,CAAC,OAAO,OAAO,SAAS;WACb,UAAU,CACnB,OAAO,EAAE,OAAO,CAAC,SAAS,EAC1B,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAClC,aAAa,KAAK,EAClB,oBAAoB,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GAC/C,OAAO,CAAC,MAAM,CAAC;IAyDlB;;OAEG;IACH,MAAM,CAAC,eAAe,CAClB,OAAO,CAAC,EAAE,aAAa,EACvB,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAClC,aAAa,KAAK,EAClB,cAAc,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GACzC,MAAM;IA0BT;;;;;;OAMG;WACU,aAAa,CAAC,QAAQ,EAAE,MAAM;IAW3C,MAAM,KAAK,SAAS,qBAEnB;CACJ;AAED;;GAEG;AACH,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAA;AAC9D,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA"}
package/build/index.js CHANGED
@@ -3,6 +3,7 @@ import logger from '@wdio/logger';
3
3
  import { webdriverMonad, sessionEnvironmentDetector } from '@wdio/utils';
4
4
  import { validateConfig } from '@wdio/config';
5
5
  import command from './command.js';
6
+ import { startWebDriver } from './driver/index.js';
6
7
  import { BidiHandler } from './bidi/handler.js';
7
8
  import { DEFAULTS } from './constants.js';
8
9
  import { startWebDriverSession, getPrototype, getEnvironmentVars, setupDirectConnect } from './utils.js';
@@ -23,11 +24,15 @@ export default class WebDriver {
23
24
  }
24
25
  log.info('Initiate new session using the WebDriver protocol');
25
26
  const requestedCapabilities = { ...params.capabilities };
27
+ const driverProcess = await startWebDriver(params);
26
28
  const { sessionId, capabilities } = await startWebDriverSession(params);
27
29
  const environment = sessionEnvironmentDetector({ capabilities, requestedCapabilities });
28
30
  const environmentPrototype = getEnvironmentVars(environment);
29
31
  const protocolCommands = getPrototype(environment);
30
- const prototype = { ...protocolCommands, ...environmentPrototype, ...userPrototype };
32
+ const driverPrototype = {
33
+ _driverProcess: { value: driverProcess, configurable: false, writable: true }
34
+ };
35
+ const prototype = { ...protocolCommands, ...environmentPrototype, ...userPrototype, ...driverPrototype };
31
36
  const monad = webdriverMonad({ ...params, requestedCapabilities }, modifier, prototype);
32
37
  let handler;
33
38
  if (capabilities.webSocketUrl) {
package/build/utils.js CHANGED
@@ -268,7 +268,7 @@ export const getSessionError = (err, params = {}) => {
268
268
  // browser driver / service is not started
269
269
  if (err.code === 'ECONNREFUSED') {
270
270
  return `Unable to connect to "${params.protocol}://${params.hostname}:${params.port}${params.path}", make sure browser driver is running on that address.` +
271
- '\nIf you use services like chromedriver see initialiseServices logs above or in wdio.log file as the service might had problems to start the driver.';
271
+ '\nIt seems like the service failed to start or is rejecting any connections.';
272
272
  }
273
273
  if (err.message === 'unhandled request') {
274
274
  return 'The browser driver couldn\'t start the session. Make sure you have set the "path" correctly!';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webdriver",
3
- "version": "8.13.13",
3
+ "version": "8.14.0",
4
4
  "description": "A Node.js bindings implementation for the W3C WebDriver and Mobile JSONWire Protocol",
5
5
  "author": "Christian Bromann <mail@bromann.dev>",
6
6
  "homepage": "https://github.com/webdriverio/webdriverio/tree/main/packages/webdriver",
@@ -36,17 +36,25 @@
36
36
  "url": "https://github.com/webdriverio/webdriverio/issues"
37
37
  },
38
38
  "dependencies": {
39
+ "@puppeteer/browsers": "^1.4.6",
39
40
  "@types/node": "^20.1.0",
40
41
  "@types/ws": "^8.5.3",
41
- "@wdio/config": "8.13.13",
42
+ "@wdio/config": "8.14.0",
42
43
  "@wdio/logger": "8.11.0",
43
44
  "@wdio/protocols": "8.11.0",
44
- "@wdio/types": "8.10.4",
45
- "@wdio/utils": "8.13.13",
46
- "deepmerge-ts": "^5.0.0",
45
+ "@wdio/types": "8.14.0",
46
+ "@wdio/utils": "8.14.0",
47
+ "chrome-launcher": "^1.0.0",
48
+ "decamelize": "^6.0.0",
49
+ "deepmerge-ts": "^5.1.0",
50
+ "edgedriver": "^5.3.2",
51
+ "geckodriver": "^4.1.3",
52
+ "get-port": "^7.0.0",
47
53
  "got": "^ 12.6.1",
48
54
  "ky": "^0.33.0",
55
+ "safaridriver": "^0.1.0",
56
+ "wait-port": "^1.0.4",
49
57
  "ws": "^8.8.0"
50
58
  },
51
- "gitHead": "ba97a49a1294e812ed35fc05be20dd29133ab200"
59
+ "gitHead": "cb2092b007e6d2ac23a49aa30dae67d70e45906d"
52
60
  }