mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-10 02:47:50 +00:00
Attempt to make sauce tests public with names, tags, and customized options.
This commit is contained in:
20
.travis.yml
20
.travis.yml
@@ -6,8 +6,8 @@ node_js:
|
|||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- BIN="node" BUILD=false COMPAT=false MAKE=false OPTION="" SAUCE_LABS=false
|
- BIN="node" BUILD=false COMPAT=false MAKE=false OPTION="" SAUCE_LABS=false
|
||||||
- SAUCE_USERNAME="jdalton"
|
- SAUCE_USERNAME="lodash"
|
||||||
- secure: "woILQltl1pI3DgadZ5NrcqntdPvnRmQBwIVNZL91Ht5d9snIhgyAixI6xNAS8F8BzD9RzqzVPHay5sHfn+GhNaojcaiHs1nXAbdyclevMyfP+3MQ1HGfMSU0bv1GdT35LJ+C0u4Y3SuuZSbBlNEeLXRPMngPZahf4xL8RsZz/is="
|
- secure: "LGVeh7z/x6hxGCtr1BfgCSRva691ChX+1bs4ecJE71QwsDNJwknqmblZm7hFSTkq7msSapSDV5P9sgr6fsmmHuY3311Vl04sneRpz8ge1ZUIbmMODI+tZAasxyvyjZJdOrTFZr89BWN6e/SddDxDKNF4n0O1DgUF4irrT+aUxUE="
|
||||||
matrix:
|
matrix:
|
||||||
- BUILD="compat"
|
- BUILD="compat"
|
||||||
- BUILD="modern"
|
- BUILD="modern"
|
||||||
@@ -70,11 +70,11 @@ script:
|
|||||||
- "([ $SAUCE_LABS != false ] || [ $BUILD == false ]) && true || cd ./test"
|
- "([ $SAUCE_LABS != false ] || [ $BUILD == false ]) && true || cd ./test"
|
||||||
- "([ $SAUCE_LABS != false ] || [ $BUILD == false ]) && true || $BIN $OPTION ./test.js ../dist/lodash.$BUILD.js"
|
- "([ $SAUCE_LABS != false ] || [ $BUILD == false ]) && true || $BIN $OPTION ./test.js ../dist/lodash.$BUILD.js"
|
||||||
- "([ $SAUCE_LABS != false ] || [ $BUILD == false ]) && true || $BIN $OPTION ./test.js ../dist/lodash.$BUILD.min.js"
|
- "([ $SAUCE_LABS != false ] || [ $BUILD == false ]) && true || $BIN $OPTION ./test.js ../dist/lodash.$BUILD.min.js"
|
||||||
- "([ $SAUCE_LABS == false ] || [ $BUILD == 'underscore' ]) && true || node ./test/saucelabs.js \"test/index.html?build=lodash-$BUILD\""
|
- "([ $SAUCE_LABS == false ] || [ $BUILD == 'underscore' ]) && true || node ./test/saucelabs.js runner=\"test/index.html?build=lodash-$BUILD\" tags=\"$BUILD,production\""
|
||||||
- "([ $SAUCE_LABS == false ] || [ $BUILD == 'underscore' ]) && true || node ./test/saucelabs.js \"test/index.html?build=../dist/lodash.$BUILD.js\""
|
- "([ $SAUCE_LABS == false ] || [ $BUILD == 'underscore' ]) && true || node ./test/saucelabs.js runner=\"test/index.html?build=../dist/lodash.$BUILD.js\" tags=\"$BUILD,development\""
|
||||||
- "[ $SAUCE_LABS == false ] && true || node ./test/saucelabs.js \"test/backbone.html?build=lodash-$BUILD\""
|
- "[ $SAUCE_LABS == false ] && true || node ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=lodash-$BUILD\" tags=\"$BUILD,production,backbone\""
|
||||||
- "[ $SAUCE_LABS == false ] && true || node ./test/saucelabs.js \"test/backbone.html?build=../dist/lodash.$BUILD.js\""
|
- "[ $SAUCE_LABS == false ] && true || node ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../dist/lodash.$BUILD.js\" tags=\"$BUILD,development,backbone\""
|
||||||
- "[ $SAUCE_LABS == false ] && true || node ./test/saucelabs.js \"test/underscore.html?build=lodash-$BUILD\""
|
- "[ $SAUCE_LABS == false ] && true || node ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=lodash-$BUILD\" tags=\"$BUILD,production,underscore\""
|
||||||
- "[ $SAUCE_LABS == false ] && true || node ./test/saucelabs.js \"test/underscore.html?build=../dist/lodash.$BUILD.js\""
|
- "[ $SAUCE_LABS == false ] && true || node ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../dist/lodash.$BUILD.js\" tags=\"$BUILD,development,underscore\""
|
||||||
- "([ $SAUCE_LABS == false ] || [ $COMPAT == false ]) && true || node ./test/saucelabs.js \"test/index.html?build=lodash-$BUILD&compat=7\""
|
- "([ $SAUCE_LABS == false ] || [ $COMPAT == false ]) && true || node ./test/saucelabs.js runner=\"test/index.html?build=lodash-$BUILD&compat=7\" tags=\"$BUILD,production,ie-compat-mode\""
|
||||||
- "([ $SAUCE_LABS == false ] || [ $COMPAT == false ]) && true || node ./test/saucelabs.js \"test/index.html?build=../dist/lodash.$BUILD.js&compat=7\""
|
- "([ $SAUCE_LABS == false ] || [ $COMPAT == false ]) && true || node ./test/saucelabs.js runner=\"test/index.html?build=../dist/lodash.$BUILD.js&compat=7\" tags=\"$BUILD,development,ie-compat-mode\""
|
||||||
|
|||||||
@@ -1,38 +1,45 @@
|
|||||||
;(function() {
|
;(function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var ecstatic = require('ecstatic'),
|
|
||||||
http = require('http'),
|
|
||||||
path = require('path'),
|
|
||||||
request = require('request'),
|
|
||||||
SauceTunnel = require('sauce-tunnel'),
|
|
||||||
url = require('url');
|
|
||||||
|
|
||||||
var attempts = -1,
|
|
||||||
prevLine = '';
|
|
||||||
|
|
||||||
var port = 8081,
|
|
||||||
username = process.env.SAUCE_USERNAME,
|
|
||||||
accessKey = process.env.SAUCE_ACCESS_KEY,
|
|
||||||
tunnelId = 'lodash_' + process.env.TRAVIS_JOB_NUMBER;
|
|
||||||
|
|
||||||
if (isFinite(process.env.TRAVIS_PULL_REQUEST)) {
|
if (isFinite(process.env.TRAVIS_PULL_REQUEST)) {
|
||||||
console.error('Testing skipped for pull requests');
|
console.error('Testing skipped for pull requests');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
var runnerPathname = (function() {
|
/** Load Node.js modules */
|
||||||
var args = process.argv;
|
var http = require('http'),
|
||||||
return args.length > 2
|
path = require('path'),
|
||||||
? '/' + args[args.length - 1].replace(/^\W+/, '')
|
url = require('url');
|
||||||
: '/test/index.html';
|
|
||||||
}());
|
|
||||||
|
|
||||||
var runnerQuery = url.parse(runnerPathname, true).query,
|
/** Load other modules */
|
||||||
isBackbone = /\bbackbone\b/i.test(runnerPathname),
|
var _ = require('../lodash'),
|
||||||
isMobile = /\bmobile\b/i.test(runnerQuery.build),
|
ecstatic = require('ecstatic'),
|
||||||
isModern = /\bmodern\b/i.test(runnerQuery.build);
|
request = require('request'),
|
||||||
|
SauceTunnel = require('sauce-tunnel');
|
||||||
|
|
||||||
|
/** Used by `logInline` */
|
||||||
|
var attempts = -1,
|
||||||
|
prevLine = '';
|
||||||
|
|
||||||
|
/** Used as request `auth` and `options` values */
|
||||||
|
var port = 8081,
|
||||||
|
username = process.env.SAUCE_USERNAME,
|
||||||
|
accessKey = process.env.SAUCE_ACCESS_KEY,
|
||||||
|
tunnelId = 'lodash_' + process.env.TRAVIS_JOB_NUMBER;
|
||||||
|
|
||||||
|
var runner = process.argv.reduce(function(result, value) {
|
||||||
|
return optionToValue('runner', value) || result;
|
||||||
|
}, '/test/index.html');
|
||||||
|
|
||||||
|
var sessionName = process.argv.reduce(function(result, value) {
|
||||||
|
return optionToValue('name', value) || result;
|
||||||
|
}, 'lodash tests');
|
||||||
|
|
||||||
|
var tags = process.argv.reduce(function(result, value) {
|
||||||
|
return optionToArray('tags', value) || result;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
/** List of platforms to load the runner on */
|
||||||
var platforms = [
|
var platforms = [
|
||||||
['Windows 7', 'chrome', ''],
|
['Windows 7', 'chrome', ''],
|
||||||
['Windows 7', 'firefox', '25'],
|
['Windows 7', 'firefox', '25'],
|
||||||
@@ -53,6 +60,12 @@
|
|||||||
['Windows 7', 'safari', '5']
|
['Windows 7', 'safari', '5']
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** Used to tailor the `platforms` array */
|
||||||
|
var runnerQuery = url.parse(runner, true).query,
|
||||||
|
isBackbone = /\bbackbone\b/i.test(runner),
|
||||||
|
isMobile = /\bmobile\b/i.test(runnerQuery.build),
|
||||||
|
isModern = /\bmodern\b/i.test(runnerQuery.build);
|
||||||
|
|
||||||
// platforms to test IE compat mode
|
// platforms to test IE compat mode
|
||||||
if (runnerQuery.compat) {
|
if (runnerQuery.compat) {
|
||||||
platforms = [
|
platforms = [
|
||||||
@@ -91,39 +104,14 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a web server for the local dir
|
|
||||||
var mount = ecstatic({
|
|
||||||
'root': process.cwd(),
|
|
||||||
'cache': false
|
|
||||||
});
|
|
||||||
|
|
||||||
http.createServer(function(req, res) {
|
|
||||||
var compat = url.parse(req.url, true).query.compat;
|
|
||||||
if (compat) {
|
|
||||||
// see http://msdn.microsoft.com/en-us/library/ff955275(v=vs.85).aspx
|
|
||||||
res.setHeader('X-UA-Compatible', 'IE=' + compat);
|
|
||||||
}
|
|
||||||
mount(req, res);
|
|
||||||
}).listen(port);
|
|
||||||
|
|
||||||
// set up Sauce Connect so we can use this server from Sauce Labs
|
|
||||||
var tunnelTimeout = 10000,
|
|
||||||
tunnel = new SauceTunnel(username, accessKey, tunnelId, true, tunnelTimeout);
|
|
||||||
|
|
||||||
console.log('Opening Sauce Connect tunnel...');
|
|
||||||
|
|
||||||
tunnel.start(function(success) {
|
|
||||||
if (success) {
|
|
||||||
console.log('Sauce Connect tunnel opened');
|
|
||||||
runTests();
|
|
||||||
} else {
|
|
||||||
console.error('Failed to open Sauce Connect tunnel');
|
|
||||||
process.exit(2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs an inline message to standard output.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} text The text to log.
|
||||||
|
*/
|
||||||
function logInline(text) {
|
function logInline(text) {
|
||||||
var blankLine = repeat(' ', prevLine.length);
|
var blankLine = repeat(' ', prevLine.length);
|
||||||
if (text.length > 40) {
|
if (text.length > 40) {
|
||||||
@@ -133,67 +121,54 @@
|
|||||||
process.stdout.write(text + blankLine.slice(text.length) + '\r');
|
process.stdout.write(text + blankLine.slice(text.length) + '\r');
|
||||||
}
|
}
|
||||||
|
|
||||||
function repeat(text, times) {
|
/**
|
||||||
return Array(times + 1).join(text);
|
* Converts a comma separated option value into an array.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} name The name of the option to inspect.
|
||||||
|
* @param {string} string The options string.
|
||||||
|
* @returns {Array} Returns the new converted array.
|
||||||
|
*/
|
||||||
|
function optionToArray(name, string) {
|
||||||
|
return _.compact(_.isArray(string)
|
||||||
|
? string
|
||||||
|
: _.invoke((optionToValue(name, string) || '').split(/, */), 'trim')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the option value from an option string.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} name The name of the option to inspect.
|
||||||
|
* @param {string} string The options string.
|
||||||
|
* @returns {string|undefined} Returns the option value, else `undefined`.
|
||||||
|
*/
|
||||||
|
function optionToValue(name, string) {
|
||||||
|
var result = (result = string.match(RegExp('^' + name + '=([\\s\\S]+)$'))) && result[1].trim();
|
||||||
|
return result || undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a string with `text` repeated `n` number of times.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} text The text to repeat.
|
||||||
|
* @param {number} n The number of times to repeat `text`.
|
||||||
|
* @returns {string} The created string.
|
||||||
|
*/
|
||||||
|
function repeat(text, n) {
|
||||||
|
return Array(n + 1).join(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
function runTests() {
|
/**
|
||||||
var testDefinition = {
|
* Processes the result object of the test session.
|
||||||
'framework': 'qunit',
|
*
|
||||||
'platforms': platforms,
|
* @private
|
||||||
'tunnel': 'tunnel-identifier:' + tunnelId,
|
* @param {Object} results The result object to process.
|
||||||
'url': 'http://localhost:' + port + runnerPathname
|
*/
|
||||||
};
|
|
||||||
|
|
||||||
console.log('Starting saucelabs tests: ' + JSON.stringify(testDefinition));
|
|
||||||
|
|
||||||
request.post('https://saucelabs.com/rest/v1/' + username + '/js-tests', {
|
|
||||||
'auth': { 'user': username, 'pass': accessKey },
|
|
||||||
'json': testDefinition
|
|
||||||
}, function(error, response, body) {
|
|
||||||
var statusCode = response && response.statusCode;
|
|
||||||
if (statusCode == 200) {
|
|
||||||
waitForTestCompletion(body);
|
|
||||||
} else {
|
|
||||||
console.error('Failed to submit test to Sauce Labs; status: ' + statusCode + ', body:\n' + JSON.stringify(body));
|
|
||||||
if (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
process.exit(3);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function waitForTestCompletion(testIdentifier) {
|
|
||||||
request.post('https://saucelabs.com/rest/v1/' + username + '/js-tests/status', {
|
|
||||||
'auth': { 'user': username, 'pass': accessKey },
|
|
||||||
'json': testIdentifier
|
|
||||||
}, function(error, response, body) {
|
|
||||||
var statusCode = response && response.statusCode;
|
|
||||||
if (statusCode == 200) {
|
|
||||||
if (body.completed) {
|
|
||||||
logInline('');
|
|
||||||
handleTestResults(body['js tests']);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
logInline('Please wait' + repeat('.', (++attempts % 3) + 1));
|
|
||||||
setTimeout(function() {
|
|
||||||
waitForTestCompletion(testIdentifier);
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logInline('');
|
|
||||||
console.error('Failed to check test status on Sauce Labs; status: ' + statusCode + ', body:\n' + JSON.stringify(body));
|
|
||||||
if (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
process.exit(4);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleTestResults(results) {
|
function handleTestResults(results) {
|
||||||
var failingTests = results.filter(function(test) {
|
var failingTests = results.filter(function(test) {
|
||||||
var result = test.result;
|
var result = test.result;
|
||||||
@@ -229,4 +204,110 @@
|
|||||||
process.exit(failingTests.length ? 1 : 0);
|
process.exit(failingTests.length ? 1 : 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a request for Sauce Labs to start the test session.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function runTests() {
|
||||||
|
var options = {
|
||||||
|
'framework': 'qunit',
|
||||||
|
'name': sessionName,
|
||||||
|
'public': 'public',
|
||||||
|
'platforms': platforms,
|
||||||
|
'record-screenshots': false,
|
||||||
|
'tags': tags,
|
||||||
|
'tunnel': 'tunnel-identifier:' + tunnelId,
|
||||||
|
'url': 'http://localhost:' + port + runner,
|
||||||
|
'video-upload-on-pass': false
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('Starting saucelabs tests: ' + JSON.stringify(options));
|
||||||
|
|
||||||
|
request.post('https://saucelabs.com/rest/v1/' + username + '/js-tests', {
|
||||||
|
'auth': { 'user': username, 'pass': accessKey },
|
||||||
|
'json': options
|
||||||
|
}, function(error, response, body) {
|
||||||
|
var statusCode = response && response.statusCode;
|
||||||
|
if (statusCode == 200) {
|
||||||
|
waitForTestCompletion(body);
|
||||||
|
} else {
|
||||||
|
console.error('Failed to submit test to Sauce Labs; status: ' + statusCode + ', body:\n' + JSON.stringify(body));
|
||||||
|
if (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
process.exit(3);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the status of the test session. If the session has completed it
|
||||||
|
* passes the result object to `handleTestResults`, else it checks the status
|
||||||
|
* again in five seconds.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} testIdentifier The object used to identify the session.
|
||||||
|
*/
|
||||||
|
function waitForTestCompletion(testIdentifier) {
|
||||||
|
request.post('https://saucelabs.com/rest/v1/' + username + '/js-tests/status', {
|
||||||
|
'auth': { 'user': username, 'pass': accessKey },
|
||||||
|
'json': testIdentifier
|
||||||
|
}, function(error, response, body) {
|
||||||
|
var statusCode = response && response.statusCode;
|
||||||
|
if (statusCode == 200) {
|
||||||
|
if (body.completed) {
|
||||||
|
logInline('');
|
||||||
|
handleTestResults(body['js tests']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logInline('Please wait' + repeat('.', (++attempts % 3) + 1));
|
||||||
|
setTimeout(function() {
|
||||||
|
waitForTestCompletion(testIdentifier);
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logInline('');
|
||||||
|
console.error('Failed to check test status on Sauce Labs; status: ' + statusCode + ', body:\n' + JSON.stringify(body));
|
||||||
|
if (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
process.exit(4);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// create a web server for the local dir
|
||||||
|
var mount = ecstatic({
|
||||||
|
'root': process.cwd(),
|
||||||
|
'cache': false
|
||||||
|
});
|
||||||
|
|
||||||
|
http.createServer(function(req, res) {
|
||||||
|
var compat = url.parse(req.url, true).query.compat;
|
||||||
|
if (compat) {
|
||||||
|
// see http://msdn.microsoft.com/en-us/library/ff955275(v=vs.85).aspx
|
||||||
|
res.setHeader('X-UA-Compatible', 'IE=' + compat);
|
||||||
|
}
|
||||||
|
mount(req, res);
|
||||||
|
}).listen(port);
|
||||||
|
|
||||||
|
// set up Sauce Connect so we can use this server from Sauce Labs
|
||||||
|
var tunnelTimeout = 10000,
|
||||||
|
tunnel = new SauceTunnel(username, accessKey, tunnelId, true, tunnelTimeout);
|
||||||
|
|
||||||
|
console.log('Opening Sauce Connect tunnel...');
|
||||||
|
|
||||||
|
tunnel.start(function(success) {
|
||||||
|
if (success) {
|
||||||
|
console.log('Sauce Connect tunnel opened');
|
||||||
|
runTests();
|
||||||
|
} else {
|
||||||
|
console.error('Failed to open Sauce Connect tunnel');
|
||||||
|
process.exit(2);
|
||||||
|
}
|
||||||
|
});
|
||||||
}());
|
}());
|
||||||
|
|||||||
Reference in New Issue
Block a user