Modularize master branch.

This commit is contained in:
John-David Dalton
2016-12-30 22:26:46 -06:00
parent 912d6b04a1
commit 2900cfd288
745 changed files with 19699 additions and 140151 deletions

View File

@@ -1,155 +0,0 @@
;(function(window) {
'use strict';
/** The base path of the lodash builds. */
var basePath = '../';
/** The lodash build to load. */
var build = (build = /build=([^&]+)/.exec(location.search)) && decodeURIComponent(build[1]);
/** The module loader to use. */
var loader = (loader = /loader=([^&]+)/.exec(location.search)) && decodeURIComponent(loader[1]);
/** The `ui` object. */
var ui = {};
/*--------------------------------------------------------------------------*/
// Initialize controls.
addEventListener('load', function() {
function eventHandler(event) {
var buildIndex = buildList.selectedIndex,
loaderIndex = loaderList.selectedIndex,
search = location.search.replace(/^\?|&?(?:build|loader)=[^&]*&?/g, '');
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
location.href =
location.href.split('?')[0] + '?' +
(search ? search + '&' : '') +
'build=' + (buildIndex < 0 ? build : buildList[buildIndex].value) + '&' +
'loader=' + (loaderIndex < 0 ? loader : loaderList[loaderIndex].value);
}
function init() {
var toolbar = document.getElementById('qunit-testrunner-toolbar');
if (!toolbar) {
setTimeout(init, 15);
return;
}
toolbar.insertBefore(span2, toolbar.lastChild);
toolbar.insertBefore(span1, span2);
buildList.selectedIndex = (function() {
switch (build) {
case 'lodash': return 1;
case 'lodash-core-dev': return 2;
case 'lodash-core': return 3;
case 'lodash-dev':
case null: return 0;
}
return -1;
}());
loaderList.selectedIndex = (function() {
switch (loader) {
case 'curl': return 1;
case 'dojo': return 2;
case 'requirejs': return 3;
case 'none':
case null: return 0;
}
return -1;
}());
buildList.addEventListener('change', eventHandler);
loaderList.addEventListener('change', eventHandler);
}
var span1 = document.createElement('span');
span1.innerHTML =
'<label for="qunit-build">Build: </label>' +
'<select id="qunit-build">' +
'<option value="lodash-dev">lodash (development)</option>' +
'<option value="lodash">lodash (production)</option>' +
'<option value="lodash-core-dev">lodash-core (development)</option>' +
'<option value="lodash-core">lodash-core (production)</option>' +
'</select>';
var span2 = document.createElement('span');
span2.innerHTML =
'<label for="qunit-loader">Loader: </label>' +
'<select id="qunit-loader">' +
'<option value="none">None</option>' +
'<option value="curl">Curl</option>' +
'<option value="dojo">Dojo</option>' +
'<option value="requirejs">RequireJS</option>' +
'</select>';
span1.style.cssText =
span2.style.cssText = 'display:inline-block;float:right;line-height:2.1em;margin-left:1em;margin-top:0;';
span1.firstChild.style.cssText =
span2.firstChild.style.cssText = 'display:inline-block;margin-right:.5em;';
var buildList = span1.lastChild,
loaderList = span2.lastChild;
setTimeout(function() {
ui.timing.loadEventEnd = +new Date;
}, 1);
init();
});
// The lodash build file path.
ui.buildPath = (function() {
var result;
switch (build) {
case 'lodash': result = 'dist/lodash.min.js'; break;
case 'lodash-core-dev': result = 'dist/lodash.core.js'; break;
case 'lodash-core': result = 'dist/lodash.core.min.js'; break;
case null: build = 'lodash-dev';
case 'lodash-dev': result = 'lodash.js'; break;
default: return build;
}
return basePath + result;
}());
// The module loader file path.
ui.loaderPath = (function() {
var result;
switch (loader) {
case 'curl': result = 'node_modules/curl-amd/dist/curl-kitchen-sink/curl.js'; break;
case 'dojo': result = 'node_modules/dojo/dojo.js'; break;
case 'requirejs': result = 'node_modules/requirejs/require.js'; break;
case null: loader = 'none'; return '';
default: return loader;
}
return basePath + result;
}());
// Used to indicate testing a core build.
ui.isCore = /\bcore(\.min)?\.js\b/.test(ui.buildPath);
// Used to indicate testing a foreign file.
ui.isForeign = RegExp('^(\\w+:)?//').test(build);
// Used to indicate testing a modularized build.
ui.isModularize = /\b(?:amd|commonjs|es|node|npm|(index|main)\.js)\b/.test([location.pathname, location.search]);
// Used to indicate testing in Sauce Labs' automated test cloud.
ui.isSauceLabs = location.port == '9001';
// Used to indicate that lodash is in strict mode.
ui.isStrict = /\bes\b/.test([location.pathname, location.search]);
ui.urlParams = { 'build': build, 'loader': loader };
ui.timing = { 'loadEventEnd': 0 };
window.ui = ui;
}(this));

View File

@@ -1,17 +0,0 @@
'use strict';
self.console || (self.console = { 'log': function() {} });
addEventListener('message', function(e) {
if (e.data) {
try {
importScripts('../' + e.data);
} catch (e) {
var lineNumber = e.lineNumber,
message = (lineNumber == null ? '' : (lineNumber + ': ')) + e.message;
self._ = { 'VERSION': message };
}
postMessage(_.VERSION);
}
});

View File

