UNPKG

wdio-chromedriver-service

Version:
137 lines (136 loc) 6.46 kB
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _ChromeDriverLauncher_pollTimeout; import path from 'node:path'; import { spawn } from 'node:child_process'; import fs from 'fs-extra'; import split2 from 'split2'; import logger from '@wdio/logger'; import tcpPortUsed from 'tcp-port-used'; import { SevereServiceError } from 'webdriverio'; import getFilePath from './utils/getFilePath.js'; import { pkg } from './constants.js'; const log = logger('chromedriver'); const DEFAULT_LOG_FILENAME = 'wdio-chromedriver.log'; const POLL_INTERVAL = 100; const DEFAULT_POLL_TIMEOUT = 10000; const DEFAULT_CONNECTION = { protocol: 'http', hostname: 'localhost', port: 9515, path: '/' }; const isMultiremote = (obj) => typeof obj === 'object' && !Array.isArray(obj); const isChrome = (cap) => cap.browserName && cap.browserName.toLowerCase() === 'chrome'; export default class ChromeDriverLauncher { constructor(options, capabilities, config) { _ChromeDriverLauncher_pollTimeout.set(this, void 0); log.info(`Initiate Chromedriver Launcher (v${pkg.version})`); __classPrivateFieldSet(this, _ChromeDriverLauncher_pollTimeout, options.pollTimeout || DEFAULT_POLL_TIMEOUT, "f"); this.options = { protocol: options.protocol || DEFAULT_CONNECTION.protocol, hostname: options.hostname || DEFAULT_CONNECTION.hostname, port: options.port || DEFAULT_CONNECTION.port, path: options.path || DEFAULT_CONNECTION.path }; this.outputDir = options.outputDir || config.outputDir; this.logFileName = options.logFileName || DEFAULT_LOG_FILENAME; this.capabilities = capabilities; this.args = options.args || []; this.chromedriverCustomPath = options.chromedriverCustomPath; } async onPrepare() { this.args.forEach(argument => { if (argument.includes('--port')) { throw new Error('Argument "--port" already exists'); } if (argument.includes('--url-base')) { throw new Error('Argument "--url-base" already exists'); } }); this.args.push(`--port=${this.options.port}`); this.args.push(`--url-base=${this.options.path}`); this._mapCapabilities(); let command = this.chromedriverCustomPath ? path.resolve(this.chromedriverCustomPath) : await this._getChromedriverPath(); log.info(`Start Chromedriver (${command}) with args ${this.args.join(' ')}`); if (!fs.existsSync(command)) { log.warn('Could not find chromedriver in default path: ', command); log.warn('Falling back to use global chromedriver bin'); command = process && process.platform === 'win32' ? 'chromedriver.exe' : 'chromedriver'; } try { await tcpPortUsed.waitUntilFree(this.options.port, POLL_INTERVAL, __classPrivateFieldGet(this, _ChromeDriverLauncher_pollTimeout, "f")); } catch (err) { throw new SevereServiceError(`Couldn't start Chromedriver: ${err.message}\n` + `Please check if port ${this.options.port} is in use!`); } this.process = spawn(command, this.args); if (typeof this.outputDir === 'string') { await this._redirectLogStream(this.process, this.outputDir); } else { this.process.stdout.pipe(split2()).on('data', log.info); this.process.stderr.pipe(split2()).on('data', log.warn); } try { await tcpPortUsed.waitUntilUsed(this.options.port, POLL_INTERVAL, __classPrivateFieldGet(this, _ChromeDriverLauncher_pollTimeout, "f")); } catch (err) { throw new SevereServiceError(`Couldn't start Chromedriver: ${err.message}\n` + 'Chromedriver failed to start.'); } process.on('exit', this.onComplete.bind(this)); process.on('SIGINT', this.onComplete.bind(this)); process.on('uncaughtException', this.onComplete.bind(this)); } onComplete() { if (this.process) { this.process.kill(); } } async _redirectLogStream(process, outputDir) { const logFile = getFilePath(outputDir, this.logFileName); await fs.ensureFile(logFile); const logStream = fs.createWriteStream(logFile, { flags: 'w' }); process.stdout.pipe(logStream); process.stderr.pipe(logStream); } _mapCapabilities() { if (isMultiremote(this.capabilities)) { for (const cap in this.capabilities) { if (isChrome(this.capabilities[cap].capabilities)) { Object.assign(this.capabilities[cap], this.options); } } } else { for (const cap of this.capabilities) { if (isChrome(cap)) { Object.assign(cap, this.options); } } } } async _getChromedriverPath() { try { return (await import('chromedriver')).path; } catch (e) { log.error('Can\'t load chromedriver, please define "chromedriverCustomPath" property or install dependency via "npm install chromedriver --save-dev"'); throw new SevereServiceError(e.message); } } } _ChromeDriverLauncher_pollTimeout = new WeakMap();