Skip to content

Commit 13447e3

Browse files
committed
build(browserstack): initial setup
Closes angular#4941
1 parent 84fe0c9 commit 13447e3

13 files changed

Lines changed: 164 additions & 22 deletions

.travis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ env:
1919
- LOGS_DIR=/tmp/angular-build/logs
2020
- SAUCE_USERNAME=angular-ci
2121
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
22+
- BROWSER_STACK_USERNAME=angularteam1
23+
- BROWSER_STACK_ACCESS_KEY=BWCd4SynLzdDcv8xtzsB
2224
- ARCH=linux-x64
2325
- DART_DEV_VERSION=latest
2426
- DART_STABLE_VERSION=latest
@@ -36,6 +38,7 @@ env:
3638
- MODE=dart DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
3739
- MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
3840
- MODE=saucelabs DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
41+
- MODE=browserstack DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
3942
- MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
4043
- MODE=js DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
4144
- MODE=router DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
@@ -45,6 +48,7 @@ env:
4548
matrix:
4649
allow_failures:
4750
- env: "MODE=saucelabs DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
51+
- env: "MODE=browserstack DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
4852
- env: "MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
4953

5054
addons:

sauce.conf.js renamed to browser-providers.conf.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,17 @@ var customLaunchers = {
124124
browserName: 'android',
125125
platform: 'Linux',
126126
version: '5.1'
127+
},
128+
129+
'BS_Chrome': {
130+
base: 'BrowserStack',
131+
browser: 'chrome',
132+
os: 'OS X',
133+
os_version: 'Yosemite'
127134
}
128135
};
129136

130-
var aliases = {
137+
var sauceAliases = {
131138
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}),
132139
'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9.0'],
133140
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5.1', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
@@ -142,11 +149,19 @@ var aliases = {
142149
'SL_CHROMEDEV', 'SL_FIREFOXBETA']
143150
};
144151

152+
var browserstackAliases = {
153+
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'BrowserStack';}),
154+
'DESKTOP': ['BS_Chrome'],
155+
'CI': ['BS_Chrome'],
156+
};
157+
145158
module.exports = {
146159
customLaunchers: customLaunchers,
147-
aliases: aliases
160+
sauceAliases: sauceAliases,
161+
browserstackAliases: browserstackAliases
148162
}
149163

150164
if (process.env.TRAVIS) {
151165
process.env.SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY.split('').reverse().join('');
166+
process.env.BROWSER_STACK_ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY.split('').reverse().join('');
152167
}

gulpfile.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ var buildRouter = require('./modules/angular1_router/build');
4343
var uglify = require('gulp-uglify');
4444
var shouldLog = require('./tools/build/logging');
4545
var dartSdk = require('./tools/build/dart');
46-
var sauceConf = require('./sauce.conf');
46+
var browserProvidersConf = require('./browser-providers.conf.js');
4747
var os = require('os');
4848

