diff --git a/vendor/backbone/LICENSE b/vendor/backbone/LICENSE
index f79bb0058..dda0a5809 100644
--- a/vendor/backbone/LICENSE
+++ b/vendor/backbone/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2010-2012 Jeremy Ashkenas, DocumentCloud
+Copyright (c) 2010-2013 Jeremy Ashkenas, DocumentCloud
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
@@ -19,4 +19,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/backbone/backbone.js b/vendor/backbone/backbone.js
index 9d0a0c3c1..aee5cb789 100644
--- a/vendor/backbone/backbone.js
+++ b/vendor/backbone/backbone.js
@@ -1,6 +1,6 @@
// Backbone.js 0.9.10
-// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
+// (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc.
// Backbone may be freely distributed under the MIT license.
// For all details and documentation:
// http://backbonejs.org
@@ -89,15 +89,15 @@
// Optimized internal dispatch function for triggering events. Tries to
// keep the usual cases speedy (most Backbone events have 3 arguments).
var triggerEvents = function(events, args) {
- var ev, i = -1, l = events.length;
+ var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
switch (args.length) {
case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx);
return;
- case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0]);
+ case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1);
return;
- case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1]);
+ case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2);
return;
- case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1], args[2]);
+ case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3);
return;
default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
}
@@ -119,25 +119,24 @@
// to a `callback` function. Passing `"all"` will bind the callback to
// all events fired.
on: function(name, callback, context) {
- if (!(eventsApi(this, 'on', name, [callback, context]) && callback)) return this;
+ if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
this._events || (this._events = {});
- var list = this._events[name] || (this._events[name] = []);
- list.push({callback: callback, context: context, ctx: context || this});
+ var events = this._events[name] || (this._events[name] = []);
+ events.push({callback: callback, context: context, ctx: context || this});
return this;
},
// Bind events to only be triggered a single time. After the first time
// the callback is invoked, it will be removed.
once: function(name, callback, context) {
- if (!(eventsApi(this, 'once', name, [callback, context]) && callback)) return this;
+ if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
var self = this;
var once = _.once(function() {
self.off(name, once);
callback.apply(this, arguments);
});
once._callback = callback;
- this.on(name, once, context);
- return this;
+ return this.on(name, once, context);
},
// Remove one or many callbacks. If `context` is null, removes all
@@ -145,7 +144,7 @@
// callbacks for the event. If `name` is null, removes all bound
// callbacks for all events.
off: function(name, callback, context) {
- var list, ev, events, names, i, l, j, k;
+ var retain, ev, events, names, i, l, j, k;
if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
if (!name && !callback && !context) {
this._events = {};
@@ -155,19 +154,19 @@
names = name ? [name] : _.keys(this._events);
for (i = 0, l = names.length; i < l; i++) {
name = names[i];
- if (list = this._events[name]) {
- events = [];
+ if (events = this._events[name]) {
+ this._events[name] = retain = [];
if (callback || context) {
- for (j = 0, k = list.length; j < k; j++) {
- ev = list[j];
+ for (j = 0, k = events.length; j < k; j++) {
+ ev = events[j];
if ((callback && callback !== ev.callback &&
callback !== ev.callback._callback) ||
(context && context !== ev.context)) {
- events.push(ev);
+ retain.push(ev);
}
}
}
- this._events[name] = events;
+ if (!retain.length) delete this._events[name];
}
}
@@ -189,21 +188,11 @@
return this;
},
- // An inversion-of-control version of `on`. Tell *this* object to listen to
- // an event in another object ... keeping track of what it's listening to.
- listenTo: function(obj, name, callback) {
- var listeners = this._listeners || (this._listeners = {});
- var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
- listeners[id] = obj;
- obj.on(name, typeof name === 'object' ? this : callback, this);
- return this;
- },
-
// Tell this object to stop listening to either specific events ... or
// to every object it's currently listening to.
stopListening: function(obj, name, callback) {
var listeners = this._listeners;
- if (!listeners) return;
+ if (!listeners) return this;
if (obj) {
obj.off(name, typeof name === 'object' ? this : callback, this);
if (!name && !callback) delete listeners[obj._listenerId];
@@ -218,6 +207,20 @@
}
};
+ var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
+
+ // An inversion-of-control versions of `on` and `once`. Tell *this* object to listen to
+ // an event in another object ... keeping track of what it's listening to.
+ _.each(listenMethods, function(implementation, method) {
+ Events[method] = function(obj, name, callback) {
+ var listeners = this._listeners || (this._listeners = {});
+ var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
+ listeners[id] = obj;
+ obj[implementation](name, typeof name === 'object' ? this : callback, this);
+ return this;
+ };
+ });
+
// Aliases for backwards compatibility.
Events.bind = Events.on;
Events.unbind = Events.off;
@@ -252,6 +255,9 @@
// A hash of attributes whose current and previous value differ.
changed: null,
+ // The value returned during the last failed validation.
+ validationError: null,
+
// The default name for the JSON `id` attribute is `"id"`. MongoDB and
// CouchDB users may want to set this to `"_id"`.
idAttribute: 'id',
@@ -1299,7 +1305,7 @@
// This only works for delegate-able events: not `focus`, `blur`, and
// not `change`, `submit`, and `reset` in Internet Explorer.
delegateEvents: function(events) {
- if (!(events || (events = _.result(this, 'events')))) return;
+ if (!(events || (events = _.result(this, 'events')))) return this;
this.undelegateEvents();
for (var key in events) {
var method = events[key];
@@ -1315,6 +1321,7 @@
this.$el.on(eventName, selector, method);
}
}
+ return this;
},
// Clears all callbacks previously bound to the view with `delegateEvents`.
@@ -1322,6 +1329,7 @@
// Backbone views attached to the same DOM element.
undelegateEvents: function() {
this.$el.off('.delegateEvents' + this.cid);
+ return this;
},
// Performs the initial configuration of a View with a set of options.
diff --git a/vendor/backbone/test/events.js b/vendor/backbone/test/events.js
index f94d32c3d..f7ba753f0 100644
--- a/vendor/backbone/test/events.js
+++ b/vendor/backbone/test/events.js
@@ -101,6 +101,38 @@ $(document).ready(function() {
b.trigger('event event2');
});
+ test("listenToOnce and stopListening", 1, function() {
+ var a = _.extend({}, Backbone.Events);
+ var b = _.extend({}, Backbone.Events);
+ a.listenToOnce(b, 'all', function() { ok(true); });
+ b.trigger('anything');
+ b.trigger('anything');
+ a.listenToOnce(b, 'all', function() { ok(false); });
+ a.stopListening();
+ b.trigger('anything');
+ });
+
+ test("listenTo, listenToOnce and stopListening", 1, function() {
+ var a = _.extend({}, Backbone.Events);
+ var b = _.extend({}, Backbone.Events);
+ a.listenToOnce(b, 'all', function() { ok(true); });
+ b.trigger('anything');
+ b.trigger('anything');
+ a.listenTo(b, 'all', function() { ok(false); });
+ a.stopListening();
+ b.trigger('anything');
+ });
+
+ test("listenTo and stopListening with event maps", 1, function() {
+ var a = _.extend({}, Backbone.Events);
+ var b = _.extend({}, Backbone.Events);
+ a.listenTo(b, {change: function(){ ok(true); }});
+ b.trigger('change');
+ a.listenTo(b, {change: function(){ ok(false); }});
+ a.stopListening();
+ b.trigger('change');
+ });
+
test("listenTo yourself", 1, function(){
var e = _.extend({}, Backbone.Events);
e.listenTo(e, "foo", function(){ ok(true); });
@@ -259,18 +291,6 @@ $(document).ready(function() {
obj.trigger('x y');
});
- test("off is chainable", 3, function() {
- var obj = _.extend({}, Backbone.Events);
- // With no events
- ok(obj.off() === obj);
- // When removing all events
- obj.on('event', function(){}, obj);
- ok(obj.off() === obj);
- // When removing some events
- obj.on('event', function(){}, obj);
- ok(obj.off('event') === obj);
- });
-
test("#1310 - off does not skip consecutive events", 0, function() {
var obj = _.extend({}, Backbone.Events);
obj.on('event', function() { ok(false); }, obj);
@@ -400,4 +420,21 @@ $(document).ready(function() {
_.extend({}, Backbone.Events).once('event').trigger('event');
});
+ test("event functions are chainable", function() {
+ var obj = _.extend({}, Backbone.Events);
+ var obj2 = _.extend({}, Backbone.Events);
+ var fn = function() {};
+ equal(obj, obj.trigger('noeventssetyet'));
+ equal(obj, obj.off('noeventssetyet'));
+ equal(obj, obj.stopListening('noeventssetyet'));
+ equal(obj, obj.on('a', fn));
+ equal(obj, obj.once('c', fn));
+ equal(obj, obj.trigger('a'));
+ equal(obj, obj.listenTo(obj2, 'a', fn));
+ equal(obj, obj.listenToOnce(obj2, 'b', fn));
+ equal(obj, obj.off('a c'));
+ equal(obj, obj.stopListening(obj2, 'a'));
+ equal(obj, obj.stopListening());
+ });
+
});
diff --git a/vendor/qunit/README.md b/vendor/qunit/README.md
index 57ff29e1f..6ab73f57a 100644
--- a/vendor/qunit/README.md
+++ b/vendor/qunit/README.md
@@ -23,9 +23,6 @@ If you are interested in helping developing QUnit, you are in the right place.
For related discussions, visit the
[QUnit and Testing forum](http://forum.jquery.com/qunit-and-testing).
-Planning for a qunitjs.com site and other testing tools related work now happens
-on the [jQuery Testing Team planning wiki](http://jquerytesting.pbworks.com/w/page/41556026/FrontPage).
-
Development
-----------
@@ -49,11 +46,17 @@ tag, update them again to the next version, commit and push commits and tags
Put the 'v' in front of the tag, e.g. `v1.8.0`. Clean up the changelog, removing merge commits
or whitespace cleanups.
-To upload to code.jquery.com (replace $version accordingly):
+To upload to code.jquery.com (replace $version accordingly), ssh to code.origin.jquery.com:
- scp -q qunit/qunit.js jqadmin@code.origin.jquery.com:/var/www/html/code.jquery.com/qunit/qunit-$version.js
- scp -q qunit/qunit.css jqadmin@code.origin.jquery.com:/var/www/html/code.jquery.com/qunit/qunit-$version.css
+ cp qunit/qunit.js /var/www/html/code.jquery.com/qunit/qunit-$version.js
+ cp qunit/qunit.css /var/www/html/code.jquery.com/qunit/qunit-$version.css
Then update /var/www/html/code.jquery.com/index.html and purge it with:
- curl -s http://code.origin.jquery.com/?reload
\ No newline at end of file
+ curl -s http://code.origin.jquery.com/?reload
+
+Update web-base-template to link to those files for qunitjs.com.
+
+Publish to npm via
+
+ npm publish
diff --git a/vendor/qunit/qunit/qunit.css b/vendor/qunit/qunit/qunit.css
index 55970e006..d7fc0c8ec 100644
--- a/vendor/qunit/qunit/qunit.css
+++ b/vendor/qunit/qunit/qunit.css
@@ -1,5 +1,5 @@
/**
- * QUnit v1.10.0 - A JavaScript Unit Testing Framework
+ * QUnit v1.11.0 - A JavaScript Unit Testing Framework
*
* http://qunitjs.com
*
@@ -20,7 +20,7 @@
/** Resets */
-#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
+#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
margin: 0;
padding: 0;
}
@@ -111,7 +111,12 @@
color: #000;
}
-#qunit-tests ol {
+#qunit-tests li .runtime {
+ float: right;
+ font-size: smaller;
+}
+
+.qunit-assert-list {
margin-top: 0.5em;
padding: 0.5em;
@@ -122,6 +127,10 @@
-webkit-border-radius: 5px;
}
+.qunit-collapsed {
+ display: none;
+}
+
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
diff --git a/vendor/qunit/qunit/qunit.js b/vendor/qunit/qunit/qunit.js
index d4f17b5ae..302545f40 100644
--- a/vendor/qunit/qunit/qunit.js
+++ b/vendor/qunit/qunit/qunit.js
@@ -1,5 +1,5 @@
/**
- * QUnit v1.10.0 - A JavaScript Unit Testing Framework
+ * QUnit v1.11.0 - A JavaScript Unit Testing Framework
*
* http://qunitjs.com
*
@@ -11,6 +11,7 @@
(function( window ) {
var QUnit,
+ assert,
config,
onErrorFnPrev,
testId = 0,
@@ -20,18 +21,67 @@ var QUnit,
// Keep a local reference to Date (GH-283)
Date = window.Date,
defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
+ setTimeout: typeof window.setTimeout !== "undefined",
+ sessionStorage: (function() {
+ var x = "qunit-test-string";
+ try {
+ sessionStorage.setItem( x, x );
+ sessionStorage.removeItem( x );
+ return true;
+ } catch( e ) {
+ return false;
+ }
+ }())
+ },
+ /**
+ * Provides a normalized error string, correcting an issue
+ * with IE 7 (and prior) where Error.prototype.toString is
+ * not properly implemented
+ *
+ * Based on http://es5.github.com/#x15.11.4.4
+ *
+ * @param {String|Error} error
+ * @return {String} error message
+ */
+ errorString = function( error ) {
+ var name, message,
+ errorString = error.toString();
+ if ( errorString.substring( 0, 7 ) === "[object" ) {
+ name = error.name ? error.name.toString() : "Error";
+ message = error.message ? error.message.toString() : "";
+ if ( name && message ) {
+ return name + ": " + message;
+ } else if ( name ) {
+ return name;
+ } else if ( message ) {
+ return message;
+ } else {
+ return "Error";
+ }
+ } else {
+ return errorString;
}
- }())
-};
+ },
+ /**
+ * Makes a clone of an object using only Array or Object as base,
+ * and copies over the own enumerable properties.
+ *
+ * @param {Object} obj
+ * @return {Object} New object with only the own properties (recursively).
+ */
+ objectValues = function( obj ) {
+ // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
+ /*jshint newcap: false */
+ var key, val,
+ vals = QUnit.is( "array", obj ) ? [] : {};
+ for ( key in obj ) {
+ if ( hasOwn.call( obj, key ) ) {
+ val = obj[key];
+ vals[key] = val === Object(val) ? objectValues(val) : val;
+ }
+ }
+ return vals;
+ };
function Test( settings ) {
extend( this, settings );
@@ -44,11 +94,11 @@ Test.count = 0;
Test.prototype = {
init: function() {
var a, b, li,
- tests = id( "qunit-tests" );
+ tests = id( "qunit-tests" );
if ( tests ) {
b = document.createElement( "strong" );
- b.innerHTML = this.name;
+ b.innerHTML = this.nameHtml;
// `a` initialized at top of scope
a = document.createElement( "a" );
@@ -92,6 +142,7 @@ Test.prototype = {
teardown: function() {}
}, this.moduleTestEnvironment );
+ this.started = +new Date();
runLoggingCallbacks( "testStart", QUnit, {
name: this.testName,
module: this.module
@@ -111,7 +162,7 @@ Test.prototype = {
try {
this.testEnvironment.setup.call( this.testEnvironment );
} catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
+ QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
}
},
run: function() {
@@ -120,22 +171,28 @@ Test.prototype = {
var running = id( "qunit-testresult" );
if ( running ) {
- running.innerHTML = "Running:
" + this.name;
+ running.innerHTML = "Running:
" + this.nameHtml;
}
if ( this.async ) {
QUnit.stop();
}
+ this.callbackStarted = +new Date();
+
if ( config.notrycatch ) {
this.callback.call( this.testEnvironment, QUnit.assert );
+ this.callbackRuntime = +new Date() - this.callbackStarted;
return;
}
try {
this.callback.call( this.testEnvironment, QUnit.assert );
+ this.callbackRuntime = +new Date() - this.callbackStarted;
} catch( e ) {
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + e.message, extractStacktrace( e, 0 ) );
+ this.callbackRuntime = +new Date() - this.callbackStarted;
+
+ QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
// else next test will carry the responsibility
saveGlobal();
@@ -148,38 +205,43 @@ Test.prototype = {
teardown: function() {
config.current = this;
if ( config.notrycatch ) {
+ if ( typeof this.callbackRuntime === "undefined" ) {
+ this.callbackRuntime = +new Date() - this.callbackStarted;
+ }
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 ) );
+ QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
}
}
checkPollution();
},
finish: function() {
config.current = this;
- if ( config.requireExpects && this.expected == null ) {
+ if ( config.requireExpects && this.expected === null ) {
QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected != null && this.expected != this.assertions.length ) {
+ } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected == null && !this.assertions.length ) {
+ } 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 assertion, a, b, i, li, ol,
+ var i, assertion, a, b, time, li, ol,
test = this,
good = 0,
bad = 0,
tests = id( "qunit-tests" );
+ this.runtime = +new Date() - this.started;
config.stats.all += this.assertions.length;
config.moduleStats.all += this.assertions.length;
if ( tests ) {
ol = document.createElement( "ol" );
+ ol.className = "qunit-assert-list";
for ( i = 0; i < this.assertions.length; i++ ) {
assertion = this.assertions[i];
@@ -208,22 +270,22 @@ Test.prototype = {
}
if ( bad === 0 ) {
- ol.style.display = "none";
+ addClass( ol, "qunit-collapsed" );
}
// `b` initialized at top of scope
b = document.createElement( "strong" );
- b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
+ b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")";
addEvent(b, "click", function() {
- var next = b.nextSibling.nextSibling,
- display = next.style.display;
- next.style.display = display === "none" ? "block" : "none";
+ var next = b.parentNode.lastChild,
+ collapsed = hasClass( next, "qunit-collapsed" );
+ ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
});
addEvent(b, "dblclick", function( e ) {
var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
+ if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
target = target.parentNode;
}
if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
@@ -231,13 +293,19 @@ Test.prototype = {
}
});
+ // `time` initialized at top of scope
+ time = document.createElement( "span" );
+ time.className = "runtime";
+ time.innerHTML = this.runtime + " ms";
+
// `li` initialized at top of scope
li = id( this.id );
li.className = bad ? "fail" : "pass";
li.removeChild( li.firstChild );
a = li.firstChild;
li.appendChild( b );
- li.appendChild ( a );
+ li.appendChild( a );
+ li.appendChild( time );
li.appendChild( ol );
} else {
@@ -255,7 +323,8 @@ Test.prototype = {
module: this.module,
failed: bad,
passed: this.assertions.length - bad,
- total: this.assertions.length
+ total: this.assertions.length,
+ duration: this.runtime
});
QUnit.reset();
@@ -321,7 +390,7 @@ QUnit = {
test: function( testName, expected, callback, async ) {
var test,
- name = "" + escapeInnerText( testName ) + "";
+ nameHtml = "" + escapeText( testName ) + "";
if ( arguments.length === 2 ) {
callback = expected;
@@ -329,11 +398,11 @@ QUnit = {
}
if ( config.currentModule ) {
- name = "" + config.currentModule + ": " + name;
+ nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml;
}
test = new Test({
- name: name,
+ nameHtml: nameHtml,
testName: testName,
expected: expected,
async: async,
@@ -360,6 +429,18 @@ QUnit = {
},
start: function( count ) {
+ // QUnit hasn't been initialized yet.
+ // Note: RequireJS (et al) may delay onLoad
+ if ( config.semaphore === undefined ) {
+ QUnit.begin(function() {
+ // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
+ setTimeout(function() {
+ QUnit.start( count );
+ });
+ });
+ return;
+ }
+
config.semaphore -= count || 1;
// don't start until equal number of stop-calls
if ( config.semaphore > 0 ) {
@@ -368,6 +449,8 @@ QUnit = {
// ignore if start is called more often then stop
if ( config.semaphore < 0 ) {
config.semaphore = 0;
+ QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
+ return;
}
// A slight delay, to avoid any current callbacks
if ( defined.setTimeout ) {
@@ -403,11 +486,14 @@ QUnit = {
}
};
+// `assert` initialized at top of scope
// Asssert helpers
-// All of these must call either QUnit.push() or manually do:
+// All of these must either call QUnit.push() or manually do:
// - runLoggingCallbacks( "log", .. );
// - config.current.assertions.push({ .. });
-QUnit.assert = {
+// We attach it to the QUnit object *after* we expose the public API,
+// otherwise `assert` will become a global variable in browsers (#341).
+assert = {
/**
* Asserts rough true-ish result.
* @name ok
@@ -428,14 +514,14 @@ QUnit.assert = {
message: msg
};
- msg = escapeInnerText( msg || (result ? "okay" : "failed" ) );
+ msg = escapeText( msg || (result ? "okay" : "failed" ) );
msg = "" + msg + "";
if ( !result ) {
source = sourceFromStacktrace( 2 );
if ( source ) {
details.source = source;
- msg += "
| Source: | " + escapeInnerText( source ) + " |
|---|
";
+ msg += "| Source: | " + escapeText( source ) + " |
|---|
";
}
}
runLoggingCallbacks( "log", QUnit, details );
@@ -453,6 +539,7 @@ QUnit.assert = {
* @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
*/
equal: function( actual, expected, message ) {
+ /*jshint eqeqeq:false */
QUnit.push( expected == actual, actual, expected, message );
},
@@ -461,9 +548,30 @@ QUnit.assert = {
* @function
*/
notEqual: function( actual, expected, message ) {
+ /*jshint eqeqeq:false */
QUnit.push( expected != actual, actual, expected, message );
},
+ /**
+ * @name propEqual
+ * @function
+ */
+ propEqual: function( actual, expected, message ) {
+ actual = objectValues(actual);
+ expected = objectValues(expected);
+ QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
+ },
+
+ /**
+ * @name notPropEqual
+ * @function
+ */
+ notPropEqual: function( actual, expected, message ) {
+ actual = objectValues(actual);
+ expected = objectValues(expected);
+ QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
+ },
+
/**
* @name deepEqual
* @function
@@ -496,8 +604,9 @@ QUnit.assert = {
QUnit.push( expected !== actual, actual, expected, message );
},
- throws: function( block, expected, message ) {
+ "throws": function( block, expected, message ) {
var actual,
+ expectedOutput = expected,
ok = false;
// 'expected' is optional
@@ -518,18 +627,20 @@ QUnit.assert = {
// we don't want to validate thrown error
if ( !expected ) {
ok = true;
+ expectedOutput = null;
// expected is a regexp
} else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( actual );
+ ok = expected.test( errorString( actual ) );
// expected is a constructor
} else if ( actual instanceof expected ) {
ok = true;
// expected is a validation function which returns true is validation passed
} else if ( expected.call( {}, actual ) === true ) {
+ expectedOutput = null;
ok = true;
}
- QUnit.push( ok, actual, null, message );
+ QUnit.push( ok, actual, expectedOutput, message );
} else {
QUnit.pushFailure( message, null, 'No exception was thrown.' );
}
@@ -538,15 +649,16 @@ QUnit.assert = {
/**
* @deprecate since 1.8.0
- * Kept assertion helpers in root for backwards compatibility
+ * Kept assertion helpers in root for backwards compatibility.
*/
-extend( QUnit, QUnit.assert );
+extend( QUnit, assert );
/**
* @deprecated since 1.9.0
- * Kept global "raises()" for backwards compatibility
+ * Kept root "raises()" for backwards compatibility.
+ * (Note that we don't introduce assert.raises).
*/
-QUnit.raises = QUnit.assert.throws;
+QUnit.raises = assert[ "throws" ];
/**
* @deprecated since 1.0.0, replaced with error pushes since 1.3.0
@@ -622,6 +734,15 @@ config = {
moduleDone: []
};
+// Export global variables, unless an 'exports' object exists,
+// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
+if ( typeof exports === "undefined" ) {
+ extend( window, QUnit );
+
+ // Expose QUnit object
+ window.QUnit = QUnit;
+}
+
// Initialize more QUnit.config and QUnit.urlParams
(function() {
var i,
@@ -655,18 +776,11 @@ config = {
QUnit.isLocal = location.protocol === "file:";
}());
-// Export global variables, unless an 'exports' object exists,
-// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
-if ( typeof exports === "undefined" ) {
- extend( window, QUnit );
-
- // Expose QUnit object
- window.QUnit = QUnit;
-}
-
// Extend QUnit object,
// these after set here because they should not be exposed as global functions
extend( QUnit, {
+ assert: assert,
+
config: config,
// Initialize the configuration options
@@ -681,7 +795,7 @@ extend( QUnit, {
autorun: false,
filter: "",
queue: [],
- semaphore: 0
+ semaphore: 1
});
var tests, banner, result,
@@ -689,7 +803,7 @@ extend( QUnit, {
if ( qunit ) {
qunit.innerHTML =
- "" +
+ "" +
"" +
"" +
"" +
@@ -745,7 +859,7 @@ extend( QUnit, {
// Safe object type checking
is: function( type, obj ) {
- return QUnit.objectType( obj ) == type;
+ return QUnit.objectType( obj ) === type;
},
objectType: function( obj ) {
@@ -757,7 +871,8 @@ extend( QUnit, {
return "null";
}
- var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || "";
+ var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
+ type = match && match[1] || "";
switch ( type ) {
case "Number":
@@ -794,16 +909,16 @@ extend( QUnit, {
expected: expected
};
- message = escapeInnerText( message ) || ( result ? "okay" : "failed" );
+ message = escapeText( message ) || ( result ? "okay" : "failed" );
message = "" + message + "";
output = message;
if ( !result ) {
- expected = escapeInnerText( QUnit.jsDump.parse(expected) );
- actual = escapeInnerText( QUnit.jsDump.parse(actual) );
+ expected = escapeText( QUnit.jsDump.parse(expected) );
+ actual = escapeText( QUnit.jsDump.parse(actual) );
output += "| Expected: | " + expected + " |
";
- if ( actual != expected ) {
+ if ( actual !== expected ) {
output += "| Result: | " + actual + " |
";
output += "| Diff: | " + QUnit.diff( expected, actual ) + " |
";
}
@@ -812,7 +927,7 @@ extend( QUnit, {
if ( source ) {
details.source = source;
- output += "| Source: | " + escapeInnerText( source ) + " |
";
+ output += "| Source: | " + escapeText( source ) + " |
";
}
output += "
";
@@ -839,19 +954,19 @@ extend( QUnit, {
message: message
};
- message = escapeInnerText( message ) || "error";
+ message = escapeText( message ) || "error";
message = "" + message + "";
output = message;
output += "";
if ( actual ) {
- output += "| Result: | " + escapeInnerText( actual ) + " |
";
+ output += "| Result: | " + escapeText( actual ) + " |
";
}
if ( source ) {
details.source = source;
- output += "| Source: | " + escapeInnerText( source ) + " |
";
+ output += "| Source: | " + escapeText( source ) + " |
";
}
output += "
";
@@ -876,7 +991,8 @@ extend( QUnit, {
querystring += encodeURIComponent( key ) + "=" +
encodeURIComponent( params[ key ] ) + "&";
}
- return window.location.pathname + querystring.slice( 0, -1 );
+ return window.location.protocol + "//" + window.location.host +
+ window.location.pathname + querystring.slice( 0, -1 );
},
extend: extend,
@@ -907,7 +1023,7 @@ extend( QUnit.constructor.prototype, {
// testStart: { name }
testStart: registerLoggingCallback( "testStart" ),
- // testDone: { name, failed, passed, total }
+ // testDone: { name, failed, passed, total, duration }
testDone: registerLoggingCallback( "testDone" ),
// moduleStart: { name }
@@ -925,9 +1041,10 @@ QUnit.load = function() {
runLoggingCallbacks( "begin", QUnit, {} );
// Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, urlConfigCheckboxes, moduleFilter,
- numModules = 0,
- moduleFilterHtml = "",
+ var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
+ urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
+ numModules = 0,
+ moduleFilterHtml = "",
urlConfigHtml = "",
oldconfig = extend( {}, config );
@@ -948,14 +1065,24 @@ QUnit.load = function() {
};
}
config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "";
+ urlConfigHtml += "";
}
- moduleFilterHtml += "