wct-sauce
Version:
WCT plugin that enables support for sauce browsers via Sauce Labs
145 lines (127 loc) • 4.96 kB
JavaScript
/**
* @license
* Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at
* http://polymer.github.io/LICENSE.txt The complete set of authors may be found
* at http://polymer.github.io/AUTHORS.txt The complete set of contributors may
* be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by
* Google as part of the polymer project is also subject to an additional IP
* rights grant found at http://polymer.github.io/PATENTS.txt
*/
var _ = require('lodash');
var request = require('request');
var browsers = require('./browsers');
var sauce = require('./sauce');
var travis = require('./travis');
/** WCT plugin that enables support for remote browsers via Sauce Labs. */
module.exports = function(wct, pluginOptions) {
// The capabilities objects for browsers to run. We don't know the tunnel id
// until `prepare`, so we've gotta hang onto them.
var eachCapabilities = [];
wct.hook('configure', function(done) {
if (!pluginOptions.browsers || pluginOptions.browsers.length === 0)
return done();
expandOptions(pluginOptions);
browsers.expand(pluginOptions, function(error, expanded) {
if (error)
return done(error);
wct.emit('log:debug', 'Using sauce browsers:', expanded);
// We are careful to append these to the configuration object, even though
// we don't know the tunnel id yet. This allows WCT to give a useful error
// if no browsers were configured.
var activeBrowsers = wct.options.activeBrowsers;
activeBrowsers.push.apply(activeBrowsers, expanded);
// But we still need to inject the sauce tunnel ID once we know it.
eachCapabilities = expanded;
done();
});
});
wct.hook('prepare', function(done) {
// Don't bother spinning up the tunnel if we don't have any browsers talking
// over it.
if (eachCapabilities.length === 0)
return done();
// Is there already an active sauce tunnel?
if (pluginOptions.tunnelId) {
_injectTunnelId(eachCapabilities, pluginOptions.tunnelId);
return done();
}
// Let anyone know, and give them a chance to modify the options prior to
// booting up the Sauce Connect tunnel.
wct.emitHook('prepare:sauce-tunnel', function(error) {
if (error)
return done(error);
sauce.startTunnel(pluginOptions, wct, function(error, tunnelId) {
if (error)
return done(error);
_injectTunnelId(eachCapabilities, tunnelId);
done();
});
});
});
wct.on('browser-start', function(def, data, stats, browser) {
if (!browser)
return;
// Bump the connection periodically to advance Sauce's remote timeout.
browser._keepalive = setInterval(function() {
browser.title(function() {});
}, (def.testTimeout / 2) || 45 * 1000);
// do not let the keepalive hang node
browser._keepalive.unref();
});
wct.on('browser-end', function(def, error, stats, sessionId, browser) {
if (eachCapabilities.length === 0 || !sessionId)
return;
if (browser._keepalive) {
clearInterval(browser._keepalive);
}
var payload = {
passed: (stats.status === 'complete' && stats.failing === 0),
'public': pluginOptions.visibility,
build: parseInt(pluginOptions.buildNumber, 10),
name: pluginOptions.jobName
};
wct.emit('log:debug', 'Updating sauce job', sessionId, payload);
// Send the pass/fail info to sauce-labs if we are testing remotely.
var username = wct.options.plugins.sauce.username;
var accessKey = wct.options.plugins.sauce.accessKey;
request.put({
url: 'https://saucelabs.com/rest/v1/' + encodeURIComponent(username) +
'/jobs/' + encodeURIComponent(sessionId),
auth: {user: username, pass: accessKey},
json: true,
body: payload,
});
});
};
function expandOptions(options) {
_.defaults(options, {
username: process.env.SAUCE_USERNAME,
accessKey: process.env.SAUCE_ACCESS_KEY,
tunnelId: process.env.SAUCE_TUNNEL_ID,
// export the travis build number (integer) and repo slug (user/repo) to
// sauce dashboard
buildNumber: process.env.TRAVIS_BUILD_NUMBER,
jobName: process.env.TRAVIS_REPO_SLUG,
visibility: 'public'
});
if (travis.isTravisSauceConnectRunning()) {
_.defaults(options, {
// Under Travis CI, the tunnel id is $TRAVIS_JOB_NUMBER:
// https://docs.travis-ci.com/user/sauce-connect
tunnelId: process.env.TRAVIS_JOB_NUMBER
});
}
}
/**
* @param {!Array<!Object>} eachCapabilities
* @param {string} tunnelId
*/
function _injectTunnelId(eachCapabilities, tunnelId) {
eachCapabilities.forEach(function(browser) {
browser['tunnel-identifier'] = tunnelId;
});
}
// Hacks for the wct-st binary.
module.exports.expandOptions = expandOptions;
module.exports.startTunnel = sauce.startTunnel;