2016-05-16 13:33:49 +02:00
|
|
|
<!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': [
|
2017-05-13 13:25:33 +02:00
|
|
|
'{}',
|
|
|
|
'[{}]'
|
2016-05-16 13:33:49 +02:00
|
|
|
],
|
|
|
|
'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': [
|
2017-05-13 13:25:33 +02:00
|
|
|
'{}',
|
|
|
|
'[{}]'
|
2016-05-16 13:33:49 +02:00
|
|
|
],
|
|
|
|
'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',
|
2017-05-13 13:25:33 +02:00
|
|
|
'partition takes a context argument'
|
2016-05-16 13:33:49 +02:00
|
|
|
],
|
|
|
|
'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': [
|
2017-05-13 13:25:33 +02:00
|
|
|
'<span id="id2"></span>'
|
2016-05-16 13:33:49 +02:00
|
|
|
]
|
|
|
|
},
|
|
|
|
'Functions': {
|
|
|
|
'debounce asap': true,
|
|
|
|
'debounce asap cancel': true,
|
|
|
|
'debounce asap recursively': true,
|
2017-05-13 13:25:33 +02:00
|
|
|
'debounce after system time is set backwards': true,
|
|
|
|
'debounce re-entrant': true,
|
2016-05-16 13:33:49 +02:00
|
|
|
'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,
|
2017-05-13 13:25:33 +02:00
|
|
|
'before': true,
|
2016-05-16 13:33:49 +02:00
|
|
|
'bind': [
|
|
|
|
'Died on test #2'
|
|
|
|
],
|
|
|
|
'bindAll': [
|
|
|
|
'throws an error for bindAll with no functions named'
|
|
|
|
],
|
2017-05-13 13:25:33 +02:00
|
|
|
'debounce': [
|
|
|
|
'incr was debounced'
|
|
|
|
],
|
|
|
|
'iteratee': [
|
|
|
|
'"bbiz"',
|
|
|
|
'"foo"',
|
|
|
|
'1'
|
|
|
|
],
|
2016-05-16 13:33:49 +02:00
|
|
|
'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`',
|
2017-05-13 13:25:33 +02:00
|
|
|
'Invalid dates are not equal',
|
2016-05-16 13:33:49 +02:00
|
|
|
'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': {
|
2017-05-13 13:25:33 +02:00
|
|
|
'_.escape & unescape': [
|
|
|
|
'` is escaped',
|
|
|
|
'` can be unescaped',
|
|
|
|
'can escape multiple occurances of `',
|
|
|
|
'multiple occurrences of ` can be unescaped'
|
|
|
|
],
|
2016-05-16 13:33:49 +02:00
|
|
|
'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(_) {
|
2017-05-13 13:25:33 +02:00
|
|
|
lodash(_)
|
|
|
|
.defaultsDeep({ 'templateSettings': lodash.templateSettings })
|
|
|
|
.mixin(lodash.pick(lodash, lodash.difference(lodash.functions(lodash), lodash.functions(_))))
|
|
|
|
.value();
|
2016-05-16 13:33:49 +02:00
|
|
|
|
|
|
|
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];
|
|
|
|
});
|
2017-05-13 13:25:33 +02:00
|
|
|
return _;
|
2016-05-16 13:33:49 +02:00
|
|
|
};
|
|
|
|
}());
|
|
|
|
|
|
|
|
// 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;
|
2017-05-13 13:25:33 +02:00
|
|
|
QUnit.config.excused.Functions.iteratee = true;
|
|
|
|
QUnit.config.excused.Utility.noConflict = true;
|
|
|
|
QUnit.config.excused.Utility['noConflict (node vm)'] = true;
|
2016-05-16 13:33:49 +02:00
|
|
|
|
|
|
|
require(getConfig(), [moduleId], function(lodash) {
|
2017-05-13 13:25:33 +02:00
|
|
|
_ = mixinPrereqs(lodash);
|
2016-05-16 13:33:49 +02:00
|
|
|
require(getConfig(), [
|
|
|
|
'test/collections',
|
|
|
|
'test/arrays',
|
|
|
|
'test/functions',
|
|
|
|
'test/objects',
|
|
|
|
'test/cross-document',
|
|
|
|
'test/utility',
|
|
|
|
'test/chaining'
|
2017-05-13 13:25:33 +02:00
|
|
|
], QUnit.start);
|
2016-05-16 13:33:49 +02:00
|
|
|
});
|
|
|
|
}());
|
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|