Socket
Socket
Sign inDemoInstall

lodash

Package Overview
Dependencies
0
Maintainers
1
Versions
114
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.0 to 0.2.0

perf/perf.js

8

package.json
{
"name": "lodash",
"version": "0.1.0",
"description": "A drop-in replacement for Underscore.js that delivers up to 8x performance improvements, bug fixes, and additional features.",
"homepage": "https://github.com/bestiejs/lodash",
"version": "0.2.0",
"description": "A drop-in replacement for Underscore.js that delivers performance improvements, bug fixes, and additional features.",
"homepage": "http://lodash.com",
"main": "lodash",

@@ -19,3 +19,3 @@ "keywords": [

"type": "MIT",
"url": "http://mths.be/mit"
"url": "http://lodash.com/license"
}

@@ -22,0 +22,0 @@ ],

@@ -1,27 +0,58 @@

# Lo-Dash <sup>v0.1.0</sup>
# Lo-Dash <sup>v0.2.0</sup>
A drop-in replacement for [Underscore.js](https://github.com/documentcloud/underscore/) that delivers up to [8x performance improvements](http://jsperf.com/lodash-underscore#chart=bar), [bug fixes](https://github.com/bestiejs/lodash/blob/master/test/test.js#L71), and additional features.
A drop-in replacement for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), that delivers [performance improvements](http://jsperf.com/lodash-underscore#filterby=family), bug fixes, and additional features.
## BestieJS
Lo-Dash’s performance is gained by avoiding slower native methods, instead opting for simplified non-ES5 compliant methods optimized for common usage, and by leveraging function compilation to reduce the number of overall function calls.
Lo-Dash is part of the BestieJS *"Best in Class"* module collection. This means we promote solid browser/environment support, ES5 precedents, unit testing, and plenty of documentation.
## Dive in
## Documentation
We’ve got [API docs](http://lodash.com/docs) and [unit tests](http://lodash.com/tests).
The documentation for Lo-Dash can be viewed here: [/doc/README.md](https://github.com/bestiejs/lodash/blob/master/doc/README.md#readme)
Underscore's [documentation](http://documentcloud.github.com/underscore/) may also be used.
For a list of upcoming features, check out our [roadmap](https://github.com/bestiejs/lodash/wiki/Roadmap).
## So What's The Secret?
## Screencasts
Lo-Dash's performance is gained by avoiding native methods, instead opting for simplified non-ES5 compliant methods optimized for common usage, and by leveraging function compilation to reduce the number of overall function calls.
For more information check out these screencasts over Lo-Dash:
## What else?
* [Introducing Lo-Dash](http://dl.dropbox.com/u/513327/allyoucanleet/post/20/file/screencast.mp4)
* [Optimizations and custom builds](http://dl.dropbox.com/u/513327/allyoucanleet/post/21/file/screencast.mp4)
Lo-Dash comes with AMD loader support baked in, chainable `_.each`, and will [soon address](https://github.com/bestiejs/lodash/wiki/Roadmap) cross-browser object iteration issues.
## Features
* AMD loader support
* [_.bind](http://lodash.com/docs#_bindfunc--arg1-arg2-) supports *"lazy"* binding
* [_.debounce](http://lodash.com/docs#_debouncefunc-wait-immediate)’ed functions match [_.throttle](http://lodash.com/docs#_throttlefunc-wait)’ed functions’ return value behavior
* [_.forEach](http://lodash.com/docs#_foreachcollection-callback--thisarg) is chainable
* [_.groupBy](http://lodash.com/docs#_groupbycollection-callback--thisarg) accepts a third `thisArg` argument
* [_.partial](http://lodash.com/docs#_partialfunc--arg1-arg2-) for more functional fun
* [_.size](http://lodash.com/docs#_sizecollection) returns the `length` of string values
## Support
Lo-Dash has been tested in at least Chrome 5-19, Firefox 1.5-12, IE 6-9, Opera 9.25-11.64, Safari 3.0.4-5.1.3, Node.js 0.4.8-0.6.18, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC3.
## Custom builds
Custom builds make it easy to create lightweight versions of Lo-Dash containing only the methods you need.
We handle all the method dependency and alias mapping for you.
Custom builds may be created in two ways:
1. Use the`include` argument to pass the names of the methods to include in the build.
~~~ bash
node build include=each,filter,map,noConflict
node build include="each, filter, map, noConflict"
~~~
2. Use the `exclude` argument to pass the names of the methods to exclude from the build.
~~~ bash
node build exclude=isNaN,isUndefined,union,zip
node build exclude="isNaN, isUndefined, union, zip"
~~~
Custom builds are saved to `lodash.custom.js` and `lodash.custom.min.js`.
## Installation and usage
In a browser:
In browsers:

@@ -32,3 +63,3 @@ ~~~ html

Via [npm](http://npmjs.org/):
Using [npm](http://npmjs.org/):

@@ -60,11 +91,8 @@ ~~~ bash

~~~ js
// opt-in
define.amd.lodash = true;
require({
'paths': {
'lodash': 'path/to/lodash'
'underscore': 'path/to/lodash'
}
},
['lodash'], function(_) {
['underscore'], function(_) {
console.log(_.VERSION);

@@ -91,4 +119,98 @@ });

Feel free to fork and send pull requests if you see improvements!
## Closed Underscore.js issues
* Fix Firefox, IE, Opera, and Safari object iteration bugs [#376](https://github.com/documentcloud/underscore/issues/376)
* Handle arrays with `undefined` values correctly in IE < 9 [#601](https://github.com/documentcloud/underscore/issues/601)
* Methods should work on pages with incorrectly shimmed native methods [#7](https://github.com/documentcloud/underscore/issues/7)
* Register as AMD module, but still export to global [#431](https://github.com/documentcloud/underscore/pull/431)
* `_.forEach` should be chainable [#142](https://github.com/documentcloud/underscore/issues/142)
* `_isNaN(new Number(NaN))` should return `true`
* `_.reduceRight` should pass correct callback arguments when iterating objects
* `_.size` should return the `length` of string values
## Optimized methods <sup>(50+)</sup>
* `_.bind`
* `_.bindAll`
* `_.clone`
* `_.compact`
* `_.contains`, `_.include`
* `_.defaults`
* `_.defer`
* `_.difference`
* `_.each`
* `_.escape`
* `_.every`, `_.all`
* `_.extend`
* `_.filter`, `_.select`
* `_.find`, `_.detect`
* `_.flatten`
* `_.forEach`, `_.each`
* `_.functions`, `_.methods`
* `_.groupBy`
* `_.indexOf`
* `_.intersection`, `_.intersect`
* `_.invoke`
* `_.isEmpty`
* `_.isEqual`
* `_.isFinite`
* `_.isObject`
* `_.isString`
* `_.keys`
* `_.lastIndexOf`
* `_.map`, `_.collect`
* `_.max`
* `_.memoize`
* `_.min`
* `_.mixin`
* `_.pick`
* `_.pluck`
* `_.reduce`, `_.foldl`, `_.inject`
* `_.reject`
* `_.result`
* `_.shuffle`
* `_.some`, `_.any`
* `_.sortBy`
* `_.sortedIndex`
* `_.template`
* `_.throttle`
* `_.toArray`
* `_.union`
* `_.uniq`, `_.unique`
* `_.values`
* `_.without`
* `_.wrap`
* `_.zip`
* plus all `_(...)` method wrappers
## Changelog
### <sup>v0.2.0</sup>
* Added custom build options
* Added default `_.templateSettings.variable` value
* Added *"lazy bind"* support to `_.bind`
* Added native method overwrite detection to avoid bad native shims
* Added support for more AMD build optimizers and aliasing as the *"underscore"* module
* Added `thisArg` to `_.groupBy`
* Added whitespace to compiled strings
* Added `_.partial`
* Commented the `iterationFactory` options object
* Ensured `_.max` and `_.min` support extremely large arrays
* Fixed IE < 9 `[DontEnum]` bug and Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1’s prototype property iteration bug
* Inlined `_.isFunction` calls.
* Made `_.debounce`’ed functions match `_.throttle`’ed functions’ return value behavior
* Made `_.escape` no longer translate the *">"* character
* Fixed `clearTimeout` typo
* Simplified all methods in the *"Arrays"* category
* Optimized `_.debounce`, `_.escape`, `_.flatten`, `_.forEach`, `_.groupBy`, `_.intersection`, `_.invoke`, `_.isObject`, `_.max`, `_.min`, `_.pick`, `_.shuffle`, `_.sortedIndex`, `_.template`, `_.throttle`, `_.union`, `_.uniq`
### <sup>v0.1.0</sup>
* Initial release
## BestieJS
Lo-Dash is part of the BestieJS *"Best in Class"* module collection. This means we promote solid browser/environment support, ES5 precedents, unit testing, and plenty of documentation.
## Author

@@ -103,1 +225,3 @@

[![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter")
* [Mathias Bynens](http://mathiasbynens.be/)
[![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter")

@@ -29,2 +29,13 @@ (function(window, undefined) {

/** Used to check problem JScript properties (a.k.a. the [[DontEnum]] bug) */
var shadowed = {
'constructor': 1,
'hasOwnProperty': 2,
'isPrototypeOf': 3,
'propertyIsEnumerable': 4,
'toLocaleString': 5,
'toString': 6,
'valueOf': 7
};
/*--------------------------------------------------------------------------*/

@@ -46,3 +57,3 @@

// must explicitly use `QUnit.module` instead of `module()`
// explicitly call `QUnit.module()` instead of `module()`
// in case we are in a CLI environment

@@ -52,5 +63,5 @@ QUnit.module('lodash');

(function() {
test('supports loading lodash.js as a module', function() {
test('supports loading lodash.js as the "lodash" module', function() {
if (window.document && window.require) {
equal((_2 || {}).VERSION, _.VERSION);
equal((_2 || {}).moduleName, 'lodash');
} else {

@@ -60,2 +71,18 @@ skipTest(1)

});
test('supports loading lodash.js as the "underscore" module', function() {
if (window.document && window.require) {
equal((_3 || {}).moduleName, 'underscore');
} else {
skipTest(1)
}
});
test('avoids overwritten native methods', function() {
if (window.lodashBadKeys) {
notDeepEqual(lodashBadKeys.keys({ 'a': 1 }), []);
} else {
skipTest(1);
}
});
}());

@@ -71,2 +98,7 @@

});
test('should pass through LoDash instances', function() {
var wrapped = _([]);
equal(_(wrapped), wrapped);
});
}());

@@ -76,2 +108,76 @@

QUnit.module('lodash.bind');
(function() {
test('supports lazy bind', function() {
var object = {
'name': 'moe',
'greet': function(greeting) {
return greeting + ': ' + this.name;
}
};
var func = _.bind(object, 'greet', 'hi');
equal(func(), 'hi: moe');
object.greet = function(greeting) {
return greeting + ' ' + this.name + '!';
};
equal(func(), 'hi moe!');
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.debounce');
(function() {
test('subsequent "immediate" debounced calls should return the result of the first call', function() {
var debounced = _.debounce(function(value) { return value; }, 100, true),
result = [debounced('x'), debounced('y')];
deepEqual(result, ['x', 'x']);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.escape');
(function() {
test('should not escape the ">" character', function() {
equal(_.escape('>'), '>');
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.extend');
(function() {
test('should not error on `null` or `undefined` sources (test in IE < 9)', function() {
try {
deepEqual(_.extend({}, null, undefined, { 'a': 1 }), { 'a': 1 });
} catch(e) {
ok(false);
}
});
test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() {
function Foo() {}
Foo.prototype.c = 3;
Foo.a = 1;
Foo.b = 2;
var expected = { 'a': 1, 'b': 2 };
deepEqual(_.extend({}, Foo), expected);
Foo.prototype = { 'c': 3 };
deepEqual(_.extend({}, Foo), expected);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.forEach');

@@ -84,2 +190,11 @@

});
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
var object = {};
_.forEach(shadowed, function(value, key) {
object[key] = value;
});
deepEqual(object, shadowed);
});
}());

@@ -89,2 +204,16 @@

QUnit.module('lodash.groupBy');
(function() {
test('supports the `thisArg` argument', function() {
var actual = _.groupBy([1.3, 2.1, 2.4], function(num) {
return this.floor(num);
}, Math);
deepEqual(actual, { '1': [1.3], '2': [2.1, 2.4] });
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.initial');

@@ -101,2 +230,22 @@

QUnit.module('lodash.isEmpty');
(function() {
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
equal(_.isEmpty(shadowed), false);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.isEqual');
(function() {
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
equal(_.isEqual(shadowed, {}), false);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.isNaN');

@@ -112,2 +261,81 @@

QUnit.module('lodash.keys');
(function() {
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
function Foo() {}
Foo.prototype.a = 1;
deepEqual(_.keys(Foo.prototype), ['a']);
deepEqual(_.keys(shadowed).sort(),
'constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf'.split(' '));
});
}());
/*--------------------------------------------------------------------------*/
(function() {
var i = -1,
largeArray = [];
while (++i <= 1e6) {
largeArray[i] = i;
}
_.each(['max', 'min'], function(methodName) {
QUnit.module('lodash.' + methodName);
test('does not error when computing the ' + methodName + ' value of massive arrays', function() {
try {
var actual = _[methodName](largeArray);
} catch(e) { }
equal(actual, methodName == 'max' ? 1e6 : 0);
});
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.partial');
(function() {
test('partially applies an argument, without additional arguments', function() {
var arg = 'catnip',
func = function(x) { return x; };
equal(_.partial(func, arg)(), arg);
});
test('partially applies an argument, with additional arguments', function() {
var arg1 = 'catnip',
arg2 = 'cheese',
func = function(x, y) { return [x, y]; };
deepEqual(_.partial(func, arg1)(arg2), [arg1, arg2]);
});
test('works without partially applying arguments, without additional arguments', function() {
var func = function() { return arguments.length; };
equal(_.partial(func)(), 0);
});
test('works without partially applying arguments, with additional arguments', function() {
var arg = 'catnip',
func = function(x) { return x; };
equal(_.partial(func)(arg), arg);
});
test('should not alter the `this` binding of either function', function() {
var o = { 'cat': 'nip' },
func = function() { return this.cat; };
equal(_.partial(_.bind(func, o))(), o.cat);
equal(_.bind(_.partial(func), o)(), o.cat);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.reduceRight');

@@ -137,2 +365,6 @@

});
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
equal(_.size(shadowed), 7);
});
}());

@@ -142,2 +374,60 @@

QUnit.module('lodash.sortBy');
(function() {
test('supports the `thisArg` argument', function() {
var actual = _.sortBy([1, 2, 3, 4], function(num) {
return this.sin(num);
}, Math);
deepEqual(actual, [4, 3, 1, 2]);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.template');
(function() {
test('supports recursive calls', function() {
var compiled = _.template('<%= a %><% a = _.template(c, object) %><%= a %>'),
data = { 'a': 'A', 'b': 'B', 'c': '<%= b %>' };
equal(compiled(data), 'AB');
});
test('should not augment the `options` object', function() {
var options = {};
_.template('', null, options);
deepEqual(options, {});
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.throttle');
(function() {
test('subsequent calls should return the result of the first call', function() {
var throttled = _.throttle(function(value) { return value; }, 100),
result = [throttled('x'), throttled('y')];
deepEqual(result, ['x', 'x']);
});
test('supports calls in a loop', function() {
var counter = 0,
throttled = _.throttle(function() { counter++; }, 100),
start = new Date,
limit = 220;
while ((new Date - start) < limit) {
throttled();
}
equal(counter, 3);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.toArray');

@@ -163,6 +453,33 @@

// explicitly call `QUnit.start()` in a CLI environment
if (!window.document) {
QUnit.start();
}
}(typeof global == 'object' && global || this));
QUnit.module('lodash(...).shift');
(function() {
test('should remove the value at index `0` when length is `0` (test in IE 8 compatibility mode)', function() {
var wrapped = _({ '0': 1, 'length': 1 });
wrapped.shift();
deepEqual(wrapped.keys(), ['length']);
equal(wrapped.first(), undefined);
});
}());
/*--------------------------------------------------------------------------*/
QUnit.module('lodash(...).splice');
(function() {
test('should remove the value at index `0` when length is `0` (test in IE < 9, and in compatibility mode for IE9)', function() {
var wrapped = _({ '0': 1, 'length': 1 });
wrapped.splice(0, 1);
deepEqual(wrapped.keys(), ['length']);
equal(wrapped.first(), undefined);
});
}());
/*--------------------------------------------------------------------------*/
// explicitly call `QUnit.start()` for Narwhal, Rhino, and RingoJS
QUnit.start();
}(typeof global == 'object' && global || this));

@@ -81,3 +81,3 @@ (function(window, undefined) {

// must explicitly use `QUnit.module` instead of `module()`
// explicitly call `QUnit.module()` instead of `module()`
// in case we are in a CLI environment

@@ -221,7 +221,7 @@ QUnit.module('Benchmark');

'inlined "setup", "fn", and "teardown"': (
'if(this instanceof Benchmark)this._fn=true;'
'if(/ops/.test(this))this._fn=true;'
),
'called "fn" and inlined "setup"/"teardown" reached by error': function() {
count++;
if (this instanceof Benchmark) {
if (/ops/.test(this)) {
this._fn = true;

@@ -231,3 +231,3 @@ }

'called "fn" and inlined "setup"/"teardown" reached by `return` statement': function() {
if (this instanceof Benchmark) {
if (/ops/.test(this)) {
this._fn = true;

@@ -242,5 +242,5 @@ }

var bench = Benchmark({
'setup': 'if(this instanceof Benchmark)this._setup=true;',
'setup': 'if(/ops/.test(this))this._setup=true;',
'fn': fn,
'teardown': 'if(this instanceof Benchmark)this._teardown=true;',
'teardown': 'if(/ops/.test(this))this._teardown=true;',
'onCycle': function() { this.abort(); }

@@ -1082,2 +1082,28 @@ }).run();

QUnit.module('Benchmark#run');
(function() {
var data = { 'onComplete': 0, 'onCycle': 0, 'onStart': 0 };
var bench = Benchmark({
'fn': function() {
this.count += 0;
},
'onStart': function() {
data.onStart++;
},
'onComplete': function() {
data.onComplete++;
}
})
.run();
test('onXYZ callbacks should not be triggered by internal benchmark clones', function() {
equal(data.onStart, 1);
equal(data.onComplete, 1);
});
}());
/*--------------------------------------------------------------------------*/
forOwn({

@@ -1962,6 +1988,20 @@ 'Benchmark': Benchmark,

asyncTest('works with string values for "fn", "setup", and "teardown"', function() {
asyncTest('should run with string values for "fn", "setup", and "teardown"', function() {
Benchmark({
'defer': true,
'setup': 'var x = [3, 2, 1];',
'fn': 'setTimeout(function() { x.sort(); deferred.resolve(); }, 10);',
'teardown': 'x.length = 0;',
'onComplete': function() {
ok(true);
QUnit.start();
}
})
.run();
});
asyncTest('should run recursively', function() {
Benchmark({
'defer': true,
'setup': 'var x = [3, 2, 1];',
'fn': 'x.sort(); deferred.resolve();',

@@ -2004,6 +2044,5 @@ 'teardown': 'x.length = 0;',

// explicitly call `QUnit.start()` in a CLI environment
if (!window.document) {
QUnit.start();
}
}(typeof global == 'object' && global || this));
// explicitly call `QUnit.start()` for Narwhal, Rhino, and RingoJS
QUnit.start();
}(typeof global == 'object' && global || this));
test("Close Numbers", function () {
var halfPi = Math.PI / 2,
sqrt2 = Math.sqrt(2);

@@ -6,17 +8,16 @@ QUnit.close(7, 7, 0);

QUnit.close(7, 7.1, 0.2);
QUnit.close(3.141, Math.PI, 0.001);
QUnit.close(3.1, Math.PI, 0.1);
var halfPi = Math.PI / 2;
QUnit.close(halfPi, 1.57, 0.001);
var sqrt2 = Math.sqrt(2);
QUnit.close(sqrt2, 1.4142, 0.0001);
QUnit.close(Infinity, Infinity, 1);
QUnit.close(Infinity, Infinity, 1);
});
test("Distant Numbers", function () {
var halfPi = Math.PI / 2,
sqrt2 = Math.sqrt(2);

@@ -26,14 +27,11 @@ QUnit.notClose(6, 7, 0);

QUnit.notClose(7, 7.2, 0.19999999999);
QUnit.notClose(3.141, Math.PI, 0.0001);
QUnit.notClose(3.1, Math.PI, 0.001);
var halfPi = Math.PI / 2;
QUnit.notClose(halfPi, 1.57, 0.0001);
var sqrt2 = Math.sqrt(2);
QUnit.notClose(sqrt2, 1.4142, 0.00001);
QUnit.notClose(Infinity, -Infinity, 5);
});

@@ -17,5 +17,5 @@ QUnit.extend( QUnit, {

},
/**
* Checks that the first two arguments are numbers with differences greater than the specified
* Checks that the first two arguments are numbers with differences greater than the specified
* minimum difference.

@@ -22,0 +22,0 @@ *

(function( QUnit ) {
var subsuiteFrame;
QUnit.extend( QUnit, {
testSuites: function( suites ) {
QUnit.begin(function() {
QUnit.initIframe();
});
for ( var i = 0; i < suites.length; i++ ) {
(function( suite ) {
asyncTest( suite, function() {
QUnit.runSuite( suite );
});
}( suites[i] ) );
QUnit.runSuite( suites[i] );
}
QUnit.done = function() {
subsuiteFrame.style.display = "none";
};
},
testStart: function( data ) {
// update the test status to show which test suite is running
QUnit.id( "qunit-testresult" ).innerHTML = "Running " + data.name + "...<br>&nbsp;";
QUnit.done(function() {
this.iframe.style.display = "none";
});
},
testDone: function() {
var current = QUnit.id( this.config.current.id ),
children = current.children;
// undo the auto-expansion of failed tests
for ( var i = 0; i < children.length; i++ ) {
if ( children[i].nodeName === "OL" ) {
children[i].style.display = "none";
}
}
runSuite: function( suite ) {
asyncTest( suite, function() {
QUnit.iframe.setAttribute( "src", suite );
});
},
runSuite: function( suite ) {
var body = document.getElementsByTagName( "body" )[0],
iframe = subsuiteFrame = document.createElement( "iframe" ),
initIframe: function() {
var body = document.body,
iframe = this.iframe = document.createElement( "iframe" ),
iframeWin;

@@ -48,25 +36,30 @@

QUnit.extend( iframeWin.QUnit, {
moduleStart: function( data ) {
// capture module name for messages
module = data.name;
},
testStart: function( data ) {
// capture test name for messages
test = data.name;
},
iframeWin.QUnit.moduleStart(function( data ) {
// capture module name for messages
module = data.name;
});
log: function( data ) {
// pass all test details through to the main page
var message = module + ": " + test + ": " + data.message;
expect( ++count );
QUnit.push( data.result, data.actual, data.expected, message );
},
iframeWin.QUnit.testStart(function( data ) {
// capture test name for messages
test = data.name;
});
iframeWin.QUnit.testDone(function() {
test = null;
});
done: function() {
// start the wrapper test from the main page
start();
iframeWin.QUnit.log(function( data ) {
if (test === null) {
return;
}
// pass all test details through to the main page
var message = module + ": " + test + ": " + data.message;
expect( ++count );
QUnit.push( data.result, data.actual, data.expected, message );
});
iframeWin.QUnit.done(function() {
// start the wrapper test from the main page
start();
});
}

@@ -76,9 +69,36 @@ QUnit.addEvent( iframe, "load", onIframeLoad );

iframeWin = iframe.contentWindow;
iframe.setAttribute( "src", suite );
}
});
this.runSuite = function( suite ) {
iframe.setAttribute( "src", suite );
};
QUnit.testStart(function( data ) {
// update the test status to show which test suite is running
QUnit.id( "qunit-testresult" ).innerHTML = "Running " + data.name + "...<br>&nbsp;";
});
QUnit.testDone(function() {
var i,
current = QUnit.id( this.config.current.id ),
children = current.children,
src = this.iframe.src;
// undo the auto-expansion of failed tests
for ( i = 0; i < children.length; i++ ) {
if ( children[i].nodeName === "OL" ) {
children[i].style.display = "none";
}
}
QUnit.addEvent(current, "dblclick", function( e ) {
var target = e && e.target ? e.target : window.event.srcElement;
if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
target = target.parentNode;
}
if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
window.location = src;
}
});
current.getElementsByTagName('a')[0].href = src;
});
}( QUnit ) );

@@ -12,3 +12,3 @@ QUnit.extend( QUnit, {

this.config.current.step++; // increment internal step counter.
if (typeof message == "undefined") {
if (typeof message === "undefined") {
message = "step " + expected;

@@ -23,5 +23,5 @@ }

* Reset the step counter for every test()
*/
*/
QUnit.testStart(function () {
this.config.current.step = 0;
});

@@ -0,2 +1,85 @@

1.6.0 / 2012-05-04
==================
* Save stack for each test, use that for failed expect() results, points at the line where test() was called. Fixes #209
* Prefix test-output id and ignore that in noglobals check. Fixes #212
* Only check for an exports object to detect a CommonJS enviroment. Fixes #237 - Incompatibility with require.js
* Add testswarm integration as grunt task
* Added padding on URL config checkboxes.
* Cleanup composite addon: Use callback registration instead of overwriting them. Set the correct src on rerun link (and dblclick). Remove the composite test itself, as that was a crazy hack not worth maintaining
* Cleanup reset() test and usage - run testDone callback first, to allow listeneres ignoring reset assertions
* Double clicking on composite test rows opens individual test page
* test-message for all message-bearing API reporting details
1.5.0 / 2012-04-04
==================
* Modify "Running..." to display test name. Fixes #220
* Fixed clearing of sessionStorage in Firefox 3.6.
* Fixes #217 by calling "block" with config.current.testEnvironment
* Add stats results to data. QUnit.jUnitReport function take one argument { xml:'<?xml ...', results:{failed:0, passed:0, total:0, time:0} }
* Add link to MDN about stack property
1.4.0 / 2012-03-10
==================
* Prefix test-related session-storage items to make removal more specific. Fixes #213 - Keep hide-passed state when clearing session storage
* Update grunt.js with seperate configs for qunit.js and grunt.js, also add tests but disable for now, not passing yet. Add grunt to devDependencies
* typo
* Cleanup grunt.js, no need for the banner
* Fix lint errors and some formatting issues. Use QUnit.pushFailure for noglobals and global error handler.
* Fix a missing expect in logs test
* Add grunt.js configuration and include some usage instructions in the readme
* Update package.json
* Partially revert af27eae841c3e1c01c46de72d676f1047e1ee375 - can't move reset around, so also don't wrap in try-catch, as the result of that is effectively swallowed. Can't output the result as the outputting is already done.
* Add QUnit.pushFailure to log error conditions like exceptions. Accepts stacktrace as second argument, allowing extraction with catched exceptions (useful even in Safari). Remove old fail() function that would just log to console, not useful anymore as regular test output is much more useful by now. Move up QUnit.reset() call to just make that another failed assertion. Used to not make a test fail. Fixes #210
* Update equals and same deprecations to use QUnit.push to provide correct source lines. Fixes #211
* Add a test file for narwhal integration. Has to use print instead of console.log. Fails when an assertion fails, something about setInterval...
* Apply notrycatch option to setup and teardown as well. Fixes #203. Reorder noglobals check to allow teardown to remove globals that were introduced intentionally. Fixes #204
* Extend exports object with QUnit properties at the end of the file to export everything.
* Output source line for ok() assertions. Fixes #202
* Make test fail if no assertions run. Fixes #178
* Sort object output alphabetically in order to improve diffs of objects where properties were set in a different order. Fixes #206
* Revert "Change fixture reset behavior", changing #194 and #195 to wontfix.
1.3.0 / 2012-02-26
==================
* Cleanup test markup
* Fix the jQuery branch of fixture reset. Would break when no fixture exists.
* Added initial version of a junitlogger addon.
* Escape document.title before inserting into markup. Extends fix for #127
* Catch assertions running outside of test() context, make sure source is provided even for ok(). Fixes #98
* Improve global object access, based on comments for 1a9120651d5464773256d8a1f2cf2eabe38ea5b3
* Clear all sessionStorage entries once all tests passed. Helps getting rid of items from renamed tests. Fixes #101
* Set fixed dimensions for #qunit-fixture. Fixes #114
* Extend nodejs test runner to check for stacktrace output, twice
* Extend nodejs test runner to check for stacktrace output
* Generate more base markup, but allow the user to exclude that completelty or choose their own. Fixes #127
* Add a simple test file to check basic nodejs integration works
* Check for global object to find setTimeout in node
* Fix CommonJS export by assigning QUnit to module.exports.
* Remove the testEnviromentArg to test(). Most obscure, never used anywhere. test() is still heavily overloaded with argument shifting, this makes it a little more sane. Fixes #172
* Serialize expected and actual values only when test fails. Speeds up output of valid tests, especially for lots of large objects. Fixes #183
* Fix sourceFromsTacktrace to get the right line in Firefox. Shift the 'error' line away in Chrome to get a match.
* Fix references to test/deepEqual.js
* In autorun mode, moduleDone is called without matching moduleStart. Fix issue #184
* Fixture test: allow anything falsy in test as getAttribute in oldIE will return empty string instead of null. We don't really care.
* Keep label and checkbox together ( http://i.imgur.com/5Wk3A.png )
* Add readme for themes
* Fix bad global in reset()
* Some cleanup in theme addons
* Update headers
* Update nv.html, add gabe theme based on https://github.com/jquery/qunit/pull/188
* Experiemental custom theme based on https://github.com/jquery/qunit/pull/62 by NV
* Replace deprecated same and equals aliases with placeholders that just throw errors, providing a hint at what to use instead. Rename test file to match that.
* Can't rely on outerHTML for Firefox < 11. Use cloneNode instead.
* Merge remote branch 'conzett/master'
* Cleanup whitespace
* Update sessionStorage support test to latest version from Modernizr, trying to setItem to avoid QUOTA_EXCEEDED_EXCEPTION
* Change fixture reset behavior
* Merge pull request #181 from simonz/development
* Escaping test names
* Show exception stack when test failed
1.2.0 / 2011-11-24

@@ -35,3 +118,2 @@ ==================

* Added more strict array type detection for dump output, and allowed NodeList objects to be output as arrays
* Bump post-release version
* Fixes a bug where after an async test, assertions could move between test cases because of internal state (config.current) being incorrectly set

@@ -38,0 +120,0 @@ * Simplified check for assertion count and adjusted whitespace

{
"name": "qunit",
"author": "The jQuery Project",
"version": "1.1.0pre",
"contributors": [
{
"name": "John Resig",
"email": "jeresig@gmail.com",
"url": "http://ejohn.org/"
},
{
"name": "Jörn Zaefferer",
"email": "joern.zaefferer@googlemail.com",
"url": "http://bassistance.de/"
}],
"url": "http://docs.jquery.com/QUnit",
"repositories" : [{
"type": "git",
"url": "https://github.com/jquery/qunit.git"
}],
"license": {
"name": "MIT",
"url": "http://www.opensource.org/licenses/mit-license.php"
},
"description": "An easy-to-use JavaScript Unit Testing framework.",
"keywords": [ "testing", "unit", "jquery" ],
"main": "qunit/qunit.js"
"name": "qunit",
"title": "QUnit",
"description": "An easy-to-use JavaScript Unit Testing framework.",
"version": "1.6.0",
"author": "The jQuery Project",
"contributors": [
"John Resig <jeresig@gmail.com> (http://ejohn.org/)",
"Jörn Zaefferer <joern.zaefferer@googlemail.com> (http://bassistance.de/)"
],
"homepage": "http://docs.jquery.com/QUnit",
"repository": {
"type": "git",
"url": "git://github.com/jquery/qunit.git"
},
"bugs": {
"url": "https://github.com/jquery/qunit/issues"
},
"license": {
"name": "MIT",
"url": "http://www.opensource.org/licenses/mit-license.php"
},
"keywords": [
"testing",
"unit",
"jquery"
],
"main": "qunit/qunit.js",
"devDependencies": {
"grunt": "0.3.x",
"testswarm": "0.2.1"
}
}
/**
* QUnit v1.2.0 - A JavaScript Unit Testing Framework
* QUnit v1.6.0 - A JavaScript Unit Testing Framework
*
* http://docs.jquery.com/QUnit
*
* Copyright (c) 2011 John Resig, Jörn Zaefferer
* Copyright (c) 2012 John Resig, Jörn Zaefferer
* Dual licensed under the MIT (MIT-LICENSE.txt)

@@ -11,38 +11,46 @@ * or GPL (GPL-LICENSE.txt) licenses.

(function(window) {
(function( window ) {
var defined = {
var QUnit,
config,
testId = 0,
toString = Object.prototype.toString,
hasOwn = Object.prototype.hasOwnProperty,
defined = {
setTimeout: typeof window.setTimeout !== "undefined",
sessionStorage: (function() {
var x = "qunit-test-string";
try {
return !!sessionStorage.getItem;
} catch(e) {
sessionStorage.setItem( x, x );
sessionStorage.removeItem( x );
return true;
} catch( e ) {
return false;
}
})()
}())
};
var testId = 0,
toString = Object.prototype.toString,
hasOwn = Object.prototype.hasOwnProperty;
var Test = function(name, testName, expected, testEnvironmentArg, async, callback) {
function Test( name, testName, expected, async, callback ) {
this.name = name;
this.testName = testName;
this.expected = expected;
this.testEnvironmentArg = testEnvironmentArg;
this.async = async;
this.callback = callback;
this.assertions = [];
};
}
Test.prototype = {
init: function() {
var tests = id("qunit-tests");
if (tests) {
var b = document.createElement("strong");
b.innerHTML = "Running " + this.name;
var li = document.createElement("li");
li.appendChild( b );
li.className = "running";
li.id = this.id = "test-output" + testId++;
var b, li,
tests = id( "qunit-tests" );
if ( tests ) {
b = document.createElement( "strong" );
b.innerHTML = "Running " + this.name;
li = document.createElement( "li" );
li.appendChild( b );
li.className = "running";
li.id = this.id = "qunit-test-output" + testId++;
tests.appendChild( li );

@@ -52,5 +60,5 @@ }

setup: function() {
if (this.module != config.previousModule) {
if ( this.module !== config.previousModule ) {
if ( config.previousModule ) {
runLoggingCallbacks('moduleDone', QUnit, {
runLoggingCallbacks( "moduleDone", QUnit, {
name: config.previousModule,

@@ -60,21 +68,23 @@ failed: config.moduleStats.bad,

total: config.moduleStats.all
} );
});
}
config.previousModule = this.module;
config.moduleStats = { all: 0, bad: 0 };
runLoggingCallbacks( 'moduleStart', QUnit, {
runLoggingCallbacks( "moduleStart", QUnit, {
name: this.module
} );
});
} else if ( config.autorun ) {
runLoggingCallbacks( "moduleStart", QUnit, {
name: this.module
});
}
config.current = this;
this.testEnvironment = extend({
setup: function() {},
teardown: function() {}
}, this.moduleTestEnvironment);
if (this.testEnvironmentArg) {
extend(this.testEnvironment, this.testEnvironmentArg);
}
}, this.moduleTestEnvironment );
runLoggingCallbacks( 'testStart', QUnit, {
runLoggingCallbacks( "testStart", QUnit, {
name: this.testName,

@@ -88,10 +98,13 @@ module: this.module

if ( !config.pollution ) {
saveGlobal();
}
if ( config.notrycatch ) {
this.testEnvironment.setup.call( this.testEnvironment );
return;
}
try {
if ( !config.pollution ) {
saveGlobal();
}
this.testEnvironment.setup.call(this.testEnvironment);
} catch(e) {
QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message );
this.testEnvironment.setup.call( this.testEnvironment );
} catch( e ) {
QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
}

@@ -101,2 +114,9 @@ },

config.current = this;
var running = id( "qunit-testresult" );
if ( running ) {
running.innerHTML = "Running: <br/>" + this.name;
}
if ( this.async ) {

@@ -107,10 +127,10 @@ QUnit.stop();

if ( config.notrycatch ) {
this.callback.call(this.testEnvironment);
this.callback.call( this.testEnvironment );
return;
}
try {
this.callback.call(this.testEnvironment);
} catch(e) {
fail("Test " + this.testName + " died, exception and test follows", e, this.callback);
QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) );
this.callback.call( this.testEnvironment );
} catch( e ) {
QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + ": " + e.message, extractStacktrace( e, 1 ) );
// else next test will carry the responsibility

@@ -127,8 +147,13 @@ saveGlobal();

config.current = this;
try {
this.testEnvironment.teardown.call(this.testEnvironment);
checkPollution();
} catch(e) {
QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message );
if ( config.notrycatch ) {
this.testEnvironment.teardown.call( this.testEnvironment );
return;
} else {
try {
this.testEnvironment.teardown.call( this.testEnvironment );
} catch( e ) {
QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
}
}
checkPollution();
},

@@ -138,7 +163,11 @@ finish: function() {

if ( this.expected != null && this.expected != this.assertions.length ) {
QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
} else if ( this.expected == null && !this.assertions.length ) {
QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
}
var good = 0, bad = 0,
tests = id("qunit-tests");
var assertion, a, b, i, li, ol,
good = 0,
bad = 0,
tests = id( "qunit-tests" );

@@ -149,10 +178,10 @@ config.stats.all += this.assertions.length;

if ( tests ) {
var ol = document.createElement("ol");
ol = document.createElement( "ol" );
for ( var i = 0; i < this.assertions.length; i++ ) {
var assertion = this.assertions[i];
for ( i = 0; i < this.assertions.length; i++ ) {
assertion = this.assertions[i];
var li = document.createElement("li");
li = document.createElement( "li" );
li.className = assertion.result ? "pass" : "fail";
li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed");
li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
ol.appendChild( li );

@@ -171,19 +200,21 @@

if ( QUnit.config.reorder && defined.sessionStorage ) {
if (bad) {
sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad);
if ( bad ) {
sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
} else {
sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName);
sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
}
}
if (bad == 0) {
if ( bad === 0 ) {
ol.style.display = "none";
}
var b = document.createElement("strong");
// `b` initialized at top of scope
b = document.createElement( "strong" );
b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
var a = document.createElement("a");
// `a` initialized at top of scope
a = document.createElement( "a" );
a.innerHTML = "Rerun";
a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
a.href = QUnit.url({ filter: getText([b]).replace( /\([^)]+\)$/, "" ).replace( /(^\s*|\s*$)/g, "" ) });

@@ -196,3 +227,3 @@ addEvent(b, "click", function() {

addEvent(b, "dblclick", function(e) {
addEvent(b, "dblclick", function( e ) {
var target = e && e.target ? e.target : window.event.srcElement;

@@ -203,7 +234,10 @@ if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {

if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
window.location = QUnit.url({
filter: getText([target]).replace( /\([^)]+\)$/, "" ).replace( /(^\s*|\s*$)/g, "" )
});
}
});
var li = id(this.id);
// `li` initialized at top of scope
li = id( this.id );
li.className = bad ? "fail" : "pass";

@@ -216,3 +250,3 @@ li.removeChild( li.firstChild );

} else {
for ( var i = 0; i < this.assertions.length; i++ ) {
for ( i = 0; i < this.assertions.length; i++ ) {
if ( !this.assertions[i].result ) {

@@ -226,9 +260,3 @@ bad++;

try {
QUnit.reset();
} catch(e) {
fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset);
}
runLoggingCallbacks( 'testDone', QUnit, {
runLoggingCallbacks( "testDone", QUnit, {
name: this.testName,

@@ -239,7 +267,11 @@ module: this.module,

total: this.assertions.length
} );
});
QUnit.reset();
},
queue: function() {
var test = this;
var bad,
test = this;
synchronize(function() {

@@ -263,17 +295,21 @@ test.init();

}
// `bad` initialized at top of scope
// defer when previous test run passed, if storage is available
var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName);
if (bad) {
bad = QUnit.config.reorder && defined.sessionStorage &&
+sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
if ( bad ) {
run();
} else {
synchronize(run, true);
};
synchronize( run, true );
}
}
};
var QUnit = {
// `QUnit` initialized at top of scope
QUnit = {
// call on start of module test to prepend name to all tests
module: function(name, testEnvironment) {
module: function( name, testEnvironment ) {
config.currentModule = name;

@@ -283,3 +319,3 @@ config.currentModuleTestEnviroment = testEnvironment;

asyncTest: function(testName, expected, callback) {
asyncTest: function( testName, expected, callback ) {
if ( arguments.length === 2 ) {

@@ -290,7 +326,8 @@ callback = expected;

QUnit.test(testName, expected, callback, true);
QUnit.test( testName, expected, callback, true );
},
test: function(testName, expected, callback, async) {
var name = '<span class="test-name">' + testName + '</span>', testEnvironmentArg;
test: function( testName, expected, callback, async ) {
var test,
name = "<span class='test-name'>" + escapeInnerText( testName ) + "</span>";

@@ -301,10 +338,5 @@ if ( arguments.length === 2 ) {

}
// is 2nd argument a testEnvironment?
if ( expected && typeof expected === 'object') {
testEnvironmentArg = expected;
expected = null;
}
if ( config.currentModule ) {
name = '<span class="module-name">' + config.currentModule + "</span>: " + name;
name = "<span class='module-name'>" + config.currentModule + "</span>: " + name;
}

@@ -316,29 +348,41 @@

var test = new Test(name, testName, expected, testEnvironmentArg, async, callback);
test = new Test( name, testName, expected, async, callback );
test.module = config.currentModule;
test.moduleTestEnvironment = config.currentModuleTestEnviroment;
test.stack = sourceFromStacktrace( 2 );
test.queue();
},
/**
* Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
*/
expect: function(asserts) {
// Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
expect: function( asserts ) {
config.current.expected = asserts;
},
/**
* Asserts true.
* @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
*/
ok: function(a, msg) {
a = !!a;
var details = {
result: a,
message: msg
};
msg = escapeInnerText(msg);
runLoggingCallbacks( 'log', QUnit, details );
// Asserts true.
// @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
ok: function( result, msg ) {
if ( !config.current ) {
throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
}
result = !!result;
var source,
details = {
result: result,
message: msg
};
msg = escapeInnerText( msg || (result ? "okay" : "failed" ) );
msg = "<span class='test-message'>" + msg + "</span>";
if ( !result ) {
source = sourceFromStacktrace( 2 );
if ( source ) {
details.source = source;
msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>";
}
}
runLoggingCallbacks( "log", QUnit, details );
config.current.assertions.push({
result: a,
result: result,
message: msg

@@ -348,42 +392,33 @@ });

/**
* Checks that the first two arguments are equal, with an optional message.
* Prints out both actual and expected values.
*
* Prefered to ok( actual == expected, message )
*
* @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
*
* @param Object actual
* @param Object expected
* @param String message (optional)
*/
equal: function(actual, expected, message) {
QUnit.push(expected == actual, actual, expected, message);
// Checks that the first two arguments are equal, with an optional message. Prints out both actual and expected values.
// @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes." );
equal: function( actual, expected, message ) {
QUnit.push( expected == actual, actual, expected, message );
},
notEqual: function(actual, expected, message) {
QUnit.push(expected != actual, actual, expected, message);
notEqual: function( actual, expected, message ) {
QUnit.push( expected != actual, actual, expected, message );
},
deepEqual: function(actual, expected, message) {
QUnit.push(QUnit.equiv(actual, expected), actual, expected, message);
deepEqual: function( actual, expected, message ) {
QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
},
notDeepEqual: function(actual, expected, message) {
QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message);
notDeepEqual: function( actual, expected, message ) {
QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
},
strictEqual: function(actual, expected, message) {
QUnit.push(expected === actual, actual, expected, message);
strictEqual: function( actual, expected, message ) {
QUnit.push( expected === actual, actual, expected, message );
},
notStrictEqual: function(actual, expected, message) {
QUnit.push(expected !== actual, actual, expected, message);
notStrictEqual: function( actual, expected, message ) {
QUnit.push( expected !== actual, actual, expected, message );
},
raises: function(block, expected, message) {
var actual, ok = false;
raises: function( block, expected, message ) {
var actual,
ok = false;
if (typeof expected === 'string') {
if ( typeof expected === "string" ) {
message = expected;

@@ -394,3 +429,3 @@ expected = null;

try {
block();
block.call( config.current.testEnvironment );
} catch (e) {

@@ -400,14 +435,14 @@ actual = e;

if (actual) {
if ( actual ) {
// we don't want to validate thrown error
if (!expected) {
if ( !expected ) {
ok = true;
// expected is a regexp
} else if (QUnit.objectType(expected) === "regexp") {
ok = expected.test(actual);
} else if ( QUnit.objectType( expected ) === "regexp" ) {
ok = expected.test( actual );
// expected is a constructor
} else if (actual instanceof expected) {
} else if ( actual instanceof expected ) {
ok = true;
// expected is a validation function which returns true is validation passed
} else if (expected.call({}, actual) === true) {
} else if ( expected.call( {}, actual ) === true ) {
ok = true;

@@ -417,13 +452,13 @@ }

QUnit.ok(ok, message);
QUnit.ok( ok, message );
},
start: function(count) {
start: function( count ) {
config.semaphore -= count || 1;
if (config.semaphore > 0) {
// don't start until equal number of stop-calls
// don't start until equal number of stop-calls
if ( config.semaphore > 0 ) {
return;
}
if (config.semaphore < 0) {
// ignore if start is called more often then stop
// ignore if start is called more often then stop
if ( config.semaphore < 0 ) {
config.semaphore = 0;

@@ -434,19 +469,19 @@ }

window.setTimeout(function() {
if (config.semaphore > 0) {
if ( config.semaphore > 0 ) {
return;
}
if ( config.timeout ) {
clearTimeout(config.timeout);
clearTimeout( config.timeout );
}
config.blocking = false;
process(true);
process( true );
}, 13);
} else {
config.blocking = false;
process(true);
process( true );
}
},
stop: function(count) {
stop: function( count ) {
config.semaphore += count || 1;

@@ -456,3 +491,3 @@ config.blocking = true;

if ( config.testTimeout && defined.setTimeout ) {
clearTimeout(config.timeout);
clearTimeout( config.timeout );
config.timeout = window.setTimeout(function() {

@@ -462,3 +497,3 @@ QUnit.ok( false, "Test timed out" );

QUnit.start();
}, config.testTimeout);
}, config.testTimeout );
}

@@ -468,17 +503,23 @@ }

//We want access to the constructor's prototype
// We want access to the constructor's prototype
(function() {
function F(){};
function F() {}
F.prototype = QUnit;
QUnit = new F();
//Make F QUnit's constructor so that we can add to the prototype later
// Make F QUnit's constructor so that we can add to the prototype later
QUnit.constructor = F;
})();
}());
// Backwards compatibility, deprecated
QUnit.equals = QUnit.equal;
QUnit.same = QUnit.deepEqual;
// deprecated; still export them to window to provide clear error messages
// next step: remove entirely
QUnit.equals = function() {
QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
};
QUnit.same = function() {
QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
};
// Maintain internal state
var config = {
// `config` initialized at top of scope
config = {
// The queue of tests to run

@@ -501,5 +542,5 @@ queue: [],

urlConfig: ['noglobals', 'notrycatch'],
urlConfig: [ "noglobals", "notrycatch" ],
//logging callback queues
// logging callback queues
begin: [],

@@ -516,3 +557,4 @@ done: [],

(function() {
var location = window.location || { search: "", protocol: "file:" },
var i,
location = window.location || { search: "", protocol: "file:" },
params = location.search.slice( 1 ).split( "&" ),

@@ -524,3 +566,3 @@ length = params.length,

if ( params[ 0 ] ) {
for ( var i = 0; i < length; i++ ) {
for ( i = 0; i < length; i++ ) {
current = params[ i ].split( "=" );

@@ -538,17 +580,14 @@ current[ 0 ] = decodeURIComponent( current[ 0 ] );

// Figure out if we're running the tests from a server or not
QUnit.isLocal = !!(location.protocol === 'file:');
})();
QUnit.isLocal = location.protocol === "file:";
}());
// Expose the API as global variables, unless an 'exports'
// object exists, in that case we assume we're in CommonJS
if ( typeof exports === "undefined" || typeof require === "undefined" ) {
extend(window, QUnit);
// Expose the API as global variables, unless an 'exports' object exists,
// in that case we assume we're in CommonJS - export everything at the end
if ( typeof exports === "undefined" ) {
extend( window, QUnit );
window.QUnit = QUnit;
} else {
extend(exports, QUnit);
exports.QUnit = QUnit;
}
// define these after exposing globals to keep them in these QUnit namespace only
extend(QUnit, {
extend( QUnit, {
config: config,

@@ -558,6 +597,6 @@

init: function() {
extend(config, {
extend( config, {
stats: { all: 0, bad: 0 },
moduleStats: { all: 0, bad: 0 },
started: +new Date,
started: +new Date(),
updateRate: 1000,

@@ -572,6 +611,18 @@ blocking: false,

var tests = id( "qunit-tests" ),
banner = id( "qunit-banner" ),
result = id( "qunit-testresult" );
var tests, banner, result,
qunit = id( "qunit" );
if ( qunit ) {
qunit.innerHTML =
"<h1 id='qunit-header'>" + escapeInnerText( document.title ) + "</h1>" +
"<h2 id='qunit-banner'></h2>" +
"<div id='qunit-testrunner-toolbar'></div>" +
"<h2 id='qunit-userAgent'></h2>" +
"<ol id='qunit-tests'></ol>";
}
tests = id( "qunit-tests" );
banner = id( "qunit-banner" );
result = id( "qunit-testresult" );
if ( tests ) {

@@ -594,18 +645,17 @@ tests.innerHTML = "";

tests.parentNode.insertBefore( result, tests );
result.innerHTML = 'Running...<br/>&nbsp;';
result.innerHTML = "Running...<br/>&nbsp;";
}
},
/**
* Resets the test setup. Useful for tests that modify the DOM.
*
* If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
*/
// Resets the test setup. Useful for tests that modify the DOM.
// If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
reset: function() {
var fixture;
if ( window.jQuery ) {
jQuery( "#qunit-fixture" ).html( config.fixture );
} else {
var main = id( 'qunit-fixture' );
if ( main ) {
main.innerHTML = config.fixture;
fixture = id( "qunit-fixture" );
if ( fixture ) {
fixture.innerHTML = config.fixture;
}

@@ -615,19 +665,13 @@ }

/**
* Trigger an event on an element.
*
* @example triggerEvent( document.body, "click" );
*
* @param DOMElement elem
* @param String type
*/
// Trigger an event on an element.
// @example triggerEvent( document.body, "click" );
triggerEvent: function( elem, type, event ) {
if ( document.createEvent ) {
event = document.createEvent("MouseEvents");
event = document.createEvent( "MouseEvents" );
event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
elem.dispatchEvent( event );
} else if ( elem.fireEvent ) {
elem.fireEvent("on"+type);
elem.fireEvent( "on" + type );
}

@@ -642,30 +686,28 @@ },

objectType: function( obj ) {
if (typeof obj === "undefined") {
if ( typeof obj === "undefined" ) {
return "undefined";
// consider: typeof null === object
}
if (obj === null) {
if ( obj === null ) {
return "null";
}
var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || '';
var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || "";
switch (type) {
case 'Number':
if (isNaN(obj)) {
return "nan";
} else {
return "number";
}
case 'String':
case 'Boolean':
case 'Array':
case 'Date':
case 'RegExp':
case 'Function':
return type.toLowerCase();
switch ( type ) {
case "Number":
if ( isNaN(obj) ) {
return "nan";
}
return "number";
case "String":
case "Boolean":
case "Array":
case "Date":
case "RegExp":
case "Function":
return type.toLowerCase();
}
if (typeof obj === "object") {
return "object";
if ( typeof obj === "object" ) {
return "object";
}

@@ -675,29 +717,40 @@ return undefined;

push: function(result, actual, expected, message) {
var details = {
result: result,
message: message,
actual: actual,
expected: expected
};
push: function( result, actual, expected, message ) {
if ( !config.current ) {
throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
}
message = escapeInnerText(message) || (result ? "okay" : "failed");
message = '<span class="test-message">' + message + "</span>";
expected = escapeInnerText(QUnit.jsDump.parse(expected));
actual = escapeInnerText(QUnit.jsDump.parse(actual));
var output = message + '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
if (actual != expected) {
output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) +'</pre></td></tr>';
}
if (!result) {
var source = sourceFromStacktrace();
if (source) {
var output, source,
details = {
result: result,
message: message,
actual: actual,
expected: expected
};
message = escapeInnerText( message ) || ( result ? "okay" : "failed" );
message = "<span class='test-message'>" + message + "</span>";
output = message;
if ( !result ) {
expected = escapeInnerText( QUnit.jsDump.parse(expected) );
actual = escapeInnerText( QUnit.jsDump.parse(actual) );
output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>";
if ( actual != expected ) {
output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>";
output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>";
}
source = sourceFromStacktrace();
if ( source ) {
details.source = source;
output += '<tr class="test-source"><th>Source: </th><td><pre>' + escapeInnerText(source) + '</pre></td></tr>';
output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>";
}
output += "</table>";
}
output += "</table>";
runLoggingCallbacks( 'log', QUnit, details );
runLoggingCallbacks( "log", QUnit, details );

@@ -710,6 +763,31 @@ config.current.assertions.push({

pushFailure: function( message, source ) {
var output,
details = {
result: false,
message: message
};
message = escapeInnerText(message ) || "error";
message = "<span class='test-message'>" + message + "</span>";
output = message;
if ( source ) {
details.source = source;
output += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>";
}
runLoggingCallbacks( "log", QUnit, details );
config.current.assertions.push({
result: false,
message: output
});
},
url: function( params ) {
params = extend( extend( {}, QUnit.urlParams ), params );
var querystring = "?",
key;
var key,
querystring = "?";
for ( key in params ) {

@@ -730,21 +808,21 @@ if ( !hasOwn.call( params, key ) ) {

//QUnit.constructor is set to the empty F() above so that we can add to it's prototype later
//Doing this allows us to tell if the following methods have been overwritten on the actual
//QUnit object, which is a deprecated way of using the callbacks.
extend(QUnit.constructor.prototype, {
// QUnit.constructor is set to the empty F() above so that we can add to it's prototype later
// Doing this allows us to tell if the following methods have been overwritten on the actual
// QUnit object, which is a deprecated way of using the callbacks.
extend( QUnit.constructor.prototype, {
// Logging callbacks; all receive a single argument with the listed properties
// run test/logs.html for any related changes
begin: registerLoggingCallback('begin'),
begin: registerLoggingCallback( "begin" ),
// done: { failed, passed, total, runtime }
done: registerLoggingCallback('done'),
done: registerLoggingCallback( "done" ),
// log: { result, actual, expected, message }
log: registerLoggingCallback('log'),
log: registerLoggingCallback( "log" ),
// testStart: { name }
testStart: registerLoggingCallback('testStart'),
testStart: registerLoggingCallback( "testStart" ),
// testDone: { name, failed, passed, total }
testDone: registerLoggingCallback('testDone'),
testDone: registerLoggingCallback( "testDone" ),
// moduleStart: { name }
moduleStart: registerLoggingCallback('moduleStart'),
moduleStart: registerLoggingCallback( "moduleStart" ),
// moduleDone: { name, failed, passed, total }
moduleDone: registerLoggingCallback('moduleDone')
moduleDone: registerLoggingCallback( "moduleDone" )
});

@@ -757,6 +835,9 @@

QUnit.load = function() {
runLoggingCallbacks( 'begin', QUnit, {} );
runLoggingCallbacks( "begin", QUnit, {} );
// Initialize the config, saving the execution queue
var oldconfig = extend({}, config);
var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
urlConfigHtml = "",
oldconfig = extend( {}, config );
QUnit.init();

@@ -767,15 +848,20 @@ extend(config, oldconfig);

var urlConfigHtml = '', len = config.urlConfig.length;
for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) {
len = config.urlConfig.length;
for ( i = 0; i < len; i++ ) {
val = config.urlConfig[i];
config[val] = QUnit.urlParams[val];
urlConfigHtml += '<label><input name="' + val + '" type="checkbox"' + ( config[val] ? ' checked="checked"' : '' ) + '>' + val + '</label>';
urlConfigHtml += "<label><input name='" + val + "' type='checkbox'" + ( config[val] ? " checked='checked'" : "" ) + ">" + val + "</label>";
}
var userAgent = id("qunit-userAgent");
// `userAgent` initialized at top of scope
userAgent = id( "qunit-userAgent" );
if ( userAgent ) {
userAgent.innerHTML = navigator.userAgent;
}
var banner = id("qunit-header");
// `banner` initialized at top of scope
banner = id( "qunit-header" );
if ( banner ) {
banner.innerHTML = '<a href="' + QUnit.url({ filter: undefined }) + '"> ' + banner.innerHTML + '</a> ' + urlConfigHtml;
banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined }) + "'>" + banner.innerHTML + "</a> " + urlConfigHtml;
addEvent( banner, "change", function( event ) {

@@ -788,26 +874,33 @@ var params = {};

var toolbar = id("qunit-testrunner-toolbar");
// `toolbar` initialized at top of scope
toolbar = id( "qunit-testrunner-toolbar" );
if ( toolbar ) {
var filter = document.createElement("input");
// `filter` initialized at top of scope
filter = document.createElement( "input" );
filter.type = "checkbox";
filter.id = "qunit-filter-pass";
addEvent( filter, "click", function() {
var ol = document.getElementById("qunit-tests");
var tmp,
ol = document.getElementById( "qunit-tests" );
if ( filter.checked ) {
ol.className = ol.className + " hidepass";
} else {
var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
ol.className = tmp.replace(/ hidepass /, " ");
tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
ol.className = tmp.replace( / hidepass /, " " );
}
if ( defined.sessionStorage ) {
if (filter.checked) {
sessionStorage.setItem("qunit-filter-passed-tests", "true");
sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
} else {
sessionStorage.removeItem("qunit-filter-passed-tests");
sessionStorage.removeItem( "qunit-filter-passed-tests" );
}
}
});
if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) {
if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
filter.checked = true;
var ol = document.getElementById("qunit-tests");
// `ol` initialized at top of scope
ol = document.getElementById( "qunit-tests" );
ol.className = ol.className + " hidepass";

@@ -817,4 +910,5 @@ }

var label = document.createElement("label");
label.setAttribute("for", "qunit-filter-pass");
// `label` initialized at top of scope
label = document.createElement( "label" );
label.setAttribute( "for", "qunit-filter-pass" );
label.innerHTML = "Hide passed tests";

@@ -824,3 +918,4 @@ toolbar.appendChild( label );

var main = id('qunit-fixture');
// `main` initialized at top of scope
main = id( "qunit-fixture" );
if ( main ) {

@@ -830,3 +925,3 @@ config.fixture = main.innerHTML;

if (config.autostart) {
if ( config.autostart ) {
QUnit.start();

@@ -836,11 +931,11 @@ }

addEvent(window, "load", QUnit.load);
addEvent( window, "load", QUnit.load );
// addEvent(window, "error") gives us a useless event object
// addEvent(window, "error" ) gives us a useless event object
window.onerror = function( message, file, line ) {
if ( QUnit.config.current ) {
ok( false, message + ", " + file + ":" + line );
QUnit.pushFailure( message, file + ":" + line );
} else {
test( "global failure", function() {
ok( false, message + ", " + file + ":" + line );
QUnit.test( "global failure", function() {
QUnit.pushFailure( message, file + ":" + line );
});

@@ -855,3 +950,3 @@ }

if ( config.currentModule ) {
runLoggingCallbacks( 'moduleDone', QUnit, {
runLoggingCallbacks( "moduleDone", QUnit, {
name: config.currentModule,

@@ -861,24 +956,25 @@ failed: config.moduleStats.bad,

total: config.moduleStats.all
} );
});
}
var banner = id("qunit-banner"),
tests = id("qunit-tests"),
runtime = +new Date - config.started,
var i, key,
banner = id( "qunit-banner" ),
tests = id( "qunit-tests" ),
runtime = +new Date() - config.started,
passed = config.stats.all - config.stats.bad,
html = [
'Tests completed in ',
"Tests completed in ",
runtime,
' milliseconds.<br/>',
'<span class="passed">',
" milliseconds.<br/>",
"<span class='passed'>",
passed,
'</span> tests of <span class="total">',
"</span> tests of <span class='total'>",
config.stats.all,
'</span> passed, <span class="failed">',
"</span> passed, <span class='failed'>",
config.stats.bad,
'</span> failed.'
].join('');
"</span> failed."
].join( "" );
if ( banner ) {
banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
}

@@ -894,8 +990,19 @@

document.title = [
(config.stats.bad ? "\u2716" : "\u2714"),
document.title.replace(/^[\u2714\u2716] /i, "")
].join(" ");
( config.stats.bad ? "\u2716" : "\u2714" ),
document.title.replace( /^[\u2714\u2716] /i, "" )
].join( " " );
}
runLoggingCallbacks( 'done', QUnit, {
// clear own sessionStorage items if all tests passed
if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
// `key` & `i` initialized at top of scope
for ( i = 0; i < sessionStorage.length; i++ ) {
key = sessionStorage.key( i++ );
if ( key.indexOf( "qunit-test-" ) === 0 ) {
sessionStorage.removeItem( key );
}
}
}
runLoggingCallbacks( "done", QUnit, {
failed: config.stats.bad,

@@ -905,7 +1012,8 @@ passed: passed,

runtime: runtime
} );
});
}
function validTest( name ) {
var filter = config.filter,
var not,
filter = config.filter,
run = false;

@@ -917,3 +1025,4 @@

var not = filter.charAt( 0 ) === "!";
not = filter.charAt( 0 ) === "!";
if ( not ) {

@@ -934,29 +1043,46 @@ filter = filter.slice( 1 );

// so far supports only Firefox, Chrome and Opera (buggy)
// could be extended in the future to use something like https://github.com/csnover/TraceKit
function sourceFromStacktrace() {
// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
// Later Safari and IE10 are supposed to support error.stack as well
// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
function extractStacktrace( e, offset ) {
offset = offset || 3;
var stack;
if ( e.stacktrace ) {
// Opera
return e.stacktrace.split( "\n" )[ offset + 3 ];
} else if ( e.stack ) {
// Firefox, Chrome
stack = e.stack.split( "\n" );
if (/^error$/i.test( stack[0] ) ) {
stack.shift();
}
return stack[ offset ];
} else if ( e.sourceURL ) {
// Safari, PhantomJS
// hopefully one day Safari provides actual stacktraces
// exclude useless self-reference for generated Error objects
if ( /qunit.js$/.test( e.sourceURL ) ) {
return;
}
// for actual exceptions, this is useful
return e.sourceURL + ":" + e.line;
}
}
function sourceFromStacktrace( offset ) {
try {
throw new Error();
} catch ( e ) {
if (e.stacktrace) {
// Opera
return e.stacktrace.split("\n")[6];
} else if (e.stack) {
// Firefox, Chrome
return e.stack.split("\n")[4];
} else if (e.sourceURL) {
// Safari, PhantomJS
// TODO sourceURL points at the 'throw new Error' line above, useless
//return e.sourceURL + ":" + e.line;
}
return extractStacktrace( e, offset );
}
}
function escapeInnerText(s) {
if (!s) {
function escapeInnerText( s ) {
if ( !s ) {
return "";
}
s = s + "";
return s.replace(/[\&<>]/g, function(s) {
switch(s) {
return s.replace( /[\&<>]/g, function( s ) {
switch( s ) {
case "&": return "&amp;";

@@ -974,3 +1100,3 @@ case "<": return "&lt;";

if ( config.autorun && !config.blocking ) {
process(last);
process( last );
}

@@ -980,2 +1106,5 @@ }

function process( last ) {
function next() {
process( last );
}
var start = new Date().getTime();

@@ -988,5 +1117,3 @@ config.depth = config.depth ? config.depth + 1 : 1;

} else {
window.setTimeout( function(){
process( last );
}, 13 );
window.setTimeout( next, 13 );
break;

@@ -1006,3 +1133,4 @@ }

for ( var key in window ) {
if ( !hasOwn.call( window, key ) ) {
// in Opera sometimes DOM element ids show up here, ignore them
if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) {
continue;

@@ -1016,13 +1144,16 @@ }

function checkPollution( name ) {
var old = config.pollution;
var newGlobals,
deletedGlobals,
old = config.pollution;
saveGlobal();
var newGlobals = diff( config.pollution, old );
newGlobals = diff( config.pollution, old );
if ( newGlobals.length > 0 ) {
ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
}
var deletedGlobals = diff( old, config.pollution );
deletedGlobals = diff( old, config.pollution );
if ( deletedGlobals.length > 0 ) {
ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
}

@@ -1033,7 +1164,9 @@ }

function diff( a, b ) {
var result = a.slice();
for ( var i = 0; i < result.length; i++ ) {
for ( var j = 0; j < b.length; j++ ) {
var i, j,
result = a.slice();
for ( i = 0; i < result.length; i++ ) {
for ( j = 0; j < b.length; j++ ) {
if ( result[i] === b[j] ) {
result.splice(i, 1);
result.splice( i, 1 );
i--;

@@ -1047,21 +1180,10 @@ break;

function fail(message, exception, callback) {
if ( typeof console !== "undefined" && console.error && console.warn ) {
console.error(message);
console.error(exception);
console.warn(callback.toString());
} else if ( window.opera && opera.postError ) {
opera.postError(message, exception, callback.toString);
}
}
function extend(a, b) {
function extend( a, b ) {
for ( var prop in b ) {
if ( b[prop] === undefined ) {
delete a[prop];
if ( b[ prop ] === undefined ) {
delete a[ prop ];
// Avoid "Member not found" error in IE8 caused by setting window.constructor
} else if ( prop !== "constructor" || a !== window ) {
a[prop] = b[prop];
a[ prop ] = b[ prop ];
}

@@ -1073,3 +1195,3 @@ }

function addEvent(elem, type, fn) {
function addEvent( elem, type, fn ) {
if ( elem.addEventListener ) {

@@ -1084,9 +1206,9 @@ elem.addEventListener( type, fn, false );

function id(name) {
return !!(typeof document !== "undefined" && document && document.getElementById) &&
function id( name ) {
return !!( typeof document !== "undefined" && document && document.getElementById ) &&
document.getElementById( name );
}
function registerLoggingCallback(key){
return function(callback){
function registerLoggingCallback( key ) {
return function( callback ) {
config[key].push( callback );

@@ -1097,11 +1219,11 @@ };

// Supports deprecated method of completely overwriting logging callbacks
function runLoggingCallbacks(key, scope, args) {
function runLoggingCallbacks( key, scope, args ) {
//debugger;
var callbacks;
if ( QUnit.hasOwnProperty(key) ) {
QUnit[key].call(scope, args);
var i, callbacks;
if ( QUnit.hasOwnProperty( key ) ) {
QUnit[ key ].call(scope, args );
} else {
callbacks = config[key];
for( var i = 0; i < callbacks.length; i++ ) {
callbacks[i].call( scope, args );
callbacks = config[ key ];
for ( i = 0; i < callbacks.length; i++ ) {
callbacks[ i ].call( scope, args );
}

@@ -1113,16 +1235,12 @@ }

// Author: Philippe Rathé <prathe@gmail.com>
QUnit.equiv = function () {
QUnit.equiv = (function() {
var innerEquiv; // the real equiv function
var callers = []; // stack to decide between skip/abort functions
var parents = []; // stack to avoiding loops from circular referencing
// Call the o related callback with the given arguments.
function bindCallbacks(o, callbacks, args) {
var prop = QUnit.objectType(o);
if (prop) {
if (QUnit.objectType(callbacks[prop]) === "function") {
return callbacks[prop].apply(callbacks, args);
function bindCallbacks( o, callbacks, args ) {
var prop = QUnit.objectType( o );
if ( prop ) {
if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
return callbacks[ prop ].apply( callbacks, args );
} else {
return callbacks[prop]; // or undefined
return callbacks[ prop ]; // or undefined
}

@@ -1132,152 +1250,158 @@ }

var getProto = Object.getPrototypeOf || function (obj) {
return obj.__proto__;
};
// the real equiv function
var innerEquiv,
// stack to decide between skip/abort functions
callers = [],
// stack to avoiding loops from circular referencing
parents = [],
var callbacks = function () {
getProto = Object.getPrototypeOf || function ( obj ) {
return obj.__proto__;
},
callbacks = (function () {
// for string, boolean, number and null
function useStrictEquality(b, a) {
if (b instanceof a.constructor || a instanceof b.constructor) {
// to catch short annotaion VS 'new' annotation of a
// declaration
// e.g. var i = 1;
// var j = new Number(1);
return a == b;
} else {
return a === b;
// for string, boolean, number and null
function useStrictEquality( b, a ) {
if ( b instanceof a.constructor || a instanceof b.constructor ) {
// to catch short annotaion VS 'new' annotation of a
// declaration
// e.g. var i = 1;
// var j = new Number(1);
return a == b;
} else {
return a === b;
}
}
}
return {
"string" : useStrictEquality,
"boolean" : useStrictEquality,
"number" : useStrictEquality,
"null" : useStrictEquality,
"undefined" : useStrictEquality,
return {
"string": useStrictEquality,
"boolean": useStrictEquality,
"number": useStrictEquality,
"null": useStrictEquality,
"undefined": useStrictEquality,
"nan" : function(b) {
return isNaN(b);
},
"nan": function( b ) {
return isNaN( b );
},
"date" : function(b, a) {
return QUnit.objectType(b) === "date"
&& a.valueOf() === b.valueOf();
},
"date": function( b, a ) {
return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
},
"regexp" : function(b, a) {
return QUnit.objectType(b) === "regexp"
&& a.source === b.source && // the regex itself
a.global === b.global && // and its modifers
// (gmi) ...
a.ignoreCase === b.ignoreCase
&& a.multiline === b.multiline;
},
"regexp": function( b, a ) {
return QUnit.objectType( b ) === "regexp" &&
// the regex itself
a.source === b.source &&
// and its modifers
a.global === b.global &&
// (gmi) ...
a.ignoreCase === b.ignoreCase &&
a.multiline === b.multiline;
},
// - skip when the property is a method of an instance (OOP)
// - abort otherwise,
// initial === would have catch identical references anyway
"function" : function() {
var caller = callers[callers.length - 1];
return caller !== Object && typeof caller !== "undefined";
},
// - skip when the property is a method of an instance (OOP)
// - abort otherwise,
// initial === would have catch identical references anyway
"function": function() {
var caller = callers[callers.length - 1];
return caller !== Object && typeof caller !== "undefined";
},
"array" : function(b, a) {
var i, j, loop;
var len;
"array": function( b, a ) {
var i, j, len, loop;
// b could be an object literal here
if (!(QUnit.objectType(b) === "array")) {
return false;
}
// b could be an object literal here
if ( QUnit.objectType( b ) !== "array" ) {
return false;
}
len = a.length;
if (len !== b.length) { // safe and faster
return false;
}
len = a.length;
if ( len !== b.length ) {
// safe and faster
return false;
}
// track reference to avoid circular references
parents.push(a);
for (i = 0; i < len; i++) {
loop = false;
for (j = 0; j < parents.length; j++) {
if (parents[j] === a[i]) {
loop = true;// dont rewalk array
// track reference to avoid circular references
parents.push( a );
for ( i = 0; i < len; i++ ) {
loop = false;
for ( j = 0; j < parents.length; j++ ) {
if ( parents[j] === a[i] ) {
loop = true;// dont rewalk array
}
}
if ( !loop && !innerEquiv(a[i], b[i]) ) {
parents.pop();
return false;
}
}
if (!loop && !innerEquiv(a[i], b[i])) {
parents.pop();
return false;
}
}
parents.pop();
return true;
},
parents.pop();
return true;
},
"object" : function(b, a) {
var i, j, loop;
var eq = true; // unless we can proove it
var aProperties = [], bProperties = []; // collection of
// strings
"object": function( b, a ) {
var i, j, loop,
// Default to true
eq = true,
aProperties = [],
bProperties = [];
// comparing constructors is more strict than using
// instanceof
if (a.constructor !== b.constructor) {
// Allow objects with no prototype to be equivalent to
// objects with Object as their constructor.
if (!((getProto(a) === null && getProto(b) === Object.prototype) ||
(getProto(b) === null && getProto(a) === Object.prototype)))
{
return false;
// comparing constructors is more strict than using
// instanceof
if ( a.constructor !== b.constructor ) {
// Allow objects with no prototype to be equivalent to
// objects with Object as their constructor.
if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
return false;
}
}
}
// stack constructor before traversing properties
callers.push(a.constructor);
// track reference to avoid circular references
parents.push(a);
// stack constructor before traversing properties
callers.push( a.constructor );
// track reference to avoid circular references
parents.push( a );
for (i in a) { // be strict: don't ensures hasOwnProperty
// and go deep
loop = false;
for (j = 0; j < parents.length; j++) {
if (parents[j] === a[i])
loop = true; // don't go down the same path
// twice
for ( i in a ) { // be strict: don't ensures hasOwnProperty
// and go deep
loop = false;
for ( j = 0; j < parents.length; j++ ) {
if ( parents[j] === a[i] ) {
// don't go down the same path twice
loop = true;
}
}
aProperties.push(i); // collect a's properties
if (!loop && !innerEquiv( a[i], b[i] ) ) {
eq = false;
break;
}
}
aProperties.push(i); // collect a's properties
if (!loop && !innerEquiv(a[i], b[i])) {
eq = false;
break;
callers.pop(); // unstack, we are done
parents.pop();
for ( i in b ) {
bProperties.push( i ); // collect b's properties
}
}
callers.pop(); // unstack, we are done
parents.pop();
for (i in b) {
bProperties.push(i); // collect b's properties
// Ensures identical properties name
return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
}
};
}());
// Ensures identical properties name
return eq
&& innerEquiv(aProperties.sort(), bProperties
.sort());
}
};
}();
innerEquiv = function() { // can take multiple arguments
var args = Array.prototype.slice.apply(arguments);
if (args.length < 2) {
var args = [].slice.apply( arguments );
if ( args.length < 2 ) {
return true; // end transition
}
return (function(a, b) {
if (a === b) {
return (function( a, b ) {
if ( a === b ) {
return true; // catch the most you can
} else if (a === null || b === null || typeof a === "undefined"
|| typeof b === "undefined"
|| QUnit.objectType(a) !== QUnit.objectType(b)) {
} else if ( a === null || b === null || typeof a === "undefined" ||
typeof b === "undefined" ||
QUnit.objectType(a) !== QUnit.objectType(b) ) {
return false; // don't lose time with error prone cases

@@ -1289,11 +1413,8 @@ } else {

// apply transition with (1..n) arguments
})(args[0], args[1])
&& arguments.callee.apply(this, args.splice(1,
args.length - 1));
}( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) );
};
return innerEquiv;
}());
}();
/**

@@ -1311,7 +1432,7 @@ * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |

function quote( str ) {
return '"' + str.toString().replace(/"/g, '\\"') + '"';
};
return '"' + str.toString().replace( /"/g, '\\"' ) + '"';
}
function literal( o ) {
return o + '';
};
return o + "";
}
function join( pre, arr, post ) {

@@ -1321,175 +1442,202 @@ var s = jsDump.separator(),

inner = jsDump.indent(1);
if ( arr.join )
arr = arr.join( ',' + s + inner );
if ( !arr )
if ( arr.join ) {
arr = arr.join( "," + s + inner );
}
if ( !arr ) {
return pre + post;
}
return [ pre, inner + arr, base + post ].join(s);
};
}
function array( arr, stack ) {
var i = arr.length, ret = Array(i);
var i = arr.length, ret = new Array(i);
this.up();
while ( i-- )
while ( i-- ) {
ret[i] = this.parse( arr[i] , undefined , stack);
}
this.down();
return join( '[', ret, ']' );
};
return join( "[", ret, "]" );
}
var reName = /^function (\w+)/;
var reName = /^function (\w+)/,
jsDump = {
parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance
stack = stack || [ ];
var inStack, res,
parser = this.parsers[ type || this.typeOf(obj) ];
var jsDump = {
parse:function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance
stack = stack || [ ];
var parser = this.parsers[ type || this.typeOf(obj) ];
type = typeof parser;
var inStack = inArray(obj, stack);
if (inStack != -1) {
return 'recursion('+(inStack - stack.length)+')';
}
//else
if (type == 'function') {
stack.push(obj);
var res = parser.call( this, obj, stack );
type = typeof parser;
inStack = inArray( obj, stack );
if ( inStack != -1 ) {
return "recursion(" + (inStack - stack.length) + ")";
}
//else
if ( type == "function" ) {
stack.push( obj );
res = parser.call( this, obj, stack );
stack.pop();
return res;
}
// else
return (type == 'string') ? parser : this.parsers.error;
},
typeOf:function( obj ) {
var type;
if ( obj === null ) {
type = "null";
} else if (typeof obj === "undefined") {
type = "undefined";
} else if (QUnit.is("RegExp", obj)) {
type = "regexp";
} else if (QUnit.is("Date", obj)) {
type = "date";
} else if (QUnit.is("Function", obj)) {
type = "function";
} else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") {
type = "window";
} else if (obj.nodeType === 9) {
type = "document";
} else if (obj.nodeType) {
type = "node";
} else if (
// native arrays
toString.call( obj ) === "[object Array]" ||
// NodeList objects
( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
) {
type = "array";
} else {
type = typeof obj;
}
return type;
},
separator:function() {
return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
},
indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
if ( !this.multiline )
return '';
var chr = this.indentChar;
if ( this.HTML )
chr = chr.replace(/\t/g,' ').replace(/ /g,'&nbsp;');
return Array( this._depth_ + (extra||0) ).join(chr);
},
up:function( a ) {
this._depth_ += a || 1;
},
down:function( a ) {
this._depth_ -= a || 1;
},
setParser:function( name, parser ) {
this.parsers[name] = parser;
},
// The next 3 are exposed so you can use them
quote:quote,
literal:literal,
join:join,
//
_depth_: 1,
// This is the list of parsers, to modify them, use jsDump.setParser
parsers:{
window: '[Window]',
document: '[Document]',
error:'[ERROR]', //when no parser is found, shouldn't happen
unknown: '[Unknown]',
'null':'null',
'undefined':'undefined',
'function':function( fn ) {
var ret = 'function',
name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
if ( name )
ret += ' ' + name;
ret += '(';
ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join('');
return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' );
}
// else
return ( type == "string" ) ? parser : this.parsers.error;
},
array: array,
nodelist: array,
arguments: array,
object:function( map, stack ) {
var ret = [ ];
QUnit.jsDump.up();
for ( var key in map ) {
var val = map[key];
ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(val, undefined, stack));
}
QUnit.jsDump.down();
return join( '{', ret, '}' );
typeOf: function( obj ) {
var type;
if ( obj === null ) {
type = "null";
} else if ( typeof obj === "undefined" ) {
type = "undefined";
} else if ( QUnit.is( "RegExp", obj) ) {
type = "regexp";
} else if ( QUnit.is( "Date", obj) ) {
type = "date";
} else if ( QUnit.is( "Function", obj) ) {
type = "function";
} else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
type = "window";
} else if ( obj.nodeType === 9 ) {
type = "document";
} else if ( obj.nodeType ) {
type = "node";
} else if (
// native arrays
toString.call( obj ) === "[object Array]" ||
// NodeList objects
( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
) {
type = "array";
} else {
type = typeof obj;
}
return type;
},
node:function( node ) {
var open = QUnit.jsDump.HTML ? '&lt;' : '<',
close = QUnit.jsDump.HTML ? '&gt;' : '>';
var tag = node.nodeName.toLowerCase(),
ret = open + tag;
for ( var a in QUnit.jsDump.DOMAttrs ) {
var val = node[QUnit.jsDump.DOMAttrs[a]];
if ( val )
ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' );
separator: function() {
return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? "&nbsp;" : " ";
},
indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
if ( !this.multiline ) {
return "";
}
return ret + close + open + '/' + tag + close;
var chr = this.indentChar;
if ( this.HTML ) {
chr = chr.replace( /\t/g, " " ).replace( / /g, "&nbsp;" );
}
return new Array( this._depth_ + (extra||0) ).join(chr);
},
functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
var l = fn.length;
if ( !l ) return '';
up: function( a ) {
this._depth_ += a || 1;
},
down: function( a ) {
this._depth_ -= a || 1;
},
setParser: function( name, parser ) {
this.parsers[name] = parser;
},
// The next 3 are exposed so you can use them
quote: quote,
literal: literal,
join: join,
//
_depth_: 1,
// This is the list of parsers, to modify them, use jsDump.setParser
parsers: {
window: "[Window]",
document: "[Document]",
error: "[ERROR]", //when no parser is found, shouldn"t happen
unknown: "[Unknown]",
"null": "null",
"undefined": "undefined",
"function": function( fn ) {
var ret = "function",
name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];//functions never have name in IE
var args = Array(l);
while ( l-- )
args[l] = String.fromCharCode(97+l);//97 is 'a'
return ' ' + args.join(', ') + ' ';
if ( name ) {
ret += " " + name;
}
ret += "( ";
ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
},
array: array,
nodelist: array,
"arguments": array,
object: function( map, stack ) {
var ret = [ ], keys, key, val, i;
QUnit.jsDump.up();
if ( Object.keys ) {
keys = Object.keys( map );
} else {
keys = [];
for ( key in map ) {
keys.push( key );
}
}
keys.sort();
for ( i = 0; i < keys.length; i++ ) {
key = keys[ i ];
val = map[ key ];
ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
}
QUnit.jsDump.down();
return join( "{", ret, "}" );
},
node: function( node ) {
var a, val,
open = QUnit.jsDump.HTML ? "&lt;" : "<",
close = QUnit.jsDump.HTML ? "&gt;" : ">",
tag = node.nodeName.toLowerCase(),
ret = open + tag;
for ( a in QUnit.jsDump.DOMAttrs ) {
val = node[ QUnit.jsDump.DOMAttrs[a] ];
if ( val ) {
ret += " " + a + "=" + QUnit.jsDump.parse( val, "attribute" );
}
}
return ret + close + open + "/" + tag + close;
},
functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function
var args,
l = fn.length;
if ( !l ) {
return "";
}
args = new Array(l);
while ( l-- ) {
args[l] = String.fromCharCode(97+l);//97 is 'a'
}
return " " + args.join( ", " ) + " ";
},
key: quote, //object calls it internally, the key part of an item in a map
functionCode: "[code]", //function calls it internally, it's the content of the function
attribute: quote, //node calls it internally, it's an html attribute value
string: quote,
date: quote,
regexp: literal, //regex
number: literal,
"boolean": literal
},
key:quote, //object calls it internally, the key part of an item in a map
functionCode:'[code]', //function calls it internally, it's the content of the function
attribute:quote, //node calls it internally, it's an html attribute value
string:quote,
date:quote,
regexp:literal, //regex
number:literal,
'boolean':literal
},
DOMAttrs:{//attributes to dump from nodes, name=>realName
id:'id',
name:'name',
'class':'className'
},
HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
indentChar:' ',//indentation unit
multiline:true //if true, items in a collection, are separated by a \n, else just a space.
};
DOMAttrs: {
//attributes to dump from nodes, name=>realName
id: "id",
name: "name",
"class": "className"
},
HTML: false,//if true, entities are escaped ( <, >, \t, space and \n )
indentChar: " ",//indentation unit
multiline: true //if true, items in a collection, are separated by a \n, else just a space.
};
return jsDump;
})();
}());
// from Sizzle.js
function getText( elems ) {
var ret = "", elem;
var i, elem,
ret = "";
for ( var i = 0; elems[i]; i++ ) {
for ( i = 0; elems[i]; i++ ) {
elem = elems[i];

@@ -1508,5 +1656,5 @@

return ret;
};
}
//from jquery.js
// from jquery.js
function inArray( elem, array ) {

@@ -1538,38 +1686,41 @@ if ( array.indexOf ) {

*
* QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
* QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
*/
QUnit.diff = (function() {
function diff(o, n) {
var ns = {};
var os = {};
function diff( o, n ) {
var i,
ns = {},
os = {};
for (var i = 0; i < n.length; i++) {
if (ns[n[i]] == null)
ns[n[i]] = {
for ( i = 0; i < n.length; i++ ) {
if ( ns[ n[i] ] == null ) {
ns[ n[i] ] = {
rows: [],
o: null
};
ns[n[i]].rows.push(i);
}
ns[ n[i] ].rows.push( i );
}
for (var i = 0; i < o.length; i++) {
if (os[o[i]] == null)
os[o[i]] = {
for ( i = 0; i < o.length; i++ ) {
if ( os[ o[i] ] == null ) {
os[ o[i] ] = {
rows: [],
n: null
};
os[o[i]].rows.push(i);
}
os[ o[i] ].rows.push( i );
}
for (var i in ns) {
for ( i in ns ) {
if ( !hasOwn.call( ns, i ) ) {
continue;
}
if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
n[ns[i].rows[0]] = {
text: n[ns[i].rows[0]],
if ( ns[i].rows.length == 1 && typeof os[i] != "undefined" && os[i].rows.length == 1 ) {
n[ ns[i].rows[0] ] = {
text: n[ ns[i].rows[0] ],
row: os[i].rows[0]
};
o[os[i].rows[0]] = {
text: o[os[i].rows[0]],
o[ os[i].rows[0] ] = {
text: o[ os[i].rows[0] ],
row: ns[i].rows[0]

@@ -1580,11 +1731,12 @@ };

for (var i = 0; i < n.length - 1; i++) {
if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
n[i + 1] == o[n[i].row + 1]) {
n[i + 1] = {
text: n[i + 1],
for ( i = 0; i < n.length - 1; i++ ) {
if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
n[ i + 1 ] == o[ n[i].row + 1 ] ) {
n[ i + 1 ] = {
text: n[ i + 1 ],
row: n[i].row + 1
};
o[n[i].row + 1] = {
text: o[n[i].row + 1],
o[ n[i].row + 1 ] = {
text: o[ n[i].row + 1 ],
row: i + 1

@@ -1595,11 +1747,12 @@ };

for (var i = n.length - 1; i > 0; i--) {
if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
n[i - 1] == o[n[i].row - 1]) {
n[i - 1] = {
text: n[i - 1],
for ( i = n.length - 1; i > 0; i-- ) {
if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
n[ i - 1 ] == o[ n[i].row - 1 ]) {
n[ i - 1 ] = {
text: n[ i - 1 ],
row: n[i].row - 1
};
o[n[i].row - 1] = {
text: o[n[i].row - 1],
o[ n[i].row - 1 ] = {
text: o[ n[i].row - 1 ],
row: i - 1

@@ -1616,45 +1769,48 @@ };

return function(o, n) {
o = o.replace(/\s+$/, '');
n = n.replace(/\s+$/, '');
var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
return function( o, n ) {
o = o.replace( /\s+$/, "" );
n = n.replace( /\s+$/, "" );
var str = "";
var i, pre,
str = "",
out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
oSpace = o.match(/\s+/g),
nSpace = n.match(/\s+/g);
var oSpace = o.match(/\s+/g);
if (oSpace == null) {
oSpace = [" "];
if ( oSpace == null ) {
oSpace = [ " " ];
}
else {
oSpace.push(" ");
oSpace.push( " " );
}
var nSpace = n.match(/\s+/g);
if (nSpace == null) {
nSpace = [" "];
if ( nSpace == null ) {
nSpace = [ " " ];
}
else {
nSpace.push(" ");
nSpace.push( " " );
}
if (out.n.length == 0) {
for (var i = 0; i < out.o.length; i++) {
str += '<del>' + out.o[i] + oSpace[i] + "</del>";
if ( out.n.length === 0 ) {
for ( i = 0; i < out.o.length; i++ ) {
str += "<del>" + out.o[i] + oSpace[i] + "</del>";
}
}
else {
if (out.n[0].text == null) {
for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
str += '<del>' + out.o[n] + oSpace[n] + "</del>";
if ( out.n[0].text == null ) {
for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
str += "<del>" + out.o[n] + oSpace[n] + "</del>";
}
}
for (var i = 0; i < out.n.length; i++) {
for ( i = 0; i < out.n.length; i++ ) {
if (out.n[i].text == null) {
str += '<ins>' + out.n[i] + nSpace[i] + "</ins>";
str += "<ins>" + out.n[i] + nSpace[i] + "</ins>";
}
else {
var pre = "";
// `pre` initialized at top of scope
pre = "";
for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {
pre += '<del>' + out.o[n] + oSpace[n] + "</del>";
for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
pre += "<del>" + out.o[n] + oSpace[n] + "</del>";
}

@@ -1668,4 +1824,10 @@ str += " " + out.n[i].text + nSpace[i] + pre;

};
})();
}());
})(this);
// for CommonJS enviroments, export everything
if ( typeof exports !== "undefined" ) {
extend(exports, QUnit);
}
// get at whatever the global object is, like window in browsers
}( (function() {return this;}.call()) ));

@@ -19,4 +19,4 @@ [QUnit](http://docs.jquery.com/QUnit) - A JavaScript Unit Testing framework.

QUnit is similar to other unit testing frameworks like JUnit, but makes use of
the features JavaScript provides and helps with testing code in the browser, eg.
with it's stop/start facilities for testing asynchronous code.
the features JavaScript provides and helps with testing code in the browser, e.g.
with its stop/start facilities for testing asynchronous code.

@@ -30,2 +30,13 @@ If you are interested in helping developing QUnit, you are in the right place.

Development
-----------
To submit patches, fork the repository, create a branch for the change. Then implement
the change, run `grunt` to lint and test it, then commit, push and create a pull request.
Include some background for the change in the commit message and `Fixes #nnn`, referring
to the issue number you're addressing.
To run `grunt`, you need `node` and `npm`, then `npm install grunt -g`.
Releases

@@ -32,0 +43,0 @@ --------

@@ -154,1 +154,28 @@ // TODO disable reordering for this suite!

});
var testAutorun = true;
QUnit.done(function() {
if (!testAutorun) {
return;
}
testAutorun = false;
module("autorun");
test("reset", 0, function() {});
moduleStart = moduleDone = 0;
test("first", function(){
equal(moduleStart, 1, "test started");
equal(moduleDone, 0, "test in progress");
});
test("second", function(){
equal(moduleStart, 2, "test started");
equal(moduleDone, 1, "test in progress");
});
});

@@ -27,3 +27,2 @@ test("module without setup/teardown (default)", function() {

test("module with setup, expect in test call", 2, function() {

@@ -39,5 +38,9 @@ ok(true);

ok(true);
x = 1;
},
teardown: function() {
ok(true);
// can introduce and delete globals in setup/teardown
// without noglobals sounding the alarm
delete x;
}

@@ -165,12 +168,12 @@ });

test("test synchronous calls to stop", 2, function() {
stop();
setTimeout(function(){
ok(true, 'first');
start();
stop();
setTimeout(function(){
ok(true, 'second');
start();
}, 150);
}, 150);
stop();
setTimeout(function(){
ok(true, 'first');
start();
stop();
setTimeout(function(){
ok(true, 'second');
start();
}, 150);
}, 150);
});

@@ -200,2 +203,3 @@ }

test("modify testEnvironment",function() {
expect(0);
this.foo="hamster";

@@ -217,2 +221,3 @@ });

test("modify testEnvironment",function() {
expect(0);
// since we do a shallow copy, the testEnvironment can be modified

@@ -245,9 +250,4 @@ this.options.ingredients.push("carrots");

test("makeurl working with settings from testEnvironment", function() {
equal( makeurl(), 'http://google.com/?q=another_search_test', 'rather than passing arguments, we use test metadata to form the url');
equal( makeurl(), 'http://google.com/?q=another_search_test', 'rather than passing arguments, we use test metadata to from the url');
});
test("each test can extend the module testEnvironment", {
q:'hamstersoup'
}, function() {
equal( makeurl(), 'http://google.com/?q=hamstersoup', 'url from module, q from test');
});

@@ -257,3 +257,3 @@ module("jsDump");

equal( QUnit.jsDump.parse([1, 2]), "[\n 1,\n 2\n]" );
equal( QUnit.jsDump.parse({top: 5, left: 0}), "{\n \"top\": 5,\n \"left\": 0\n}" );
equal( QUnit.jsDump.parse({top: 5, left: 0}), "{\n \"left\": 0,\n \"top\": 5\n}" );
if (typeof document !== 'undefined' && document.getElementById("qunit-header")) {

@@ -316,2 +316,12 @@ equal( QUnit.jsDump.parse(document.getElementById("qunit-header")), "<h1 id=\"qunit-header\"></h1>" );

this.CustomError = CustomError;
raises(
function() {
throw new this.CustomError("some error description");
},
/description/,
"raised error with 'this' context"
);
});

@@ -323,2 +333,3 @@

test("setup", function() {
expect(0);
document.getElementById("qunit-fixture").innerHTML = "foobar";

@@ -330,2 +341,11 @@ });

test("running test name displayed", function() {
expect(2);
var displaying = document.getElementById("qunit-testresult");
ok( /running test name displayed/.test(displaying.innerHTML), "Expect test name to be found in displayed text" );
ok( /fixture/.test(displaying.innerHTML), "Expect module name to be found in displayed text" );
});
}

@@ -342,3 +362,3 @@

mod2(3, 1, "3 % 2 == 1");
})
});
})();

@@ -350,53 +370,53 @@

function Wrap(x) {
this.wrap = x;
if (x == undefined) this.first = true;
this.wrap = x;
if (x == undefined) this.first = true;
}
function chainwrap(depth, first, prev) {
depth = depth || 0;
var last = prev || new Wrap();
first = first || last;
depth = depth || 0;
var last = prev || new Wrap();
first = first || last;
if (depth == 1) {
first.wrap = last;
}
if (depth > 1) {
last = chainwrap(depth-1, first, new Wrap(last));
}
if (depth == 1) {
first.wrap = last;
}
if (depth > 1) {
last = chainwrap(depth-1, first, new Wrap(last));
}
return last;
return last;
}
test("check jsDump recursion", function() {
expect(4);
expect(4);
var noref = chainwrap(0);
var nodump = QUnit.jsDump.parse(noref);
equal(nodump, '{\n "wrap": undefined,\n "first": true\n}');
var noref = chainwrap(0);
var nodump = QUnit.jsDump.parse(noref);
equal(nodump, '{\n "first": true,\n "wrap": undefined\n}');
var selfref = chainwrap(1);
var selfdump = QUnit.jsDump.parse(selfref);
equal(selfdump, '{\n "wrap": recursion(-1),\n "first": true\n}');
var selfref = chainwrap(1);
var selfdump = QUnit.jsDump.parse(selfref);
equal(selfdump, '{\n "first": true,\n "wrap": recursion(-1)\n}');
var parentref = chainwrap(2);
var parentdump = QUnit.jsDump.parse(parentref);
equal(parentdump, '{\n "wrap": {\n "wrap": recursion(-2),\n "first": true\n }\n}');
var parentref = chainwrap(2);
var parentdump = QUnit.jsDump.parse(parentref);
equal(parentdump, '{\n "wrap": {\n "first": true,\n "wrap": recursion(-2)\n }\n}');
var circref = chainwrap(10);
var circdump = QUnit.jsDump.parse(circref);
ok(new RegExp("recursion\\(-10\\)").test(circdump), "(" +circdump + ") should show -10 recursion level");
var circref = chainwrap(10);
var circdump = QUnit.jsDump.parse(circref);
ok(new RegExp("recursion\\(-10\\)").test(circdump), "(" +circdump + ") should show -10 recursion level");
});
test("check (deep-)equal recursion", function() {
var noRecursion = chainwrap(0);
equal(noRecursion, noRecursion, "I should be equal to me.");
deepEqual(noRecursion, noRecursion, "... and so in depth.");
var noRecursion = chainwrap(0);
equal(noRecursion, noRecursion, "I should be equal to me.");
deepEqual(noRecursion, noRecursion, "... and so in depth.");
var selfref = chainwrap(1);
equal(selfref, selfref, "Even so if I nest myself.");
deepEqual(selfref, selfref, "... into the depth.");
var selfref = chainwrap(1);
equal(selfref, selfref, "Even so if I nest myself.");
deepEqual(selfref, selfref, "... into the depth.");
var circref = chainwrap(10);
equal(circref, circref, "Or hide that through some levels of indirection.");
deepEqual(circref, circref, "... and checked on all levels!");
var circref = chainwrap(10);
equal(circref, circref, "Or hide that through some levels of indirection.");
deepEqual(circref, circref, "... and checked on all levels!");
});

@@ -407,25 +427,25 @@

// pure array self-ref
var arr = [];
arr.push(arr);
// pure array self-ref
var arr = [];
arr.push(arr);
var arrdump = QUnit.jsDump.parse(arr);
var arrdump = QUnit.jsDump.parse(arr);
equal(arrdump, '[\n recursion(-1)\n]');
equal(arr, arr[0], 'no endless stack when trying to dump arrays with circular ref');
equal(arrdump, '[\n recursion(-1)\n]');
equal(arr, arr[0], 'no endless stack when trying to dump arrays with circular ref');
// mix obj-arr circular ref
var obj = {};
var childarr = [obj];
obj.childarr = childarr;
// mix obj-arr circular ref
var obj = {};
var childarr = [obj];
obj.childarr = childarr;
var objdump = QUnit.jsDump.parse(obj);
var childarrdump = QUnit.jsDump.parse(childarr);
var objdump = QUnit.jsDump.parse(obj);
var childarrdump = QUnit.jsDump.parse(childarr);
equal(objdump, '{\n "childarr": [\n recursion(-2)\n ]\n}');
equal(childarrdump, '[\n {\n "childarr": recursion(-2)\n }\n]');
equal(objdump, '{\n "childarr": [\n recursion(-2)\n ]\n}');
equal(childarrdump, '[\n {\n "childarr": recursion(-2)\n }\n]');
equal(obj.childarr, childarr, 'no endless stack when trying to dump array/object mix with circular ref');
equal(childarr[0], obj, 'no endless stack when trying to dump array/object mix with circular ref');
equal(obj.childarr, childarr, 'no endless stack when trying to dump array/object mix with circular ref');
equal(childarr[0], obj, 'no endless stack when trying to dump array/object mix with circular ref');

@@ -436,39 +456,35 @@ });

test('Circular reference - test reported by soniciq in #105', function() {
var MyObject = function() {};
MyObject.prototype.parent = function(obj) {
if (obj === undefined) { return this._parent; }
this._parent = obj;
};
MyObject.prototype.children = function(obj) {
if (obj === undefined) { return this._children; }
this._children = obj;
};
var MyObject = function() {};
MyObject.prototype.parent = function(obj) {
if (obj === undefined) { return this._parent; }
this._parent = obj;
};
MyObject.prototype.children = function(obj) {
if (obj === undefined) { return this._children; }
this._children = obj;
};
var a = new MyObject(),
b = new MyObject();
var a = new MyObject(),
b = new MyObject();
var barr = [b];
a.children(barr);
b.parent(a);
var barr = [b];
a.children(barr);
b.parent(a);
equal(a.children(), barr);
deepEqual(a.children(), [b]);
equal(a.children(), barr);
deepEqual(a.children(), [b]);
});
(function() {
var reset = QUnit.reset;
function afterTest() {
ok( false, "reset should not modify test status" );
}
module("reset");
test("reset runs assertions", function() {
expect(0);
QUnit.reset = function() {
afterTest();
ok( false, "reset should not modify test status" );
reset.apply( this, arguments );
};
});
test("reset runs assertions2", function() {
test("reset runs assertions, cleanup", function() {
expect(0);
QUnit.reset = reset;

@@ -475,0 +491,0 @@ });

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc