@wdio/utils 8.13.13 → 8.15.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.
@@ -79,4 +79,13 @@ export declare const UNICODE_CHARACTERS: {
79
79
  readonly ZenkakuHankaku: "";
80
80
  readonly Zenkaku_Hankaku: "";
81
81
  };
82
+ export declare const SUPPORTED_BROWSERNAMES: {
83
+ chrome: string[];
84
+ firefox: string[];
85
+ edge: string[];
86
+ safari: string[];
87
+ };
88
+ export declare const DEFAULT_HOSTNAME = "0.0.0.0";
89
+ export declare const DEFAULT_PROTOCOL = "http";
90
+ export declare const DEFAULT_PATH = "/";
82
91
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4ErB,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4ErB,CAAA;AAEV,eAAO,MAAM,sBAAsB;;;;;CAKlC,CAAA;AAED,eAAO,MAAM,gBAAgB,YAAY,CAAA;AACzC,eAAO,MAAM,gBAAgB,SAAS,CAAA;AACtC,eAAO,MAAM,YAAY,MAAM,CAAA"}
@@ -79,3 +79,12 @@ export const UNICODE_CHARACTERS = {
79
79
  'ZenkakuHankaku': '\uE040',
80
80
  'Zenkaku_Hankaku': '\uE040'
81
81
  };