@@ -1,170 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Backbone Test Suite</title>
<link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
</head>
<body>
<script>
// Avoid reporting tests to Sauce Labs when script errors occur.
if (location.port == '9001') {
window.onerror = function(message) {
if (window.QUnit) {
QUnit.config.done.length = 0;
}
global_test_results = { 'message': message };
};
}
</script>
<script src="../node_modules/qunitjs/qunit/qunit.js"></script>
<script src="../node_modules/qunit-extras/qunit-extras.js"></script>
<script src="../vendor/json-js/json2.js"></script>
<script src="../node_modules/platform/platform.js"></script>
<script src="./asset/test-ui.js"></script>
<script src="../lodash.js"></script>
<script>
QUnit.config.asyncRetries = 10;
QUnit.config.hidepassed = true;
var mixinPrereqs = (function() {
var aliasToReal = {
'indexBy': 'keyBy',
'invoke': 'invokeMap'
};
var keyMap = {
'rest': 'tail'
};
var lodash = _.noConflict();
return function(_) {
lodash(_)
.defaultsDeep({ 'templateSettings': lodash.templateSettings })
.mixin(lodash.pick(lodash, lodash.difference([
'countBy',
'debounce',
'difference',
'find',
'findIndex',
'findLastIndex',
'groupBy',
'includes',
'invert',
'invokeMap',
'keyBy',
'omit',
'partition',
'reduceRight',
'reject',
'sample',
'without'
], lodash.functions(_))))
.value();
lodash.forOwn(keyMap, function(realName, otherName) {
_[otherName] = lodash[realName];
_.prototype[otherName] = lodash.prototype[realName];
});
lodash.forOwn(aliasToReal, function(realName, alias) {
_[alias] = _[realName];
_.prototype[alias] = _.prototype[realName];
});
return _;
};
}());
// Load prerequisite scripts.
document.write(ui.urlParams.loader == 'none'
? '<script src="' + ui.buildPath + '"><\/script>'
: '<script data-dojo-config="async:1" src="' + ui.loaderPath + '"><\/script>'
);
</script>
<script>
if (ui.urlParams.loader == 'none') {
mixinPrereqs(_);
document.write([
'<script src="../node_modules/jquery/dist/jquery.js"><\/script>',
'<script src="../vendor/backbone/backbone.js"><\/script>',
'<script src="../vendor/backbone/test/setup/dom-setup.js"><\/script>',
'<script src="../vendor/backbone/test/setup/environment.js"><\/script>',
'<script src="../vendor/backbone/test/noconflict.js"><\/script>',
'<script src="../vendor/backbone/test/events.js"><\/script>',
'<script src="../vendor/backbone/test/model.js"><\/script>',
'<script src="../vendor/backbone/test/collection.js"><\/script>',
'<script src="../vendor/backbone/test/router.js"><\/script>',
'<script src="../vendor/backbone/test/view.js"><\/script>',
'<script src="../vendor/backbone/test/sync.js"><\/script>'
].join('\n'));
}
</script>
<script>
(function() {
if (window.curl) {
curl.config({ 'apiName': 'require' });
}
if (!window.require) {
return;
}
var reBasename = /[\w.-]+$/,
basePath = ('//' + location.host + location.pathname.replace(reBasename, '')).replace(/\btest\/$/, ''),
modulePath = ui.buildPath.replace(/\.js$/, ''),
locationPath = modulePath.replace(reBasename, '').replace(/^\/|\/$/g, ''),
moduleMain = modulePath.match(reBasename)[0],
uid = +new Date;
function getConfig() {
var result = {
'baseUrl': './',
'urlArgs': 't=' + uid++,
'waitSeconds': 0,
'paths': {
'backbone': '../vendor/backbone/backbone',
'jquery': '../node_modules/jquery/dist/jquery'
},
'packages': [{
'name': 'test',
'location': '../vendor/backbone/test',
'config': {
// Work around no global being exported.
'exports': 'QUnit',
'loader': 'curl/loader/legacy'
}
}]
};
if (ui.isModularize) {
result.packages.push({
'name': 'underscore',
'location': locationPath,
'main': moduleMain
});
} else {
result.paths.underscore = modulePath;
}
return result;
}
QUnit.config.autostart = false;
require(getConfig(), ['underscore'], function(lodash) {
_ = mixinPrereqs(lodash);
require(getConfig(), ['backbone'], function() {
require(getConfig(), [
'test/setup/dom-setup',
'test/setup/environment',
'test/noconflict',
'test/events',
'test/model',
'test/collection',
'test/router',
'test/view',
'test/sync'
], QUnit.start);
});
});
}());
</script>
</body>
</html>

View File

@@ -1,41 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>lodash-fp Test Suite</title>
<link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
</head>
<body>
<script>
// Avoid reporting tests to Sauce Labs when script errors occur.
if (location.port == '9001') {
window.onerror = function(message) {
if (window.QUnit) {
QUnit.config.done.length = 0;
}
global_test_results = { 'message': message };
};
}
</script>
<script src="../lodash.js"></script>
<script src="../dist/lodash.fp.js"></script>
<script src="../dist/mapping.fp.js"></script>
<script src="../node_modules/qunitjs/qunit/qunit.js"></script>
<script src="../node_modules/qunit-extras/qunit-extras.js"></script>
<script src="../node_modules/platform/platform.js"></script>
<script src="./test-fp.js"></script>
<div id="qunit"></div>
<script>
// Set a more readable browser name.
window.onload = function() {
var timeoutId = setInterval(function() {
var ua = document.getElementById('qunit-userAgent');
if (ua) {
ua.innerHTML = platform;
clearInterval(timeoutId);
}
}, 16);
};
</script>
</body>
</html>

View File

