From ffcd93624599dd988ddb0173e24b6fbafaf21041 Mon Sep 17 00:00:00 2001 From: Ryan Lovelett Date: Thu, 15 Feb 2018 10:47:45 -0500 Subject: [PATCH] Find an existing Safari WebDriver process or launch a new one The old code only ever launched a new WebDriver process. The new code has been refactored to launch a new instance of the web driver if an existing process cannot be used. It's also using `async`/`await` and `const` so it will require a fairly new version of Node now. --- index.js | 83 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 21 deletions(-) diff --git a/index.js b/index.js index 0edf3c0..f386147 100644 --- a/index.js +++ b/index.js @@ -3,22 +3,14 @@ var http = require('http'); var url = require('url'); /** - * The `safaridriver` does not always start accepting incoming connections immediately. As a result we have to "ping" - * the driver to figure out when it is safe to start sending commands. This method pings the server, in a callback loop, - * to determine when the server starts accepting incoming connections. + * Use `async`/`await` to provide a `sleep` capability. * - * @param {*} options The options to send to `http.get`. - * @param {number} limit The maximum number of attempts to make before quitting. - * @param {Function} done The callback performed when the Safari WebDriver is accepting connections. + * @see https://stackoverflow.com/a/39914235/247730 + * @param {number} ms The time, in milliseconds, to block the event queue. + * @returns {Promise} A promise to be resolved when the timeout finishes. */ -function ping(options, limit, done) { - var attempts = 0; - function error(e) { - if (attempts <= limit) { - http.get(options, done).on('error', error); - } - } - http.get(options, done).on('error', error); +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); } var SafariBrowser = function(baseBrowserDecorator, args, logger) { @@ -35,24 +27,73 @@ var SafariBrowser = function(baseBrowserDecorator, args, logger) { this.name = 'Safari via WebDriver at ' + webDriver; var log = logger.create(this.name); + this.driver = wd.promiseChainRemote(config); + + this.driver.on('status', (info) => { + log.debug(info); + }); + + this.driver.on('command', (eventType, command, response) => { + log.debug(`${eventType} ${command} ${response || ''}`); + }); + + this.driver.on('http', (meth, path, data) => { + log.debug(`${meth} ${path} ${data || ''}`); + }); + this._getOptions = function() { return [ "-p", config.port.toString() ]; } + /** + * This launcher works by checking to see if there is a `/usr/bin/safaridriver` instance running. + * It is determined to be running if the web driver API can be reached on the configured host and port. + * If it is then it it launches the Karma test runner in a new session. If it is not, it then attempts + * to start its own new instance of `/usr/bin/safaridriver` and then connect the Karma test runner in + * a new session. + * + * @param {string} url The URL that the Karma server is listening on. + */ this._start = function(url) { var self = this; - log.debug(url); - // self._execCommand(self._getCommand(), self._getOptions(url)); - ping(config, 100, function() { - self.driver = wd.remote(config, 'promiseChain'); - self.browser = self.driver.init({}); + var attempts = 0; + // TODO: It would be nice if this was configurable + const MAX_ATTEMPTS = 3; + async function attachKarma(error) { + attempts += 1; + if (error && attempts === 1) { + log.debug(`attachKarma ${attempts} of ${MAX_ATTEMPTS}`); + log.debug(`${self._getCommand()} is not running.`); + log.debug(`Attempting to start ${self._getCommand()} ${self._getOptions(url).join(' ')}`); + self._execCommand(self._getCommand(), self._getOptions(url)); + self.browser = self.driver.init({}, attachKarma); + } else if (error && attempts <= MAX_ATTEMPTS) { + log.debug(`attachKarma ${attempts} of ${MAX_ATTEMPTS}`); + // TODO: It would be nice if this was configurable + const sleepDuration = 4000; + log.debug(`Going to give the driver time to start-up. Sleeping for ${sleepDuration}ms.`); + await sleep(sleepDuration); + self.browser = self.driver.init({}, attachKarma); + } else if (error) { + log.error('Could not connect to Safari.'); + } else { + log.debug('Connected to Safari WebDriver'); + log.debug(`Connecting to ${url}`); + self.browser.get(url).done(); + } + } - self.browser.get(url).done(); - }); + self.browser = self.driver.init({}, attachKarma); }; + + this.on('kill', (done) => { + if (this.browser) { + this.browser.quit(() => done()); + } + }); }; SafariBrowser.prototype = {