82
+ export const SUPPORTED_BROWSERNAMES = {
83
+ chrome: ['chrome', 'googlechrome', 'chromium', 'chromium-browser'],
84
+ firefox: ['firefox', 'ff', 'mozilla', 'mozilla firefox'],
85
+ edge: ['edge', 'microsoftedge', 'msedge'],
86
+ safari: ['safari', 'safari technology preview']
87
+ };
88
+ export const DEFAULT_HOSTNAME = '0.0.0.0';
89
+ export const DEFAULT_PROTOCOL = 'http';
90
+ export const DEFAULT_PATH = '/';
@@ -0,0 +1,22 @@
1
+ /// <reference types="node" />
2
+ import cp from 'node:child_process';
3
+ import { type SafaridriverOptions as SafaridriverParameters } from 'safaridriver';
4
+ import { type GeckodriverParameters } from 'geckodriver';
5
+ import { type EdgedriverParameters } from 'edgedriver';
6
+ import type { InstallOptions } from '@puppeteer/browsers';
7
+ import type { Options } from '@wdio/types';
8
+ export type ChromedriverParameters = InstallOptions & Omit<EdgedriverParameters, 'port' | 'edgeDriverVersion' | 'customEdgeDriverPath'>;
9
+ declare global {
10
+ namespace WebdriverIO {
11
+ interface ChromedriverOptions extends ChromedriverParameters {
12
+ }
13
+ interface GeckodriverOptions extends Omit<GeckodriverParameters, 'port'> {
14
+ }
15
+ interface EdgedriverOptions extends Omit<EdgedriverParameters, 'port'> {
16
+ }
17
+ interface SafaridriverOptions extends Omit<SafaridriverParameters, 'port'> {
18
+ }
19
+ }
20
+ }
21
+ export declare function startWebDriver(options: Options.WebDriver): Promise<cp.ChildProcess | undefined>;
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/driver/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAyB,MAAM,oBAAoB,CAAA;AAO1D,OAAO,EAA8B,KAAK,mBAAmB,IAAI,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAC7G,OAAO,EAA6B,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACnF,OAAO,EAA4B,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEzD,OAAO,KAAK,EAAgB,OAAO,EAAE,MAAM,aAAa,CAAA;AAQxD,MAAM,MAAM,sBAAsB,GAAG,cAAc,GAAG,IAAI,CAAC,oBAAoB,EAAE,MAAM,GAAG,mBAAmB,GAAG,sBAAsB,CAAC,CAAA;AACvI,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,WAAW,CAAC;QAClB,UAAU,mBAAoB,SAAQ,sBAAsB;SAAG;QAC/D,UAAU,kBAAmB,SAAQ,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC;SAAG;QAC3E,UAAU,iBAAkB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC;SAAG;QACzE,UAAU,mBAAoB,SAAQ,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC;SAAG;KAChF;CACJ;AAID,wBAAsB,cAAc,CAAE,OAAO,EAAE,OAAO,CAAC,SAAS,wCAoH/D"}
@@ -0,0 +1,117 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import cp from 'node:child_process';
4
+ import getPort from 'get-port';
5
+ import waitPort from 'wait-port';
6
+ import logger from '@wdio/logger';
7
+ import { deepmerge } from 'deepmerge-ts';
8
+ import { start as startSafaridriver } from 'safaridriver';
9
+ import { start as startGeckodriver } from 'geckodriver';
10
+ import { start as startEdgedriver } from 'edgedriver';
11
+ import { parseParams, setupChrome, definesRemoteDriver, setupChromedriver, isChrome, isFirefox, isEdge, isSafari, getCacheDir } from './utils.js';
12
+ import { SUPPORTED_BROWSERNAMES } from '../constants.js';
13
+ const log = logger('@wdio/utils');
14
+ export async function startWebDriver(options) {
15
+ /**
16
+ * in case we are running unit tests, just return
17
+ */
18
+ if (process.env.WDIO_SKIP_DRIVER_SETUP) {
19
+ options.hostname = '0.0.0.0';
20
+ options.port = 4321;
21
+ return;
22
+ }
23
+ /**
24
+ * if any of the connection parameter are set, don't start any driver
25
+ */
26
+ if (definesRemoteDriver(options)) {
27
+ log.info(`Connecting to existing driver at ${options.protocol}://${options.hostname}:${options.port}${options.path}`);
28
+ return;
29
+ }
30
+ let driverProcess;
31
+ let driver = '';
32
+ const start = Date.now();
33
+ const caps = options.capabilities.alwaysMatch || options.capabilities;
34
+ /**
35
+ * session might be a mobile session so don't do anything
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 mobile session with Appium, make sure to set "hostname" and "port" in your ' +
40
+ 'WebdriverIO options. If you like to run a local browser session make sure to pick from one of ' +
41
+ `the following browser names: ${Object.values(SUPPORTED_BROWSERNAMES).flat(Infinity)}`);
42
+ }
43
+ const port = await getPort();
44
+ const cacheDir = getCacheDir(options, caps);
45
+ if (isChrome(caps.browserName)) {
46
+ /**
47
+ * Chrome
48
+ */
49
+ const chromedriverOptions = caps['wdio:chromedriverOptions'] || {};
50
+ const { executablePath: chromeExecuteablePath, browserVersion } = await setupChrome(cacheDir, caps);
51
+ const { executablePath: chromedriverExcecuteablePath } = await setupChromedriver(cacheDir, browserVersion);
52
+ caps['goog:chromeOptions'] = deepmerge({ binary: chromeExecuteablePath }, caps['goog:chromeOptions'] || {});
53
+ chromedriverOptions.allowedOrigins = chromedriverOptions.allowedOrigins || ['*'];
54
+ chromedriverOptions.allowedIps = chromedriverOptions.allowedIps || [''];
55
+ const driverParams = parseParams({ port, ...chromedriverOptions });
56
+ driverProcess = cp.spawn(chromedriverExcecuteablePath, driverParams);
57
+ driver = `Chromedriver v${browserVersion} with params ${driverParams.join(' ')}`;
58
+ }
59
+ else if (isSafari(caps.browserName)) {
60
+ const safaridriverOptions = caps['wdio:safaridriverOptions'] || {};
61
+ /**
62
+ * Safari
63
+ */
64
+ driver = 'SafariDriver';
65
+ driverProcess = startSafaridriver({
66
+ useTechnologyPreview: Boolean(caps.browserName.match(/preview/i)),
67
+ ...safaridriverOptions,
68
+ port
69
+ });
70
+ /**
71
+ * set "Host" header as it is required by Safaridriver
72
+ */
73
+ options.headers = deepmerge({ Host: 'localhost' }, (options.headers || {}));
74
+ }
75
+ else if (isFirefox(caps.browserName)) {
76
+ /**
77
+ * Firefox
78
+ */
79
+ const geckodriverOptions = caps['wdio:geckodriverOptions'] || {};
80
+ driver = 'GeckoDriver';
81
+ driverProcess = await startGeckodriver({ ...geckodriverOptions, cacheDir, port });
82
+ }
83
+ else if (isEdge(caps.browserName)) {
84
+ /**
85
+ * Microsoft Edge
86
+ */
87
+ const edgedriverOptions = caps['wdio:edgedriverOptions'] || {};
88
+ driver = 'EdgeDriver';
89
+ driverProcess = await startEdgedriver({ ...edgedriverOptions, cacheDir, port }).catch((err) => {
90
+ log.warn(`Couldn't start EdgeDriver: ${err.message}, retry ...`);
91
+ return startEdgedriver({ ...edgedriverOptions, cacheDir, port });
92
+ });
93
+ /**
94
+ * Microsoft Edge is very particular when it comes to browser names
95
+ */
96
+ caps.browserName = 'MicrosoftEdge';
97
+ }
98
+ else {
99
+ throw new Error(`Unknown browser name "${caps.browserName}". Make sure to pick from one of the following ` +
100
+ Object.values(SUPPORTED_BROWSERNAMES).flat(Infinity));
101
+ }
102
+ if (options.outputDir) {
103
+ const logIdentifier = driver.split(' ').shift()?.toLowerCase();
104
+ const logFileName = process.env.WDIO_WORKER_ID
105
+ ? `wdio-${process.env.WDIO_WORKER_ID}-${logIdentifier}.log`
106
+ : `wdio-${logIdentifier}-${port}.log`;
107
+ const logFile = path.resolve(options.outputDir, logFileName);
108
+ const logStream = fs.createWriteStream(logFile, { flags: 'w' });
109
+ driverProcess.stdout?.pipe(logStream);
110
+ driverProcess.stderr?.pipe(logStream);
111
+ }
112
+ await waitPort({ port, output: 'silent' });
113
+ options.hostname = '0.0.0.0';
114
+ options.port = port;
115
+ log.info(`Started ${driver} in ${Date.now() - start}ms on port ${port}`);
116
+ return driverProcess;
117
+ }
@@ -0,0 +1,4 @@
1
+ import type { Options, Capabilities } from '@wdio/types';
2
+ export declare function setupDriver(options: Omit<Options.WebDriver, 'capabilities'>, caps: Capabilities.RemoteCapabilities): Promise<unknown[] | undefined>;
3
+ export declare function setupBrowser(options: Omit<Options.WebDriver, 'capabilities'>, caps: Capabilities.RemoteCapabilities): Promise<unknown[]> | undefined;
4
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/driver/manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAyFxD,wBAAsB,WAAW,CAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,IAAI,EAAE,YAAY,CAAC,kBAAkB,kCAazH;AAED,wBAAgB,YAAY,CAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,IAAI,EAAE,YAAY,CAAC,kBAAkB,kCAepH"}
@@ -0,0 +1,98 @@
1
+ import logger from '@wdio/logger';
2
+ import { getCacheDir, definesRemoteDriver, isSafari, isEdge, isFirefox, isChrome, setupChromedriver, setupEdgedriver, setupGeckodriver, setupChrome } from './utils.js';
3
+ const log = logger('@wdio/utils');
4
+ const UNDEFINED_BROWSER_VERSION = null;
5
+ function mapCapabilities(options, caps, task, taskItemLabel) {
6
+ const capabilitiesToRequireSetup = (Array.isArray(caps)
7
+ ? caps.map((cap) => {
8
+ const w3cCaps = cap;
9
+ const multiremoteCaps = cap;
10
+ const isMultiremote = Boolean(multiremoteCaps[Object.keys(cap)[0]].capabilities);
11
+ if (isMultiremote) {
12
+ return Object.values(multiremoteCaps).map((c) => c.capabilities);
13
+ }
14
+ else if (w3cCaps.alwaysMatch) {
15
+ return w3cCaps.alwaysMatch;
16
+ }
17
+ return cap;
18
+ }).flat()
19
+ : Object.values(caps).map((mrOpts) => {
20
+ const w3cCaps = mrOpts.capabilities;
21
+ if (w3cCaps.alwaysMatch) {
22
+ return w3cCaps.alwaysMatch;
23
+ }
24
+ return mrOpts.capabilities;
25
+ })).flat().filter((cap) => (
26
+ /**
27
+ * only set up driver if
28
+ * - browserName is defined so we know it is a browser session
29
+ * - we are not about to run a cloud session
30
+ * - we are not running Safari (driver already installed on macOS)
31
+ */
32
+ cap.browserName &&
33
+ !definesRemoteDriver(options) &&
34
+ !isSafari(cap.browserName)));
35
+ /**
36
+ * nothing to setup
37
+ */
38
+ if (capabilitiesToRequireSetup.length === 0) {
39
+ return;
40
+ }
41
+ /**
42
+ * get all browser names and versions that need driver setup
43
+ */
44
+ const queueByBrowserName = capabilitiesToRequireSetup.reduce((queue, cap) => {
45
+ if (!cap.browserName) {
46
+ return queue;
47
+ }
48
+ if (!queue.has(cap.browserName)) {
49
+ queue.set(cap.browserName, new Map());
50
+ }
51
+ const browserVersion = cap.browserVersion || UNDEFINED_BROWSER_VERSION;
52
+ queue.get(cap.browserName).set(browserVersion, cap);
53
+ return queue;
54
+ }, new Map());
55
+ const driverToSetupString = Array.from(queueByBrowserName.entries())
56
+ .map(([browserName, versions]) => `${browserName}@${Array.from(versions.keys()).map((bv) => bv || 'stable').join(', ')}`)
57
+ .join(' - ');
58
+ log.info(`Setting up ${taskItemLabel} for: ${driverToSetupString}`);
59
+ return Promise.all(Array.from(queueByBrowserName.entries()).map(([browserName, queueByBrowserVersion]) => {
60
+ return Array.from(queueByBrowserVersion).map(([browserVersion, cap]) => task({
61
+ ...cap,
62
+ browserName,
63
+ ...(browserVersion !== UNDEFINED_BROWSER_VERSION ? { browserVersion } : {})
64
+ }));
65
+ }).flat());
66
+ }
67
+ export async function setupDriver(options, caps) {
68
+ return mapCapabilities(options, caps, async (cap) => {
69
+ const cacheDir = getCacheDir(options, cap);
70
+ if (isEdge(cap.browserName)) {
71
+ return setupEdgedriver(cacheDir, cap.browserVersion);
72
+ }
73
+ else if (isFirefox(cap.browserName)) {
74
+ return setupGeckodriver(cacheDir, cap.browserVersion);
75
+ }
76
+ else if (isChrome(cap.browserName)) {
77
+ return setupChromedriver(cacheDir, cap.browserVersion);
78
+ }
79
+ return Promise.resolve();
80
+ }, 'browser driver');
81
+ }
82
+ export function setupBrowser(options, caps) {
83
+ return mapCapabilities(options, caps, async (cap) => {
84
+ const cacheDir = getCacheDir(options, cap);
85
+ if (isEdge(cap.browserName)) {
86
+ // not yet implemented
87
+ return Promise.resolve();
88
+ }
89
+ else if (isFirefox(cap.browserName)) {
90
+ // not yet implemented
91
+ return Promise.resolve();
92
+ }
93
+ else if (isChrome(cap.browserName)) {
94
+ return setupChrome(cacheDir, cap);
95
+ }
96
+ return Promise.resolve();
97
+ }, 'browser binaries');
98
+ }
@@ -0,0 +1,36 @@
1
+ import type { EdgedriverParameters } from 'edgedriver';
2
+ import type { Options, Capabilities } 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(cacheDir: string, caps: Capabilities.Capabilities): Promise<{
8
+ cacheDir: string;
9
+ platform: import("@puppeteer/browsers").BrowserPlatform;
10
+ executablePath: string;
11
+ buildId: string;
12
+ browserVersion?: undefined;
13
+ } | {
14
+ executablePath: string;
15
+ browserVersion: string;
16
+ cacheDir?: undefined;
17
+ platform?: undefined;
18
+ buildId?: undefined;
19
+ }>;
20
+ export declare function getCacheDir(options: Pick<Options.WebDriver, 'cacheDir'>, caps: Capabilities.Capabilities): string;
21
+ export declare function setupChromedriver(cacheDir: string, driverVersion?: string): Promise<{
22
+ executablePath: string;
23
+ }>;
24
+ export declare function setupGeckodriver(cacheDir: string, driverVersion?: string): Promise<string>;
25
+ export declare function setupEdgedriver(cacheDir: string, driverVersion?: string): Promise<string>;
26
+ /**
27
+ * helper method to determine if we need to start a browser driver
28
+ * which is: whenever the user has set connection options that differ from
29
+ * the default, or a port is set
30
+ */
31
+ export declare function definesRemoteDriver(options: Pick<Options.WebDriver, 'protocol' | 'hostname' | 'port' | 'path'>): boolean;
32
+ export declare function isChrome(browserName?: string): boolean;
33
+ export declare function isSafari(browserName?: string): boolean;
34
+ export declare function isFirefox(browserName?: string): boolean;
35
+ export declare function isEdge(browserName?: string): boolean;
36
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/driver/utils.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,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,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,YAAY;;;;;;;;;;;;GAmDlF;AAED,wBAAgB,WAAW,CAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,IAAI,EAAE,YAAY,CAAC,YAAY,UASzG;AAED,wBAAsB,iBAAiB,CAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM;;GA8DhF;AAED,wBAAgB,gBAAgB,CAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,mBAEzE;AAED,wBAAgB,eAAe,CAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,mBAExE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC,WAO9G;AAED,wBAAgB,QAAQ,CAAE,WAAW,CAAC,EAAE,MAAM,WAE7C;AACD,wBAAgB,QAAQ,CAAE,WAAW,CAAC,EAAE,MAAM,WAE7C;AACD,wBAAgB,SAAS,CAAE,WAAW,CAAC,EAAE,MAAM,WAE9C;AACD,wBAAgB,MAAM,CAAE,WAAW,CAAC,EAAE,MAAM,WAE3C"}
@@ -0,0 +1,207 @@
1
+ import os from 'node:os';
2
+ import fs from 'node:fs';
3
+ import fsp from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import cp from 'node:child_process';
6
+ import got from 'got';
7
+ import decamelize from 'decamelize';
8
+ import logger from '@wdio/logger';
9
+ import { getChromePath } from 'chrome-launcher';
10
+ import { install, canDownload, resolveBuildId, detectBrowserPlatform, Browser, ChromeReleaseChannel, computeExecutablePath } from '@puppeteer/browsers';
11
+ import { download as downloadGeckodriver } from 'geckodriver';
12
+ import { download as downloadEdgedriver } from 'edgedriver';
13
+ import { DEFAULT_HOSTNAME, DEFAULT_PROTOCOL, DEFAULT_PATH, SUPPORTED_BROWSERNAMES } from '../constants.js';
14
+ const log = logger('webdriver');
15
+ const EXCLUDED_PARAMS = ['version', 'help'];
16
+ export function parseParams(params) {
17
+ return Object.entries(params)
18
+ .filter(([key,]) => !EXCLUDED_PARAMS.includes(key))
19
+ .map(([key, val]) => {
20
+ if (typeof val === 'boolean' && !val) {
21
+ return '';
22
+ }
23
+ const vals = Array.isArray(val) ? val : [val];
24
+ return vals.map((v) => `--${decamelize(key, { separator: '-' })}${typeof v === 'boolean' ? '' : `=${v}`}`);
25
+ })
26
+ .flat()
27
+ .filter(Boolean);
28
+ }
29
+ export function getLocalChromePath() {
30
+ try {
31
+ const chromePath = getChromePath();
32
+ return chromePath;
33
+ }
34
+ catch (err) {
35
+ return;
36
+ }
37
+ }
38
+ export function getBuildIdByPath(chromePath) {
39
+ if (!chromePath) {
40
+ return;
41
+ }
42
+ else if (os.platform() === 'win32') {
43
+ const versionPath = path.dirname(chromePath);
44
+ const contents = fs.readdirSync(versionPath);
45
+ const versions = contents.filter(a => /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/g.test(a));
46
+ // returning oldest in case there is an updated version and chrome still hasn't relaunched
47
+ const oldest = versions.sort((a, b) => a > b ? -1 : 1)[0];
48
+ return oldest;
49
+ }
50
+ const versionString = cp.execSync(`"${chromePath}" --version`).toString();
51
+ return versionString.split(' ').pop()?.trim();
52
+ }
53
+ let lastTimeCalled = Date.now();
54
+ export const downloadProgressCallback = (artifact, downloadedBytes, totalBytes) => {
55
+ if (Date.now() - lastTimeCalled < 1000) {
56
+ return;
57
+ }
58
+ const percentage = ((downloadedBytes / totalBytes) * 100).toFixed(2);
59
+ log.info(`Downloading ${artifact} ${percentage}%`);
60
+ lastTimeCalled = Date.now();
61
+ };
62
+ export async function setupChrome(cacheDir, caps) {
63
+ caps.browserName = caps.browserName?.toLowerCase();
64
+ const exist = await fsp.access(cacheDir).then(() => true, () => false);
65
+ if (!exist) {
66
+ await fsp.mkdir(cacheDir, { recursive: true });
67
+ }
68
+ const platform = detectBrowserPlatform();
69
+ if (!platform) {
70
+ throw new Error('The current platform is not supported.');
71
+ }
72
+ if (!caps.browserVersion) {
73
+ const executablePath = getLocalChromePath();
74
+ const tag = getBuildIdByPath(executablePath);
75
+ /**
76
+ * verify that we have a valid Chrome browser installed
77
+ */
78
+ if (tag) {
79
+ return {
80
+ cacheDir,
81
+ platform,
82
+ executablePath,
83
+ buildId: await resolveBuildId(Browser.CHROME, platform, tag)
84
+ };
85
+ }
86
+ }
87
+ /**
88
+ * otherwise download provided Chrome browser version or "stable"
89
+ */
90
+ const tag = caps.browserVersion || ChromeReleaseChannel.STABLE;
91
+ const buildId = await resolveBuildId(Browser.CHROME, platform, tag);
92
+ const installOptions = {
93
+ unpack: true,
94
+ cacheDir,
95
+ platform,
96
+ buildId,
97
+ browser: Browser.CHROME,
98
+ downloadProgressCallback: (downloadedBytes, totalBytes) => downloadProgressCallback('Chrome', downloadedBytes, totalBytes)
99
+ };
100
+ const isCombinationAvailable = await canDownload(installOptions);
101
+ if (!isCombinationAvailable) {
102
+ throw new Error(`Couldn't find a matching Chrome browser for tag "${buildId}" on platform "${platform}"`);
103
+ }
104
+ log.info(`Setting up Chrome v${buildId}`);
105
+ await install(installOptions);
106
+ const executablePath = computeExecutablePath(installOptions);
107
+ return { executablePath, browserVersion: buildId };
108
+ }
109
+ export function getCacheDir(options, caps) {
110
+ const driverOptions = (caps['wdio:chromedriverOptions'] ||
111
+ caps['wdio:chromedriverOptions'] ||
112
+ caps['wdio:chromedriverOptions'] ||
113
+ caps['wdio:chromedriverOptions'] ||
114
+ {});
115
+ return driverOptions.cacheDir || options.cacheDir || os.tmpdir();
116
+ }
117
+ export async function setupChromedriver(cacheDir, driverVersion) {
118
+ const platform = detectBrowserPlatform();
119
+ if (!platform) {
120
+ throw new Error('The current platform is not supported.');
121
+ }
122
+ const version = driverVersion || getBuildIdByPath(getLocalChromePath()) || ChromeReleaseChannel.STABLE;
123
+ const buildId = await resolveBuildId(Browser.CHROMEDRIVER, platform, version);
124
+ let executablePath = computeExecutablePath({
125
+ browser: Browser.CHROMEDRIVER,
126
+ buildId,
127
+ platform,
128
+ cacheDir
129
+ });
130
+ let loggedBuildId = buildId;
131
+ const hasChromedriverInstalled = await fsp.access(executablePath).then(() => true, () => false);
132
+ if (!hasChromedriverInstalled) {
133
+ log.info(`Downloading Chromedriver v${buildId}`);
134
+ const chromedriverInstallOpts = {
135
+ cacheDir,
136
+ buildId,
137
+ platform,
138
+ browser: Browser.CHROMEDRIVER,
139
+ unpack: true,
140
+ downloadProgressCallback: (downloadedBytes, totalBytes) => downloadProgressCallback('Chromedriver', downloadedBytes, totalBytes)
141
+ };
142
+ try {
143
+ await install({ ...chromedriverInstallOpts, buildId });
144
+ }
145
+ catch (err) {
146
+ /**
147
+ * in case we detect a Chrome browser installed for which there is no Chromedriver available
148
+ * we are falling back to the latest known good version
149
+ */
150
+ log.warn(`Couldn't download Chromedriver v${buildId}: ${err.message}, trying to find known good version...`);
151
+ let knownGoodVersion;
152
+ if (buildId.includes('.')) {
153
+ const majorVersion = buildId.split('.')[0];
154
+ const knownGoodVersions = await got('https://googlechromelabs.github.io/chrome-for-testing/known-good-versions.json').json();
155
+ const versionMatch = knownGoodVersions.versions.filter(({ version }) => version.startsWith(majorVersion)).pop();
156
+ if (!versionMatch) {
157
+ throw new Error(`Couldn't find known good version for Chromedriver v${majorVersion}`);
158
+ }
159
+ knownGoodVersion = versionMatch.version;
160
+ }
161
+ else {
162
+ knownGoodVersion = await resolveBuildId(Browser.CHROMEDRIVER, platform, buildId);
163
+ }
164
+ loggedBuildId = knownGoodVersion;
165
+ await install({ ...chromedriverInstallOpts, buildId: loggedBuildId });
166
+ executablePath = computeExecutablePath({
167
+ browser: Browser.CHROMEDRIVER,
168
+ buildId: loggedBuildId,
169
+ platform,
170
+ cacheDir
171
+ });
172
+ }
173
+ }
174
+ else {
175
+ log.info(`Using Chromedriver v${buildId} from cache directory ${cacheDir}`);
176
+ }
177
+ return { executablePath };
178
+ }
179
+ export function setupGeckodriver(cacheDir, driverVersion) {
180
+ return downloadGeckodriver(driverVersion, cacheDir);
181
+ }
182
+ export function setupEdgedriver(cacheDir, driverVersion) {
183
+ return downloadEdgedriver(driverVersion, cacheDir);
184
+ }
185
+ /**
186
+ * helper method to determine if we need to start a browser driver
187
+ * which is: whenever the user has set connection options that differ from
188
+ * the default, or a port is set
189
+ */
190
+ export function definesRemoteDriver(options) {
191
+ return Boolean((options.protocol && options.protocol !== DEFAULT_PROTOCOL) ||
192
+ (options.hostname && options.hostname !== DEFAULT_HOSTNAME) ||
193
+ Boolean(options.port) ||
194
+ (options.path && options.path !== DEFAULT_PATH));
195
+ }
196
+ export function isChrome(browserName) {
197
+ return Boolean(browserName && SUPPORTED_BROWSERNAMES.chrome.includes(browserName.toLowerCase()));
198
+ }
199
+ export function isSafari(browserName) {
200
+ return Boolean(browserName && SUPPORTED_BROWSERNAMES.safari.includes(browserName.toLowerCase()));
201
+ }
202
+ export function isFirefox(browserName) {
203
+ return Boolean(browserName && SUPPORTED_BROWSERNAMES.firefox.includes(browserName.toLowerCase()));
204
+ }
205
+ export function isEdge(browserName) {
206
+ return Boolean(browserName && SUPPORTED_BROWSERNAMES.edge.includes(browserName.toLowerCase()));
207
+ }
@@ -57,9 +57,9 @@ function isChrome(capabilities) {
57
57
  return Boolean(capabilities.chrome || capabilities['goog:chromeOptions']);
58
58
  }