@@ -1,341 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>lodash Test Suite</title>
<link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
<style>
#exports, #module {
display: none;
}
</style>
</head>
<body>
<script>
// Avoid reporting tests to Sauce Labs when script errors occur.
if (location.port == '9001') {
window.onerror = function(message) {
if (window.QUnit) {
QUnit.config.done.length = 0;
}
global_test_results = { 'message': message };
};
}
</script>
<script src="../node_modules/lodash/lodash.js"></script>
<script>var lodashStable = _.noConflict();</script>
<script src="../node_modules/qunitjs/qunit/qunit.js"></script>
<script src="../node_modules/qunit-extras/qunit-extras.js"></script>
<script src="../node_modules/platform/platform.js"></script>
<script src="./asset/test-ui.js"></script>
<div id="qunit"></div>
<div id="exports"></div>
<div id="module"></div>
<script>
function setProperty(object, key, value) {
try {
Object.defineProperty(object, key, {
'configurable': true,
'enumerable': false,
'writable': true,
'value': value
});
} catch (e) {
object[key] = value;
}
return object;
}
function addBizarroMethods() {
var funcProto = Function.prototype,
objectProto = Object.prototype;
var hasOwnProperty = objectProto.hasOwnProperty,
fnToString = funcProto.toString,
nativeString = fnToString.call(objectProto.toString),
noop = function() {},
propertyIsEnumerable = objectProto.propertyIsEnumerable,
reToString = /toString/g;
function constant(value) {
return function() {
return value;
};
}
function createToString(funcName) {
return constant(nativeString.replace(reToString, funcName));
}
// Allow bypassing native checks.
setProperty(funcProto, 'toString', (function() {
function wrapper() {
setProperty(funcProto, 'toString', fnToString);
var result = hasOwnProperty.call(this, 'toString') ? this.toString() : fnToString.call(this);
setProperty(funcProto, 'toString', wrapper);
return result;
}
return wrapper;
}()));
// Add prototype extensions.
funcProto._method = noop;
// Set bad shims.
setProperty(Object, '_create', Object.create);
setProperty(Object, 'create', undefined);
setProperty(Object, '_getOwnPropertySymbols', Object.getOwnPropertySymbols);
setProperty(Object, 'getOwnPropertySymbols', undefined);
setProperty(objectProto, '_propertyIsEnumerable', propertyIsEnumerable);
setProperty(objectProto, 'propertyIsEnumerable', function(key) {
return !(key == 'valueOf' && this && this.valueOf === 1) && _propertyIsEnumerable.call(this, key);
});
setProperty(window, '_Map', window.Map);
if (_Map) {
setProperty(window, 'Map', (function(Map) {
var count = 0;
return function() {
if (count++) {
return new Map;
}
var result = {};
setProperty(window, 'Map', Map);
return result;
};
}(_Map)));
setProperty(Map, 'toString', createToString('Map'));
}
setProperty(window, '_Promise', window.Promise);
setProperty(window, 'Promise', noop);
setProperty(window, '_Set', window.Set);
setProperty(window, 'Set', noop);
setProperty(window, '_Symbol', window.Symbol);
setProperty(window, 'Symbol', undefined);
setProperty(window, '_WeakMap', window.WeakMap);
setProperty(window, 'WeakMap', noop);
// Fake `WinRTError`.
setProperty(window, 'WinRTError', Error);
// Fake free variable `global`.
setProperty(window, 'exports', window);
setProperty(window, 'global', window);
setProperty(window, 'module', {});
}
function removeBizarroMethods() {
var funcProto = Function.prototype,
objectProto = Object.prototype;
setProperty(objectProto, 'propertyIsEnumerable', objectProto._propertyIsEnumerable);
if (Object._create) {
Object.create = Object._create;
} else {
delete Object.create;
}
if (Object._getOwnPropertySymbols) {
Object.getOwnPropertySymbols = Object._getOwnPropertySymbols;
} else {
delete Object.getOwnPropertySymbols;
}
if (_Map) {
Map = _Map;
} else {
setProperty(window, 'Map', undefined);
}
if (_Promise) {
Promise = _Promise;
} else {
setProperty(window, 'Promise', undefined);
}
if (_Set) {
Set = _Set;
} else {
setProperty(window, 'Set', undefined);
}
if (_Symbol) {
Symbol = _Symbol;
}
if (_WeakMap) {
WeakMap = _WeakMap;
} else {
setProperty(window, 'WeakMap', undefined);
}
setProperty(window, '_Map', undefined);
setProperty(window, '_Promise', undefined);
setProperty(window, '_Set', undefined);
setProperty(window, '_Symbol', undefined);
setProperty(window, '_WeakMap', undefined);
setProperty(window, 'WinRTError', undefined);
setProperty(window, 'exports', document.getElementById('exports'));
setProperty(window, 'global', undefined);
setProperty(window, 'module', document.getElementById('module'));
delete funcProto._method;
delete Object._create;
delete Object._getOwnPropertySymbols;
delete objectProto._propertyIsEnumerable;
}
// Load lodash to expose it to the bad extensions/shims.
if (!ui.isModularize) {
addBizarroMethods();
document.write('<script src="' + ui.buildPath + '"><\/script>');
}
</script>
<script>
// Store lodash to test for bad extensions/shims.
if (!ui.isModularize) {
var lodashBizarro = window._;
window._ = undefined;
removeBizarroMethods();
}
// Load test scripts.
document.write((ui.isForeign || ui.urlParams.loader == 'none')
? '<script src="' + ui.buildPath + '"><\/script><script src="test.js"><\/script>'
: '<script data-dojo-config="async:1" src="' + ui.loaderPath + '"><\/script>'
);
</script>
<script>
var lodashModule,
shimmedModule,
underscoreModule;
(function() {
if (window.curl) {
curl.config({ 'apiName': 'require' });
}
if (ui.isForeign || !window.require) {
return;
}
var reBasename = /[\w.-]+$/,
basePath = ('//' + location.host + location.pathname.replace(reBasename, '')).replace(/\btest\/$/, ''),
modulePath = ui.buildPath.replace(/\.js$/, ''),
moduleMain = modulePath.match(reBasename)[0],
locationPath = modulePath.replace(reBasename, '').replace(/^\/|\/$/g, ''),
shimmedLocationPath = './abc/../' + locationPath,
underscoreLocationPath = './xyz/../' + locationPath,
uid = +new Date;
function getConfig() {
var result = {
'baseUrl': './',
'urlArgs': 't=' + uid++,
'waitSeconds': 0,
'paths': {},
'packages': [{
'name': 'test',
'location': basePath + 'test',
'main': 'test',
'config': {
// Work around no global being exported.
'exports': 'QUnit',
'loader': 'curl/loader/legacy'
}
}],
'shim': {
'shimmed': {
'exports': '_'
}
}
};
if (ui.isModularize) {
result.packages.push({
'name': 'lodash',
'location': locationPath,
'main': moduleMain
}, {
'name': 'shimmed',
'location': shimmedLocationPath,
'main': moduleMain
}, {
'name': 'underscore',
'location': underscoreLocationPath,
'main': moduleMain
});
} else {
result.paths.lodash = modulePath;
result.paths.shimmed = shimmedLocationPath + '/' + moduleMain;
result.paths.underscore = underscoreLocationPath + '/' + moduleMain;
}
return result;
}
function loadTests() {
require(getConfig(), ['test'], function() {
QUnit.start();
});
}
function loadModulesAndTests() {
require(getConfig(), ['lodash', 'shimmed', 'underscore'], function(lodash, shimmed, underscore) {
lodashModule = lodash;
lodashModule.moduleName = 'lodash';
if (shimmed) {
shimmedModule = shimmed.result(shimmed, 'noConflict') || shimmed;
shimmedModule.moduleName = 'shimmed';
}
if (underscore) {
underscoreModule = underscore.result(underscore, 'noConflict') || underscore;
underscoreModule.moduleName = 'underscore';
}
window._ = lodash;
if (ui.isModularize) {
require(getConfig(), [
'lodash/_baseEach',
'lodash/_isIndex',
'lodash/_isIterateeCall'
], function(baseEach, isIndex, isIterateeCall) {
lodash._baseEach = baseEach;
lodash._isIndex = isIndex;
lodash._isIterateeCall = isIterateeCall;
loadTests();
});
} else {
loadTests();
}
});
}
QUnit.config.autostart = false;
if (window.requirejs) {
addBizarroMethods();
require(getConfig(), ['lodash'], function(lodash) {
lodashBizarro = lodash.result(lodash, 'noConflict') || lodash;
delete requirejs.s.contexts._;
removeBizarroMethods();
loadModulesAndTests();
});
} else {
loadModulesAndTests();
}
}());
// Set a more readable browser name.
window.onload = function() {
var timeoutId = setInterval(function() {
var ua = document.getElementById('qunit-userAgent');
if (ua) {
ua.innerHTML = platform;
clearInterval(timeoutId);
}
}, 16);
};
</script>
</body>
</html>

View File

@@ -1,27 +0,0 @@
#!/usr/bin/env node
'use strict';
var _ = require('../lodash'),
fs = require('fs'),
path = require('path');
var args = (args = process.argv)
.slice((args[0] === process.execPath || args[0] === 'node') ? 2 : 0);
var filePath = path.resolve(args[1]),
reLine = /.*/gm;
var pattern = (function() {
var result = args[0],
delimiter = result.charAt(0),
lastIndex = result.lastIndexOf(delimiter);
return RegExp(result.slice(1, lastIndex), result.slice(lastIndex + 1));
}());
/*----------------------------------------------------------------------------*/
fs.writeFileSync(filePath, fs.readFileSync(filePath, 'utf8').replace(pattern, function(match) {
var snippet = _.slice(arguments, -3, -2)[0];
return match.replace(snippet, snippet.replace(reLine, ''));
}));

View File

