UNPKG

4.87 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7 * Code distributed by Google as part of the polymer project is also
8 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9 */
10var _ = require('lodash');
11var request = require('request');
12
13var browsers = require('./browsers');
14var sauce = require('./sauce');
15
16/** WCT plugin that enables support for remote browsers via Sauce Labs. */
17module.exports = function(wct, pluginOptions) {
18
19 // The capabilities objects for browsers to run. We don't know the tunnel id
20 // until `prepare`, so we've gotta hang onto them.
21 var eachCapabilities = [];
22
23 wct.hook('configure', function(done) {
24 if (!pluginOptions.browsers || pluginOptions.browsers.length === 0) return done();
25
26 expandOptions(pluginOptions);
27
28 browsers.expand(pluginOptions, function(error, expanded) {
29 if (error) return done(error);
30 wct.emit('log:debug', 'Using sauce browsers:', expanded);
31 // We are careful to append these to the configuration object, even though
32 // we don't know the tunnel id yet. This allows WCT to give a useful error
33 // if no browsers were configured.
34 var activeBrowsers = wct.options.activeBrowsers;
35 activeBrowsers.push.apply(activeBrowsers, expanded);
36 // But we still need to inject the sauce tunnel ID once we know it.
37 eachCapabilities = expanded;
38
39 done();
40 });
41 });
42
43 wct.hook('prepare', function(done) {
44 // Don't bother spinning up the tunnel if we don't have any browsers talking
45 // over it.
46 if (eachCapabilities.length === 0) return done();
47
48 // Is there already an active sauce tunnel?
49 if (pluginOptions.tunnelId) {
50 _injectTunnelId(eachCapabilities, pluginOptions.tunnelId);
51 return done();
52 }
53
54 // Let anyone know, and give them a chance to modify the options prior to
55 // booting up the Sauce Connect tunnel.
56 wct.emitHook('prepare:sauce-tunnel', function(error) {
57 if (error) return done(error);
58 sauce.startTunnel(pluginOptions, wct, function(error, tunnelId) {
59 if (error) return done(error);
60 _injectTunnelId(eachCapabilities, tunnelId);
61 done();
62 });
63 });
64 });
65
66 wct.on('browser-start', function(def, data, stats, browser) {
67 if (!browser) return;
68 // Bump the connection periodically to advance Sauce's remote timeout.
69 browser._keepalive = setInterval(function(){
70 browser.title(function() {});
71 }, (def.testTimeout / 2) || 45 * 1000);
72 // do not let the keepalive hang node
73 browser._keepalive.unref();
74 });
75
76 wct.on('browser-end', function(def, error, stats, sessionId, browser) {
77 if (eachCapabilities.length === 0 || !sessionId) return;
78
79 if (browser._keepalive) {
80 clearInterval(browser._keepalive);
81 }
82
83 var payload = {
84 passed: (stats.status === 'complete' && stats.failing === 0),
85 'public': pluginOptions.visibility,
86 build: parseInt(pluginOptions.buildNumber, 10),
87 name: pluginOptions.jobName
88 };
89 wct.emit('log:debug', 'Updating sauce job', sessionId, payload);
90
91 // Send the pass/fail info to sauce-labs if we are testing remotely.
92 var username = wct.options.plugins.sauce.username;
93 var accessKey = wct.options.plugins.sauce.accessKey;
94 request.put({
95 url: 'https://saucelabs.com/rest/v1/' + encodeURIComponent(username) + '/jobs/' + encodeURIComponent(sessionId),
96 auth: {user: username, pass: accessKey},
97 json: true,
98 body: payload,
99 });
100 });
101
102};
103
104function expandOptions(options) {
105 _.defaults(options, {
106 username: process.env.SAUCE_USERNAME,
107 accessKey: process.env.SAUCE_ACCESS_KEY,
108 tunnelId: process.env.SAUCE_TUNNEL_ID,
109 // export the travis build number (integer) and repo slug (user/repo) to
110 // sauce dashboard
111 buildNumber: process.env.TRAVIS_BUILD_NUMBER,
112 jobName: process.env.TRAVIS_REPO_SLUG,
113 visibility: 'public'
114 });
115 if (sauce.isTravisSauceConnectRunning()) {
116 _.defaults(options, {
117 // Under Travis CI, the tunnel id is $TRAVIS_JOB_NUMBER: https://docs.travis-ci.com/user/sauce-connect
118 tunnelId: process.env.TRAVIS_JOB_NUMBER
119 });
120 }
121}
122
123/**
124 * @param {!Array<!Object>} eachCapabilities
125 * @param {string} tunnelId
126 */
127function _injectTunnelId(eachCapabilities, tunnelId) {
128 eachCapabilities.forEach(function(browser) {
129 browser['tunnel-identifier'] = tunnelId;
130 });
131}
132
133// Hacks for the wct-st binary.
134module.exports.expandOptions = expandOptions;
135module.exports.startTunnel = sauce.startTunnel;