4949
require('./tools/check-environment')({
@@ -463,17 +463,17 @@ function getBrowsersFromCLI() {
463463
for (var i = 0; i < inputList.length; i++) {
464464
var input = inputList[i];
465465
var karmaChromeLauncher = require('karma-chrome-launcher');
466-
if (sauceConf.customLaunchers.hasOwnProperty(input) || karmaChromeLauncher.hasOwnProperty("launcher:" + input)) {
466+
if (browserProvidersConf.customLaunchers.hasOwnProperty(input) || karmaChromeLauncher.hasOwnProperty("launcher:" + input)) {
467467
// In case of non-sauce browsers, or browsers defined in karma-chrome-launcher (Chrome, ChromeCanary and Dartium):
468468
// overrides everything, ignoring other options
469469
outputList = [input];
470470
isSauce = false;
471471
break;
472-
} else if (sauceConf.customLaunchers.hasOwnProperty("SL_" + input.toUpperCase())) {
472+
} else if (browserProvidersConf.customLaunchers.hasOwnProperty("SL_" + input.toUpperCase())) {
473473
isSauce = true;
474474
outputList.push("SL_" + input.toUpperCase());
475-
} else if (sauceConf.aliases.hasOwnProperty(input.toUpperCase())) {
476-
outputList = outputList.concat(sauceConf.aliases[input]);
475+
} else if (browserProvidersConf.sauceAliases.hasOwnProperty(input.toUpperCase())) {
476+
outputList = outputList.concat(browserProvidersConf.sauceAliases[input]);
477477
isSauce = true;
478478
} else {
479479
throw new Error('ERROR: unknown browser found in getBrowsersFromCLI()');
@@ -661,12 +661,25 @@ gulp.task('test.unit.js.sauce/ci', function (done) {
661661
browserNoActivityTimeout: 240000,
662662
captureTimeout: 120000,
663663
reporters: ['dots', 'saucelabs'],
664-
browsers: sauceConf.aliases.CI
664+
browsers: browserProvidersConf.sauceAliases.CI
665665
},
666666
function(err) {done(); process.exit(err ? 1 : 0);}
667667
).start();
668668
});
669669

670+
gulp.task('test.unit.js.browserstack/ci', function (done) {
671+
new karma.Server({
672+
configFile: __dirname + '/karma-js.conf.js',
673+
singleRun: true,
674+
browserNoActivityTimeout: 240000,
675+
captureTimeout: 120000,
676+
reporters: ['dots'],
677+
browsers: browserProvidersConf.browserstackAliases.CI
678+
},
679+
function(err) {done(); process.exit(err ? 1 : 0);}
680+
).start();
681+
});
682+
670683
gulp.task('test.unit.dart/ci', function (done) {
671684
var browserConf = getBrowsersFromCLI();
672685
new karma.Server({

karma-dart.conf.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
var sauceConf = require('./sauce.conf');
1+
var browserProvidersConf = require('./browser-providers.conf.js');
22

33
var packageSources = {
44
// Dependencies installed with `pub install`.
@@ -67,7 +67,7 @@ module.exports = function(config) {
6767
// Map packages to the correct urls where Karma serves them.
6868
proxies: proxyPaths,
6969

70-
customLaunchers: sauceConf.customLaunchers,
70+
customLaunchers: browserProvidersConf.customLaunchers,
7171
browsers: ['DartiumWithWebPlatform'],
7272

7373
port: 9877,

karma-js.conf.js

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
var sauceConf = require('./sauce.conf');
1+
var browserProvidersConf = require('./browser-providers.conf.js');
22

33
// Karma configuration
44
// Generated on Thu Sep 25 2014 11:52:02 GMT-0700 (PDT)
@@ -33,7 +33,7 @@ module.exports = function(config) {
3333

3434
exclude: ['dist/js/dev/es5/**/e2e_test/**', 'dist/js/dev/es5/angular2/examples/**', 'dist/angular1_router.js'],
3535

36-
customLaunchers: sauceConf.customLaunchers,
36+
customLaunchers: browserProvidersConf.customLaunchers,
3737

3838
sauceLabs: {
3939
testName: 'Angular2',
@@ -48,18 +48,33 @@ module.exports = function(config) {
4848
}
4949
},
5050

51+
browserStack: {
52+
project: 'Angular2',
53+
startTunnel: false,
54+
retryLimit: 1,
55+
timeout: 600
56+
},
57+
5158
browsers: ['Chrome'],
5259

5360
port: 9876
5461
});
5562

56-
if (process.env.TRAVIS && process.env.MODE === 'saucelabs') {
57-
config.sauceLabs.build = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
58-
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
63+
if (process.env.TRAVIS) {
64+
var buildId = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
65+
if (process.env.MODE === 'saucelabs') {
66+
config.sauceLabs.build = buildId;
67+
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
68+
69+
// TODO(mlaval): remove once SauceLabs supports websockets.
70+
// This speeds up the capturing a bit, as browsers don't even try to use websocket.
71+
console.log('>>>> setting socket.io transport to polling <<<<');
72+
config.transports = ['polling'];
73+
}
5974

60-
// TODO(mlaval): remove once SauceLabs supports websockets.
61-
// This speeds up the capturing a bit, as browsers don't even try to use websocket.
62-
console.log('>>>> setting socket.io transport to polling <<<<');
63-
config.transports = ['polling'];
75+
if (process.env.MODE === 'browserstack') {
76+
config.browserStack.build = buildId;
77+
config.browserStack.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
78+
}
6479
}
6580
};

modules/angular1_router/karma-router.conf.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
var sauceConf = require('../../sauce.conf');
3+
var browserProvidersConf = require('../../browser-providers.conf.js');
44

55
// This runs the tests for the router in Angular 1.x
66

@@ -20,7 +20,7 @@ module.exports = function (config) {
2020
'test/**/*_spec.js'
2121
],
2222

23-
customLaunchers: sauceConf.customLaunchers,
23+
customLaunchers: browserProvidersConf.customLaunchers,
2424

2525
browsers: ['ChromeCanary']
2626
};
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
'use strict';
2+
3+
var fs = require('fs');
4+
var http = require('http');
5+
var BrowserStackTunnel = require('browserstacktunnel-wrapper');
6+
7+
var HOSTNAME = 'localhost';
8+
var PORTS = [9876, 9877];
9+
var ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY;
10+
var READY_FILE = process.env.BROWSER_PROVIDER_READY_FILE;
11+
var TUNNEL_IDENTIFIER = process.env.TRAVIS_JOB_NUMBER;
12+
13+
// We need to start fake servers, otherwise the tunnel does not start.
14+
var fakeServers = [];
15+
var hosts = [];
16+
17+
PORTS.forEach(function(port) {
18+
fakeServers.push(http.createServer(function() {}).listen(port));
19+
hosts.push({
20+
name: HOSTNAME,
21+
port: port,
22+
sslFlag: 0
23+
});
24+
});
25+
26+
var tunnel = new BrowserStackTunnel({
27+
key: ACCESS_KEY,
28+
localIdentifier: TUNNEL_IDENTIFIER,
29+
hosts: hosts
30+
});
31+
32+
console.log('Starting tunnel on ports', PORTS.join(', '));
33+
tunnel.start(function(error) {
34+
if (error) {
35+
console.error('Can not establish the tunnel', error);
36+
} else {
37+
console.log('Tunnel established.');
38+
fakeServers.forEach(function(server) {
39+
server.close();
40+
});
41+
42+
if (READY_FILE) {
43+
fs.writeFile(READY_FILE, '');
44+
}
45+
}
46+
});
47+
48+
tunnel.on('error', function(error) {
49+
console.error(error);
50+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export BROWSER_STACK_ACCESS_KEY=`echo $BROWSER_STACK_ACCESS_KEY | rev`
2+
3+
node ./scripts/browserstack/start_tunnel.js &
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/bash
2+
3+
set -e -o pipefail
4+
5+
6+
echo "Shutting down Browserstack tunnel"
7+
echo "TODO: implement me"
8+
exit 1
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/bash
2+
3+
4+
# Wait for Connect to be ready before exiting
5+
# Time out if we wait for more than 2 minutes, so that we can print logs.
6+
let "counter=0"
7+
8+
while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do
9+
let "counter++"
10+
if [ $counter -gt 240 ]; then
11+
echo "Timed out after 2 minutes waiting for browser provider ready file"
12+
# We must manually print logs here because travis will not run
13+
# after_script commands if the failure occurs before the script
14+
# phase.
15+
./scripts/ci/print-logs.sh
16+
exit 5
17+
fi
18+
sleep .5
19+
done

0 commit comments

Comments
 (0)