@@ -1,908 +0,0 @@
#!/usr/bin/env node
'use strict';
/** Environment shortcut. */
var env = process.env;
/** Load Node.js modules. */
var EventEmitter = require('events').EventEmitter,
http = require('http'),
path = require('path'),
url = require('url'),
util = require('util');
/** Load other modules. */
var _ = require('../lodash.js'),
chalk = require('chalk'),
ecstatic = require('ecstatic'),
request = require('request'),
SauceTunnel = require('sauce-tunnel');
/** Used for Sauce Labs credentials. */
var accessKey = env.SAUCE_ACCESS_KEY,
username = env.SAUCE_USERNAME;
/** Used as the default maximum number of times to retry a job and tunnel. */
var maxJobRetries = 3,
maxTunnelRetries = 3;
/** Used as the static file server middleware. */
var mount = ecstatic({
'cache': 'no-cache',
'root': process.cwd()
});
/** Used as the list of ports supported by Sauce Connect. */
var ports = [
80, 443, 888, 2000, 2001, 2020, 2109, 2222, 2310, 3000, 3001, 3030, 3210,
3333, 4000, 4001, 4040, 4321, 4502, 4503, 4567, 5000, 5001, 5050, 5555, 5432,
6000, 6001, 6060, 6666, 6543, 7000, 7070, 7774, 7777, 8000, 8001, 8003, 8031,
8080, 8081, 8765, 8777, 8888, 9000, 9001, 9080, 9090, 9876, 9877, 9999, 49221,
55001
];
/** Used by `logInline` to clear previously logged messages. */
var prevLine = '';
/** Method shortcut. */
var push = Array.prototype.push;
/** Used to detect error messages. */
var reError = /(?:\be|E)rror\b/;
/** Used to detect valid job ids. */
var reJobId = /^[a-z0-9]{32}$/;
/** Used to display the wait throbber. */
var throbberDelay = 500,
waitCount = -1;
/**
* Used as Sauce Labs config values.
* See the [Sauce Labs documentation](https://docs.saucelabs.com/reference/test-configuration/)
* for more details.
*/
var advisor = getOption('advisor', false),
build = getOption('build', (env.TRAVIS_COMMIT || '').slice(0, 10)),
commandTimeout = getOption('commandTimeout', 90),
compatMode = getOption('compatMode', null),
customData = Function('return {' + getOption('customData', '').replace(/^\{|}$/g, '') + '}')(),
deviceOrientation = getOption('deviceOrientation', 'portrait'),
framework = getOption('framework', 'qunit'),
idleTimeout = getOption('idleTimeout', 60),
jobName = getOption('name', 'unit tests'),
maxDuration = getOption('maxDuration', 180),
port = ports[Math.min(_.sortedIndex(ports, getOption('port', 9001)), ports.length - 1)],
publicAccess = getOption('public', true),
queueTimeout = getOption('queueTimeout', 240),
recordVideo = getOption('recordVideo', true),
recordScreenshots = getOption('recordScreenshots', false),
runner = getOption('runner', 'test/index.html').replace(/^\W+/, ''),
runnerUrl = getOption('runnerUrl', 'http://localhost:' + port + '/' + runner),
statusInterval = getOption('statusInterval', 5),
tags = getOption('tags', []),
throttled = getOption('throttled', 10),
tunneled = getOption('tunneled', true),
tunnelId = getOption('tunnelId', 'tunnel_' + (env.TRAVIS_JOB_ID || 0)),
tunnelTimeout = getOption('tunnelTimeout', 120),
videoUploadOnPass = getOption('videoUploadOnPass', false);
/** Used to convert Sauce Labs browser identifiers to their formal names. */
var browserNameMap = {
'googlechrome': 'Chrome',
'iehta': 'Internet Explorer',
'ipad': 'iPad',
'iphone': 'iPhone',
'microsoftedge': 'Edge'
};
/** List of platforms to load the runner on. */
var platforms = [
['Linux', 'android', '5.1'],
['Windows 10', 'chrome', '54'],
['Windows 10', 'chrome', '53'],
['Windows 10', 'firefox', '50'],
['Windows 10', 'firefox', '49'],
['Windows 10', 'microsoftedge', '14'],
['Windows 10', 'internet explorer', '11'],
['Windows 8', 'internet explorer', '10'],
['Windows 7', 'internet explorer', '9'],
['macOS 10.12', 'safari', '10'],
['OS X 10.11', 'safari', '9']
];
/** Used to tailor the `platforms` array. */
var isAMD = _.includes(tags, 'amd'),
isBackbone = _.includes(tags, 'backbone'),
isModern = _.includes(tags, 'modern');
// The platforms to test IE compatibility modes.
if (compatMode) {
platforms = [
['Windows 10', 'internet explorer', '11'],
['Windows 8', 'internet explorer', '10'],
['Windows 7', 'internet explorer', '9'],
['Windows 7', 'internet explorer', '8']
];
}
// The platforms for AMD tests.
if (isAMD) {
platforms = _.filter(platforms, function(platform) {
var browser = browserName(platform[1]),
version = +platform[2];
switch (browser) {
case 'Android': return version >= 4.4;
case 'Opera': return version >= 10;
}
return true;
});
}
// The platforms for Backbone tests.
if (isBackbone) {
platforms = _.filter(platforms, function(platform) {
var browser = browserName(platform[1]),
version = +platform[2];
switch (browser) {
case 'Firefox': return version >= 4;
case 'Internet Explorer': return version >= 7;
case 'iPad': return version >= 5;
case 'Opera': return version >= 12;
}
return true;
});
}
// The platforms for modern builds.
if (isModern) {
platforms = _.filter(platforms, function(platform) {
var browser = browserName(platform[1]),
version = +platform[2];
switch (browser) {
case 'Android': return version >= 4.1;
case 'Firefox': return version >= 10;
case 'Internet Explorer': return version >= 9;
case 'iPad': return version >= 6;
case 'Opera': return version >= 12;
case 'Safari': return version >= 6;
}
return true;
});
}
/** Used as the default `Job` options object. */
var jobOptions = {
'build': build,
'command-timeout': commandTimeout,
'custom-data': customData,
'device-orientation': deviceOrientation,
'framework': framework,
'idle-timeout': idleTimeout,
'max-duration': maxDuration,
'name': jobName,
'public': publicAccess,
'platforms': platforms,
'record-screenshots': recordScreenshots,
'record-video': recordVideo,
'sauce-advisor': advisor,
'tags': tags,
'url': runnerUrl,
'video-upload-on-pass': videoUploadOnPass
};
if (publicAccess === true) {
jobOptions['public'] = 'public';
}
if (tunneled) {
jobOptions['tunnel-identifier'] = tunnelId;
}
/*----------------------------------------------------------------------------*/
/**
* Resolves the formal browser name for a given Sauce Labs browser identifier.
*
* @private
* @param {string} identifier The browser identifier.
* @returns {string} Returns the formal browser name.
*/
function browserName(identifier) {
return browserNameMap[identifier] || _.startCase(identifier);
}
/**
* Gets the value for the given option name. If no value is available the
* `defaultValue` is returned.
*
* @private
* @param {string} name The name of the option.
* @param {*} defaultValue The default option value.
* @returns {*} Returns the option value.
*/
function getOption(name, defaultValue) {
var isArr = _.isArray(defaultValue);
return _.reduce(process.argv, function(result, value) {
if (isArr) {
value = optionToArray(name, value);
return _.isEmpty(value) ? result : value;
}
value = optionToValue(name, value);
return value == null ? result : value;
}, defaultValue);
}
/**
* Checks if `value` is a job ID.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a job ID, else `false`.
*/
function isJobId(value) {
return reJobId.test(value);
}
/**
* Writes an inline message to standard output.
*
* @private
* @param {string} [text=''] The text to log.
*/
function logInline(text) {
var blankLine = _.repeat(' ', _.size(prevLine));
prevLine = text = _.truncate(text, { 'length': 40 });
process.stdout.write(text + blankLine.slice(text.length) + '\r');
}
/**
* Writes the wait throbber to standard output.
*
* @private
*/
function logThrobber() {
logInline('Please wait' + _.repeat('.', (++waitCount % 3) + 1));
}
/**
* 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(_.invokeMap((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 = string.match(RegExp('^' + name + '(?:=([\\s\\S]+))?$'));
if (result) {
result = _.get(result, 1);
result = result ? _.trim(result) : true;
}
if (result === 'false') {
return false;
}
return result || undefined;
}
/*----------------------------------------------------------------------------*/
/**
* The `Job#remove` and `Tunnel#stop` callback used by `Jobs#restart`
* and `Tunnel#restart` respectively.
*
* @private
*/
function onGenericRestart() {
this.restarting = false;
this.emit('restart');
this.start();
}
/**
* The `request.put` and `SauceTunnel#stop` callback used by `Jobs#stop`
* and `Tunnel#stop` respectively.
*
* @private
* @param {Object} [error] The error object.
*/
function onGenericStop(error) {
this.running = this.stopping = false;
this.emit('stop', error);
}
/**
* The `request.del` callback used by `Jobs#remove`.
*
* @private
*/
function onJobRemove(error, res, body) {
this.id = this.taskId = this.url = null;
this.removing = false;
this.emit('remove');
}
/**
* The `Job#remove` callback used by `Jobs#reset`.
*
* @private
*/
function onJobReset() {
this.attempts = 0;
this.failed = this.resetting = false;
this._pollerId = this.id = this.result = this.taskId = this.url = null;
this.emit('reset');
}
/**
* The `request.post` callback used by `Jobs#start`.
*
* @private
* @param {Object} [error] The error object.
* @param {Object} res The response data object.
* @param {Object} body The response body JSON object.
*/
function onJobStart(error, res, body) {
this.starting = false;
if (this.stopping) {
return;
}
var statusCode = _.get(res, 'statusCode'),
taskId = _.first(_.get(body, 'js tests'));
if (error || !taskId || statusCode != 200) {
if (this.attempts < this.retries) {
this.restart();
return;
}
var na = 'unavailable',
bodyStr = _.isObject(body) ? '\n' + JSON.stringify(body) : na,
statusStr = _.isFinite(statusCode) ? statusCode : na;
logInline();
console.error('Failed to start job; status: %s, body: %s', statusStr, bodyStr);
if (error) {
console.error(error);
}
this.failed = true;
this.emit('complete');
return;
}
this.running = true;
this.taskId = taskId;
this.timestamp = _.now();
this.emit('start');
this.status();
}
/**
* The `request.post` callback used by `Job#status`.
*
* @private
* @param {Object} [error] The error object.
* @param {Object} res The response data object.
* @param {Object} body The response body JSON object.
*/
function onJobStatus(error, res, body) {
this.checking = false;
if (!this.running || this.stopping) {
return;
}
var completed = _.get(body, 'completed', false),
data = _.first(_.get(body, 'js tests')),
elapsed = (_.now() - this.timestamp) / 1000,
jobId = _.get(data, 'job_id', null),
jobResult = _.get(data, 'result', null),
jobStatus = _.get(data, 'status', ''),
jobUrl = _.get(data, 'url', null),
expired = (elapsed >= queueTimeout && !_.includes(jobStatus, 'in progress')),
options = this.options,
platform = options.platforms[0];
if (_.isObject(jobResult)) {
var message = _.get(jobResult, 'message');
} else {
if (typeof jobResult == 'string') {
message = jobResult;
}
jobResult = null;
}
if (isJobId(jobId)) {
this.id = jobId;
this.result = jobResult;
this.url = jobUrl;
} else {
completed = false;
}
this.emit('status', jobStatus);
if (!completed && !expired) {
this._pollerId = _.delay(_.bind(this.status, this), this.statusInterval * 1000);
return;
}
var description = browserName(platform[1]) + ' ' + platform[2] + ' on ' + _.startCase(platform[0]),
errored = !jobResult || !jobResult.passed || reError.test(message) || reError.test(jobStatus),
failures = _.get(jobResult, 'failed'),
label = options.name + ':',
tunnel = this.tunnel;
if (errored || failures) {
if (errored && this.attempts < this.retries) {
this.restart();
return;
}
var details = 'See ' + jobUrl + ' for details.';
this.failed = true;
logInline();
if (failures) {
console.error(label + ' %s ' + chalk.red('failed') + ' %d test' + (failures > 1 ? 's' : '') + '. %s', description, failures, details);
}
else if (tunnel.attempts < tunnel.retries) {
tunnel.restart();
return;
}
else {
if (message === undefined) {
message = 'Results are unavailable. ' + details;
}
console.error(label, description, chalk.red('failed') + ';', message);
}
}
else {
logInline();
console.log(label, description, chalk.green('passed'));
}
this.running = false;
this.emit('complete');
}
/**
* The `SauceTunnel#start` callback used by `Tunnel#start`.
*
* @private
* @param {boolean} success The connection success indicator.
*/
function onTunnelStart(success) {
this.starting = false;
if (this._timeoutId) {
clearTimeout(this._timeoutId);
this._timeoutId = null;
}
if (!success) {
if (this.attempts < this.retries) {
this.restart();
return;
}
logInline();
console.error('Failed to open Sauce Connect tunnel');
process.exit(2);
}
logInline();
console.log('Sauce Connect tunnel opened');
var jobs = this.jobs;
push.apply(jobs.queue, jobs.all);
this.running = true;
this.emit('start');
console.log('Starting jobs...');
this.dequeue();
}
/*----------------------------------------------------------------------------*/
/**
* The Job constructor.
*
* @private
* @param {Object} [properties] The properties to initialize a job with.
*/
function Job(properties) {
EventEmitter.call(this);
this.options = {};
_.merge(this, properties);
_.defaults(this.options, _.cloneDeep(jobOptions));
this.attempts = 0;
this.checking = this.failed = this.removing = this.resetting = this.restarting = this.running = this.starting = this.stopping = false;
this._pollerId = this.id = this.result = this.taskId = this.url = null;
}
util.inherits(Job, EventEmitter);
/**
* Removes the job.
*
* @memberOf Job
* @param {Function} callback The function called once the job is removed.
* @param {Object} Returns the job instance.
*/
Job.prototype.remove = function(callback) {
this.once('remove', _.iteratee(callback));
if (this.removing) {
return this;
}
this.removing = true;
return this.stop(function() {
var onRemove = _.bind(onJobRemove, this);
if (!this.id) {
_.defer(onRemove);
return;
}
request.del(_.template('https://saucelabs.com/rest/v1/${user}/jobs/${id}')(this), {
'auth': { 'user': this.user, 'pass': this.pass }
}, onRemove);
});
};
/**
* Resets the job.
*
* @memberOf Job
* @param {Function} callback The function called once the job is reset.
* @param {Object} Returns the job instance.
*/
Job.prototype.reset = function(callback) {
this.once('reset', _.iteratee(callback));
if (this.resetting) {
return this;
}
this.resetting = true;
return this.remove(onJobReset);
};
/**
* Restarts the job.
*
* @memberOf Job
* @param {Function} callback The function called once the job is restarted.
* @param {Object} Returns the job instance.
*/
Job.prototype.restart = function(callback) {
this.once('restart', _.iteratee(callback));
if (this.restarting) {
return this;
}
this.restarting = true;
var options = this.options,
platform = options.platforms[0],
description = browserName(platform[1]) + ' ' + platform[2] + ' on ' + _.startCase(platform[0]),
label = options.name + ':';
logInline();
console.log('%s %s restart %d of %d', label, description, ++this.attempts, this.retries);
return this.remove(onGenericRestart);
};
/**
* Starts the job.
*
* @memberOf Job
* @param {Function} callback The function called once the job is started.
* @param {Object} Returns the job instance.
*/
Job.prototype.start = function(callback) {
this.once('start', _.iteratee(callback));
if (this.starting || this.running) {
return this;
}
this.starting = true;
request.post(_.template('https://saucelabs.com/rest/v1/${user}/js-tests')(this), {
'auth': { 'user': this.user, 'pass': this.pass },
'json': this.options
}, _.bind(onJobStart, this));
return this;
};
/**
* Checks the status of a job.
*
* @memberOf Job
* @param {Function} callback The function called once the status is resolved.
* @param {Object} Returns the job instance.
*/
Job.prototype.status = function(callback) {
this.once('status', _.iteratee(callback));
if (this.checking || this.removing || this.resetting || this.restarting || this.starting || this.stopping) {
return this;
}
this._pollerId = null;
this.checking = true;
request.post(_.template('https://saucelabs.com/rest/v1/${user}/js-tests/status')(this), {
'auth': { 'user': this.user, 'pass': this.pass },
'json': { 'js tests': [this.taskId] }
}, _.bind(onJobStatus, this));
return this;
};
/**
* Stops the job.
*
* @memberOf Job
* @param {Function} callback The function called once the job is stopped.
* @param {Object} Returns the job instance.
*/
Job.prototype.stop = function(callback) {
this.once('stop', _.iteratee(callback));
if (this.stopping) {
return this;
}
this.stopping = true;
if (this._pollerId) {
clearTimeout(this._pollerId);
this._pollerId = null;
this.checking = false;
}
var onStop = _.bind(onGenericStop, this);
if (!this.running || !this.id) {
_.defer(onStop);
return this;
}
request.put(_.template('https://saucelabs.com/rest/v1/${user}/jobs/${id}/stop')(this), {
'auth': { 'user': this.user, 'pass': this.pass }
}, onStop);
return this;
};
/*----------------------------------------------------------------------------*/
/**
* The Tunnel constructor.
*
* @private
* @param {Object} [properties] The properties to initialize the tunnel with.
*/
function Tunnel(properties) {
EventEmitter.call(this);
_.merge(this, properties);
var active = [],
queue = [];
var all = _.map(this.platforms, _.bind(function(platform) {
return new Job(_.merge({
'user': this.user,
'pass': this.pass,
'tunnel': this,
'options': { 'platforms': [platform] }
}, this.job));
}, this));
var completed = 0,
restarted = [],
success = true,
total = all.length,
tunnel = this;
_.invokeMap(all, 'on', 'complete', function() {
_.pull(active, this);
if (success) {
success = !this.failed;
}
if (++completed == total) {
tunnel.stop(_.partial(tunnel.emit, 'complete', success));
return;
}
tunnel.dequeue();
});
_.invokeMap(all, 'on', 'restart', function() {
if (!_.includes(restarted, this)) {
restarted.push(this);
}
// Restart tunnel if all active jobs have restarted.
var threshold = Math.min(all.length, _.isFinite(throttled) ? throttled : 3);
if (tunnel.attempts < tunnel.retries &&
active.length >= threshold && _.isEmpty(_.difference(active, restarted))) {
tunnel.restart();
}
});
this.on('restart', function() {
completed = 0;
success = true;
restarted.length = 0;
});
this._timeoutId = null;
this.attempts = 0;
this.restarting = this.running = this.starting = this.stopping = false;
this.jobs = { 'active': active, 'all': all, 'queue': queue };
this.connection = new SauceTunnel(this.user, this.pass, this.id, this.tunneled, ['-P', '0']);
}
util.inherits(Tunnel, EventEmitter);
/**
* Restarts the tunnel.
*
* @memberOf Tunnel
* @param {Function} callback The function called once the tunnel is restarted.
*/
Tunnel.prototype.restart = function(callback) {
this.once('restart', _.iteratee(callback));
if (this.restarting) {
return this;
}
this.restarting = true;
logInline();
console.log('Tunnel %s: restart %d of %d', this.id, ++this.attempts, this.retries);
var jobs = this.jobs,
active = jobs.active,
all = jobs.all;
var reset = _.after(all.length, _.bind(this.stop, this, onGenericRestart)),
stop = _.after(active.length, _.partial(_.invokeMap, all, 'reset', reset));
if (_.isEmpty(active)) {
_.defer(stop);
}
if (_.isEmpty(all)) {
_.defer(reset);
}
_.invokeMap(active, 'stop', function() {
_.pull(active, this);
stop();
});
if (this._timeoutId) {
clearTimeout(this._timeoutId);
this._timeoutId = null;
}
return this;
};
/**
* Starts the tunnel.
*
* @memberOf Tunnel
* @param {Function} callback The function called once the tunnel is started.
* @param {Object} Returns the tunnel instance.
*/
Tunnel.prototype.start = function(callback) {
this.once('start', _.iteratee(callback));
if (this.starting || this.running) {
return this;
}
this.starting = true;
logInline();
console.log('Opening Sauce Connect tunnel...');
var onStart = _.bind(onTunnelStart, this);
if (this.timeout) {
this._timeoutId = _.delay(onStart, this.timeout * 1000, false);
}
this.connection.start(onStart);
return this;
};
/**
* Removes jobs from the queue and starts them.
*
* @memberOf Tunnel
* @param {Object} Returns the tunnel instance.
*/
Tunnel.prototype.dequeue = function() {
var count = 0,
jobs = this.jobs,
active = jobs.active,
queue = jobs.queue,
throttled = this.throttled;
while (queue.length && (active.length < throttled)) {
var job = queue.shift();
active.push(job);
_.delay(_.bind(job.start, job), ++count * 1000);
}
return this;
};
/**
* Stops the tunnel.
*
* @memberOf Tunnel
* @param {Function} callback The function called once the tunnel is stopped.
* @param {Object} Returns the tunnel instance.
*/
Tunnel.prototype.stop = function(callback) {
this.once('stop', _.iteratee(callback));
if (this.stopping) {
return this;
}
this.stopping = true;
logInline();
console.log('Shutting down Sauce Connect tunnel...');
var jobs = this.jobs,
active = jobs.active;
var stop = _.after(active.length, _.bind(function() {
var onStop = _.bind(onGenericStop, this);
if (this.running) {
this.connection.stop(onStop);
} else {
onStop();
}
}, this));
jobs.queue.length = 0;
if (_.isEmpty(active)) {
_.defer(stop);
}
_.invokeMap(active, 'stop', function() {
_.pull(active, this);
stop();
});
if (this._timeoutId) {
clearTimeout(this._timeoutId);
this._timeoutId = null;
}
return this;
};
/*----------------------------------------------------------------------------*/
// Cleanup any inline logs when exited via `ctrl+c`.
process.on('SIGINT', function() {
logInline();
process.exit();
});
// Create a web server for the current working directory.
http.createServer(function(req, res) {
// See http://msdn.microsoft.com/en-us/library/ff955275(v=vs.85).aspx.
if (compatMode && path.extname(url.parse(req.url).pathname) == '.html') {
res.setHeader('X-UA-Compatible', 'IE=' + compatMode);
}
mount(req, res);
}).listen(port);
// Setup Sauce Connect so we can use this server from Sauce Labs.
var tunnel = new Tunnel({
'user': username,
'pass': accessKey,
'id': tunnelId,
'job': { 'retries': maxJobRetries, 'statusInterval': statusInterval },
'platforms': platforms,
'retries': maxTunnelRetries,
'throttled': throttled,
'tunneled': tunneled,
'timeout': tunnelTimeout
});
tunnel.on('complete', function(success) {
process.exit(success ? 0 : 1);
});
tunnel.start();
setInterval(logThrobber, throbberDelay);

