Skip to content

Commit

Permalink
Find an existing Safari WebDriver process or launch a new one
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
RLovelett committed Feb 15, 2018
1 parent 791507a commit ffcd936
Showing 1 changed file with 62 additions and 21 deletions.
83 changes: 62 additions & 21 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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 = {
Expand Down

0 comments on commit ffcd936

Please sign in to comment.