59
59
  /**
60
- * check if session is run by Chromedriver
60
+ * check if session is run by Geckodriver
61
61
  * @param {Object} capabilities caps of session response
62
- * @return {Boolean} true if run by Chromedriver
62
+ * @return {Boolean} true if run by Geckodriver
63
63
  */
64
64
  function isFirefox(capabilities) {
65
65
  if (!capabilities) {
package/build/index.d.ts CHANGED
@@ -5,8 +5,10 @@ import { commandCallStructure, isValidParameter, getArgumentType, safeImport, is
5
5
  import { wrapCommand, executeHooksWithArgs, executeAsync } from './shim.js';
6
6
  import { testFnWrapper, wrapGlobalTestMethod } from './test-framework/index.js';
7
7
  import { isW3C, capabilitiesEnvironmentDetector, sessionEnvironmentDetector, devtoolsEnvironmentDetector } from './envDetector.js';
8
+ import { startWebDriver } from './driver/index.js';
9
+ import { setupDriver, setupBrowser } from './driver/manager.js';
8
10
  import { UNICODE_CHARACTERS } from './constants.js';
9
- export { initialisePlugin, initialiseLauncherService, initialiseWorkerService, isFunctionAsync, transformCommandLogResult, webdriverMonad, commandCallStructure, isValidParameter, getArgumentType, safeImport, canAccess, sleep,
11
+ export { initialisePlugin, initialiseLauncherService, initialiseWorkerService, isFunctionAsync, transformCommandLogResult, webdriverMonad, commandCallStructure, isValidParameter, getArgumentType, safeImport, canAccess, sleep, startWebDriver, setupBrowser, setupDriver,
10
12
  /**
11
13
  * runner shim
12
14
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,gBAAgB,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAA;AAC5F,OAAO,cAAc,MAAM,YAAY,CAAA;AACvC,OAAO,EACH,oBAAoB,EAAE,gBAAgB,EAAE,eAAe,EAAE,UAAU,EACnE,eAAe,EAAE,yBAAyB,EAAE,SAAS,EAAE,KAAK,EAC/D,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAC/E,OAAO,EACH,KAAK,EAAE,+BAA+B,EACtC,0BAA0B,EAAE,2BAA2B,EAC1D,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAEnD,OAAO,EACH,gBAAgB,EAChB,yBAAyB,EACzB,uBAAuB,EACvB,eAAe,EACf,yBAAyB,EACzB,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,SAAS,EACT,KAAK;AAEL;;GAEG;AACH,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,aAAa,EACb,oBAAoB;AAEpB;;GAEG;AACH,KAAK,EACL,0BAA0B,EAC1B,+BAA+B,EAC/B,2BAA2B;AAE3B;;GAEG;AACH,kBAAkB,EACrB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,gBAAgB,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAA;AAC5F,OAAO,cAAc,MAAM,YAAY,CAAA;AACvC,OAAO,EACH,oBAAoB,EAAE,gBAAgB,EAAE,eAAe,EAAE,UAAU,EACnE,eAAe,EAAE,yBAAyB,EAAE,SAAS,EAAE,KAAK,EAC/D,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAC/E,OAAO,EACH,KAAK,EAAE,+BAA+B,EACtC,0BAA0B,EAAE,2BAA2B,EAC1D,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAEnD,OAAO,EACH,gBAAgB,EAChB,yBAAyB,EACzB,uBAAuB,EACvB,eAAe,EACf,yBAAyB,EACzB,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,SAAS,EACT,KAAK,EACL,cAAc,EACd,YAAY,EACZ,WAAW;AAEX;;GAEG;AACH,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,aAAa,EACb,oBAAoB;AAEpB;;GAEG;AACH,KAAK,EACL,0BAA0B,EAC1B,+BAA+B,EAC/B,2BAA2B;AAE3B;;GAEG;AACH,kBAAkB,EACrB,CAAA"}
package/build/index.js CHANGED
@@ -6,8 +6,10 @@ import { commandCallStructure, isValidParameter, getArgumentType, safeImport, is
6
6
  import { wrapCommand, executeHooksWithArgs, executeAsync } from './shim.js';
7
7
  import { testFnWrapper, wrapGlobalTestMethod } from './test-framework/index.js';
8
8
  import { isW3C, capabilitiesEnvironmentDetector, sessionEnvironmentDetector, devtoolsEnvironmentDetector } from './envDetector.js';
9
+ import { startWebDriver } from './driver/index.js';
10
+ import { setupDriver, setupBrowser } from './driver/manager.js';
9
11
  import { UNICODE_CHARACTERS } from './constants.js';
10
- export { initialisePlugin, initialiseLauncherService, initialiseWorkerService, isFunctionAsync, transformCommandLogResult, webdriverMonad, commandCallStructure, isValidParameter, getArgumentType, safeImport, canAccess, sleep,
12
+ export { initialisePlugin, initialiseLauncherService, initialiseWorkerService, isFunctionAsync, transformCommandLogResult, webdriverMonad, commandCallStructure, isValidParameter, getArgumentType, safeImport, canAccess, sleep, startWebDriver, setupBrowser, setupDriver,
11
13
  /**
12
14
  * runner shim
13
15
  */
@@ -1 +1 @@
1
- {"version":3,"file":"shim.d.ts","sourceRoot":"","sources":["../src/shim.ts"],"names":[],"mappings":"AAQA,UAAU,OAAO;IACb,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACnB;AAED,OAAO,CAAC,MAAM,CAAC;IAEX,IAAI,WAAW,EAAE,GAAG,CAAA;CACvB;AAED,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM,CAAC;QACb,UAAU,MAAM;YACZ,MAAM,EAAE,GAAG,CAAA;YACX,WAAW,EAAE,GAAG,CAAA;SACnB;KACJ;CACJ;AAaD,QAAA,MAAM,oBAAoB,YAAqD,GAAG,YAAY,MAAM,UAAS,QAAQ,GAAG,QAAQ,EAAE,SAAa,GAAG,EAAE,2BA6CnJ,CAAA;AAED;;;;GAIG;AACH,QAAA,MAAM,WAAW,mBAAwC,MAAM,MAAM,QAAQ,eAAa,GAAG,eAkL5F,CAAA;AAED;;;;;;;GAOG;AACH,iBAAe,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAmBzG;AAED,OAAO,EACH,oBAAoB,EACpB,WAAW,EACX,YAAY,GACf,CAAA"}
1
+ {"version":3,"file":"shim.d.ts","sourceRoot":"","sources":["../src/shim.ts"],"names":[],"mappings":"AASA,UAAU,OAAO;IACb,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACnB;AAED,OAAO,CAAC,MAAM,CAAC;IAEX,IAAI,WAAW,EAAE,GAAG,CAAA;CACvB;AAED,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM,CAAC;QACb,UAAU,MAAM;YACZ,MAAM,EAAE,GAAG,CAAA;YACX,WAAW,EAAE,GAAG,CAAA;SACnB;KACJ;CACJ;AAaD,QAAA,MAAM,oBAAoB,YAAqD,GAAG,YAAY,MAAM,UAAS,QAAQ,GAAG,QAAQ,EAAE,SAAa,GAAG,EAAE,2BA6CnJ,CAAA;AAED;;;;GAIG;AACH,QAAA,MAAM,WAAW,mBAAwC,MAAM,MAAM,QAAQ,eAAa,GAAG,eAkL5F,CAAA;AAED;;;;;;;GAOG;AACH,iBAAe,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAmBzG;AAED,OAAO,EACH,oBAAoB,EACpB,WAAW,EACX,YAAY,GACf,CAAA"}
package/build/shim.js CHANGED
@@ -1,5 +1,5 @@
1
- import * as iterators from './pIteration.js';
2
1
  import logger from '@wdio/logger';
2
+ import * as iterators from './pIteration.js';
3
3
  const log = logger('@wdio/utils:shim');
4
4
  let inCommandHook = false;
5
5
  const ELEMENT_QUERY_COMMANDS = [
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAW,MAAM,aAAa,CAAA;AAMpD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,gBAAgB,EAAE;IAAE,sBAAsB,CAAC,EAAE;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,QAwCzH;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,MAAM,UAAQ,UA+BrF;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAE,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;;;EAapF;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAE,GAAG,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,WA8B/D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAE,GAAG,EAAE,GAAG,wGAExC;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,GAAG,IAAI,CAAC,CA4DtF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAE,EAAE,EAAE,QAAQ,WAE5C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAE,IAAI,EAAE,GAAG,EAAE,SAE1C;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,WAenC;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,UAAW,MAAM,YAWtC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,KAAK,mCAAoD,CAAA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAW,MAAM,aAAa,CAAA;AAMpD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,gBAAgB,EAAE;IAAE,sBAAsB,CAAC,EAAE;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,QAwCzH;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,MAAM,UAAQ,UA+BrF;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAE,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;;;EAapF;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAE,GAAG,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,WA8B/D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAE,GAAG,EAAE,GAAG,wGAExC;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,GAAG,IAAI,CAAC,CA2DtF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAE,EAAE,EAAE,QAAQ,WAE5C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAE,IAAI,EAAE,GAAG,EAAE,SAE1C;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,WAenC;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,UAAW,MAAM,YAWtC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,KAAK,mCAAoD,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdio/utils",
3
- "version": "8.13.13",
3
+ "version": "8.15.0",
4
4
  "description": "A WDIO helper utility to provide several utility functions used across the project.",
5
5
  "author": "Christian Bromann <mail@bromann.dev>",
6
6
  "homepage": "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-utils",
@@ -30,12 +30,22 @@
30
30
  "url": "https://github.com/webdriverio/webdriverio/issues"
31
31
  },
32
32
  "dependencies": {
33
+ "@puppeteer/browsers": "^1.6.0",
33
34
  "@wdio/logger": "8.11.0",
34
- "@wdio/types": "8.10.4",
35
- "import-meta-resolve": "^3.0.0"
35
+ "@wdio/types": "8.15.0",
36
+ "chrome-launcher": "^1.0.0",
37
+ "decamelize": "^6.0.0",
38
+ "deepmerge-ts": "^5.1.0",
39
+ "edgedriver": "^5.3.3",
40
+ "geckodriver": "^4.2.0",
41
+ "get-port": "^7.0.0",
42
+ "got": "^13.0.0",
43
+ "import-meta-resolve": "^3.0.0",
44
+ "safaridriver": "^0.1.0",
45
+ "wait-port": "^1.0.4"
36
46
  },
37
47
  "publishConfig": {
38
48
  "access": "public"
39
49
  },
40
- "gitHead": "ba97a49a1294e812ed35fc05be20dd29133ab200"
50
+ "gitHead": "78e199c5ffd74bdf3a5576952c3834c29afa989f"
41
51
  }