File diff suppressed because it is too large Load Diff

26787
test/test.js

File diff suppressed because it is too large Load Diff

View File

@@ -1,466 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Underscore Test Suite</title>
<link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
</head>
<body>
<div id="qunit"></div>
<script>
// Avoid reporting tests to Sauce Labs when script errors occur.
if (location.port == '9001') {
window.onerror = function(message) {
if (window.QUnit) {
QUnit.config.done.length = 0;
}
global_test_results = { 'message': message };
};
}
</script>
<script src="../node_modules/qunitjs/qunit/qunit.js"></script>
<script src="../node_modules/qunit-extras/qunit-extras.js"></script>
<script src="../node_modules/jquery/dist/jquery.js"></script>
<script src="../node_modules/platform/platform.js"></script>
<script src="./asset/test-ui.js"></script>
<script src="../lodash.js"></script>
<script>
QUnit.config.asyncRetries = 10;
QUnit.config.hidepassed = true;
QUnit.config.excused = {
'Arrays': {
'chunk': [
'defaults to empty array (chunk size 0)'
],
'difference': [
'can perform an OO-style difference'
],
'drop': [
'is an alias for rest'
],
'first': [
'returns an empty array when n <= 0 (0 case)',
'returns an empty array when n <= 0 (negative case)',
'can fetch the first n elements',
'returns the whole array if n > length'
],
'findIndex': [
'called with context'
],
'findLastIndex': [
'called with context'
],
'flatten': [
'supports empty arrays',
'can flatten nested arrays',
'works on an arguments object',
'can handle very deep arrays'
],
'indexOf': [
"sorted indexOf doesn't uses binary search",
'0'
],
'initial': [
'returns all but the last n elements',
'returns an empty array when n > length',
'works on an arguments object'
],
'intersection': [
'can perform an OO-style intersection'
],
'last': [
'returns an empty array when n <= 0 (0 case)',
'returns an empty array when n <= 0 (negative case)',
'can fetch the last n elements',
'returns the whole array if n > length'
],
'lastIndexOf': [
'should treat falsey `fromIndex` values, except `0` and `NaN`, as `array.length`',
'should treat non-number `fromIndex` values as `array.length`',
'[0,-1,-1]'
],
'object': [
'an array of pairs zipped together into an object',
'an object converted to pairs and back to an object'
],
'rest': [
'returns the whole array when index is 0',
'returns elements starting at the given index',
'works on an arguments object'
],
'sortedIndex': [
'2',
'3'
],
'tail': [
'is an alias for rest'
],
'take': [
'is an alias for first'
],
'uniq': [
'uses the result of `iterator` for uniqueness comparisons (unsorted case)',
'`sorted` argument defaults to false when omitted',
'when `iterator` is a string, uses that key for comparisons (unsorted case)',
'uses the result of `iterator` for uniqueness comparisons (sorted case)',
'when `iterator` is a string, uses that key for comparisons (sorted case)',
'can use falsey pluck like iterator'
],
'union': [
'can perform an OO-style union'
]
},
'Chaining': {
'pop': true,
'shift': true,
'splice': true,
'reverse/concat/unshift/pop/map': [
'can chain together array functions.'
]
},
'Collections': {
'lookupIterator with contexts': true,
'Iterating objects with sketchy length properties': true,
'Resistant to collection length and properties changing while iterating': true,
'countBy': [
'{}',
'[{}]'
],
'each': [
'context object property accessed'
],
'every': [
'Can be called with object',
'Died on test #15',
'context works'
],
'filter': [
'given context',
'OO-filter'
],
'find': [
'called with context'
],
'findWhere': [
'checks properties given function'
],
'groupBy': [
'{}',
'[{}]'
],
'includes': [
"doesn't delegate to binary search"
],
'invoke': [
'handles null & undefined'
],
'map': [
'tripled numbers with context',
'OO-style doubled numbers'
],
'max': [
'can handle null/undefined',
'can perform a computation-based max',
'Maximum value of an empty object',
'Maximum value of an empty array',
'Maximum value of a non-numeric collection',
'Finds correct max in array starting with num and containing a NaN',
'Finds correct max in array starting with NaN',
'Respects iterator return value of -Infinity',
'String keys use property iterator',
'Iterator context',
'Lookup falsy iterator'
],
'min': [
'can handle null/undefined',
'can perform a computation-based min',
'Minimum value of an empty object',
'Minimum value of an empty array',
'Minimum value of a non-numeric collection',
'Finds correct min in array starting with NaN',
'Respects iterator return value of Infinity',
'String keys use property iterator',
'Iterator context',
'Lookup falsy iterator'
],
'partition': [
'can reference the array index',
'Died on test #8',
'partition takes a context argument'
],
'pluck': [
'[1]'
],
'reduce': [
'can reduce with a context object'
],
'reject': [
'Returns empty list given empty array'
],
'sample': [
'behaves correctly on negative n',
'Died on test #3'
],
'some': [
'Can be called with object',
'Died on test #17',
'context works'
],
'where': [
'checks properties given function'
],
'Can use various collection methods on NodeLists': [
'<span id="id2"></span>'
]
},
'Functions': {
'debounce asap': true,
'debounce asap cancel': true,
'debounce asap recursively': true,
'debounce after system time is set backwards': true,
'debounce re-entrant': true,
'throttle repeatedly with results': true,
'more throttle does not trigger leading call when leading is set to false': true,
'throttle does not trigger trailing call when trailing is set to false': true,
'before': true,
'bind': [
'Died on test #2'
],
'bindAll': [
'throws an error for bindAll with no functions named'
],
'debounce': [
'incr was debounced'
],
'iteratee': [
'"bbiz"',
'"foo"',
'1'
],
'memoize': [
'{"bar":"BAR","foo":"FOO"}',
'Died on test #8'
]
},
'Objects': {
'#1929 Typed Array constructors are functions': true,
'allKeys': [
'is not fooled by sparse arrays; see issue #95',
'is not fooled by sparse arrays with additional properties',
'[]'
],
'extend': [
'extending null results in null',
'extending undefined results in undefined'
],
'extendOwn': [
'extending non-objects results in returning the non-object value',
'extending undefined results in undefined'
],
'functions': [
'also looks up functions on the prototype'
],
'isEqual': [
'`0` is not equal to `-0`',
'Commutative equality is implemented for `0` and `-0`',
'`new Number(0)` and `-0` are not equal',
'Commutative equality is implemented for `new Number(0)` and `-0`',
'Invalid dates are not equal',
'false'
],
'isFinite': [
'Numeric strings are numbers',
'Number instances can be finite'
],
'isSet': [
'Died on test #9'
],
'findKey': [
'called with context'
],
'keys': [
'is not fooled by sparse arrays; see issue #95',
'[]'
],
'mapObject': [
'keep context',
'called with context',
'mapValue identity'
],
'omit': [
'can accept a predicate',
'function is given context'
],
'pick': [
'can accept a predicate and context',
'function is given context'
]
},
'Utility': {
'_.escape & unescape': [
'` is escaped',
'` can be unescaped',
'can escape multiple occurances of `',
'multiple occurrences of ` can be unescaped'
],
'now': [
'Produces the correct time in milliseconds'
],
'times': [
'works as a wrapper'
]
}
};
var mixinPrereqs = (function() {
var aliasToReal = {
'all': 'every',
'allKeys': 'keysIn',
'any': 'some',
'collect': 'map',
'compose': 'flowRight',
'contains': 'includes',
'detect': 'find',
'extendOwn': 'assign',
'findWhere': 'find',
'foldl': 'reduce',
'foldr': 'reduceRight',
'include': 'includes',
'indexBy': 'keyBy',
'inject': 'reduce',
'invoke': 'invokeMap',
'mapObject': 'mapValues',
'matcher': 'matches',
'methods': 'functions',
'object': 'zipObject',
'pairs': 'toPairs',
'pluck': 'map',
'restParam': 'restArgs',
'select': 'filter',
'unique': 'uniq',
'where': 'filter'
};
var keyMap = {
'rest': 'tail',
'restArgs': 'rest'
};
var lodash = _.noConflict();
return function(_) {
lodash(_)
.defaultsDeep({ 'templateSettings': lodash.templateSettings })
.mixin(lodash.pick(lodash, lodash.difference(lodash.functions(lodash), lodash.functions(_))))
.value();
lodash.forOwn(keyMap, function(realName, otherName) {
_[otherName] = lodash[realName];
_.prototype[otherName] = lodash.prototype[realName];
});
lodash.forOwn(aliasToReal, function(realName, alias) {
_[alias] = _[realName];
_.prototype[alias] = _.prototype[realName];
});
return _;
};
}());
// Only excuse in Sauce Labs.
if (!ui.isSauceLabs) {
delete QUnit.config.excused.Functions['throttle does not trigger trailing call when trailing is set to false'];
delete QUnit.config.excused.Utility.now;
}
// Load prerequisite scripts.
document.write(ui.urlParams.loader == 'none'
? '<script src="' + ui.buildPath + '"><\/script>'
: '<script data-dojo-config="async:1" src="' + ui.loaderPath + '"><\/script>'
);
</script>
<script>
if (ui.urlParams.loader == 'none') {
mixinPrereqs(_);
document.write([
'<script src="../vendor/underscore/test/collections.js"><\/script>',
'<script src="../vendor/underscore/test/arrays.js"><\/script>',
'<script src="../vendor/underscore/test/functions.js"><\/script>',
'<script src="../vendor/underscore/test/objects.js"><\/script>',
'<script src="../vendor/underscore/test/cross-document.js"><\/script>',
'<script src="../vendor/underscore/test/utility.js"><\/script>',
'<script src="../vendor/underscore/test/chaining.js"><\/script>'
].join('\n'));
}
</script>
<script>
(function() {
if (window.curl) {
curl.config({ 'apiName': 'require' });
}
if (!window.require) {
return;
}
// Wrap to work around tests assuming Node `require` use.
require = (function(func) {
return function() {
return arguments[0] === '..' ? window._ : func.apply(null, arguments);
};
}(require));
var reBasename = /[\w.-]+$/,
basePath = ('//' + location.host + location.pathname.replace(reBasename, '')).replace(/\btest\/$/, ''),
modulePath = ui.buildPath.replace(/\.js$/, ''),
locationPath = modulePath.replace(reBasename, '').replace(/^\/|\/$/g, ''),
moduleId = /\bunderscore\b/i.test(ui.buildPath) ? 'underscore' : 'lodash',
moduleMain = modulePath.match(reBasename)[0],
uid = +new Date;
function getConfig() {
var result = {
'baseUrl': './',
'urlArgs': 't=' + uid++,
'waitSeconds': 0,
'paths': {},
'packages': [{
'name': 'test',
'location': '../vendor/underscore/test',
'config': {
// Work around no global being exported.
'exports': 'QUnit',
'loader': 'curl/loader/legacy'
}
}]
};
if (ui.isModularize) {
result.packages.push({
'name': moduleId,
'location': locationPath,
'main': moduleMain
});
} else {
result.paths[moduleId] = modulePath;
}
return result;
}
QUnit.config.autostart = false;
QUnit.config.excused.Functions.iteratee = true;
QUnit.config.excused.Utility.noConflict = true;
QUnit.config.excused.Utility['noConflict (node vm)'] = true;
require(getConfig(), [moduleId], function(lodash) {
_ = mixinPrereqs(lodash);
require(getConfig(), [
'test/collections',
'test/arrays',
'test/functions',
'test/objects',
'test/cross-document',
'test/utility',
'test/chaining'
], QUnit.start);
});
}());
</script>
</body>
</html>