From 09259964dfb64680cd389e189031f6daacd26297 Mon Sep 17 00:00:00 2001 From: Brad Dunbar Date: Wed, 3 Jul 2013 11:03:19 -0400 Subject: [PATCH] QUnit 1.12.0 --- test/collection.js | 6 +- test/environment.js | 60 ++++------ test/model.js | 5 +- test/sync.js | 6 +- test/vendor/qunit.css | 2 +- test/vendor/qunit.js | 262 ++++++++++++++++++++++++++---------------- 6 files changed, 193 insertions(+), 148 deletions(-) diff --git a/test/collection.js b/test/collection.js index 53bd3278..05b5af7f 100644 --- a/test/collection.js +++ b/test/collection.js @@ -2,11 +2,9 @@ $(document).ready(function() { var a, b, c, d, e, col, otherCol; - module("Backbone.Collection", _.extend(new Environment, { + module("Backbone.Collection", { setup: function() { - Environment.prototype.setup.apply(this, arguments); - a = new Backbone.Model({id: 3, label: 'a'}); b = new Backbone.Model({id: 2, label: 'b'}); c = new Backbone.Model({id: 1, label: 'c'}); @@ -16,7 +14,7 @@ $(document).ready(function() { otherCol = new Backbone.Collection(); } - })); + }); test("new and sort", 9, function() { var counter = 0; diff --git a/test/environment.js b/test/environment.js index 54aa2c40..996884bb 100644 --- a/test/environment.js +++ b/test/environment.js @@ -1,45 +1,35 @@ (function() { - var Environment = this.Environment = function(){}; + var sync = Backbone.sync; + var ajax = Backbone.ajax; + var emulateHTTP = Backbone.emulateHTTP; + var emulateJSON = Backbone.emulateJSON; - _.extend(Environment.prototype, { + QUnit.testStart(function() { + var env = this.config.current.testEnvironment; - ajax: Backbone.ajax, + // Capture ajax settings for comparison. + Backbone.ajax = function(settings) { + env.ajaxSettings = settings; + }; - sync: Backbone.sync, - - emulateHTTP: Backbone.emulateHTTP, - - emulateJSON: Backbone.emulateJSON, - - setup: function() { - var env = this; - - // Capture ajax settings for comparison. - Backbone.ajax = function(settings) { - env.ajaxSettings = settings; + // Capture the arguments to Backbone.sync for comparison. + Backbone.sync = function(method, model, options) { + env.syncArgs = { + method: method, + model: model, + options: options }; - - // Capture the arguments to Backbone.sync for comparison. - Backbone.sync = function(method, model, options) { - env.syncArgs = { - method: method, - model: model, - options: options - }; - env.sync.apply(this, arguments); - }; - }, - - teardown: function() { - this.syncArgs = null; - this.ajaxSettings = null; - Backbone.sync = this.sync; - Backbone.ajax = this.ajax; - Backbone.emulateHTTP = this.emulateHTTP; - Backbone.emulateJSON = this.emulateJSON; - } + sync.apply(this, arguments); + }; }); + QUnit.testDone(function() { + Backbone.sync = sync; + Backbone.ajax = ajax; + Backbone.emulateHTTP = emulateHTTP; + Backbone.emulateJSON = emulateJSON; + }); + })(); diff --git a/test/model.js b/test/model.js index faede68a..123c91e1 100644 --- a/test/model.js +++ b/test/model.js @@ -6,10 +6,9 @@ $(document).ready(function() { }); var doc, collection; - module("Backbone.Model", _.extend(new Environment, { + module("Backbone.Model", { setup: function() { - Environment.prototype.setup.apply(this, arguments); doc = new proxy({ id : '1-the-tempest', title : "The Tempest", @@ -20,7 +19,7 @@ $(document).ready(function() { collection.add(doc); } - })); + }); test("initialize", 3, function() { var Model = Backbone.Model.extend({ diff --git a/test/sync.js b/test/sync.js index 8fddb47f..b8389051 100644 --- a/test/sync.js +++ b/test/sync.js @@ -11,20 +11,18 @@ $(document).ready(function() { length : 123 }; - module("Backbone.sync", _.extend(new Environment, { + module("Backbone.sync", { setup : function() { - Environment.prototype.setup.apply(this, arguments); library = new Library; library.create(attrs, {wait: false}); }, teardown: function() { - Environment.prototype.teardown.apply(this, arguments); Backbone.emulateHTTP = false; } - })); + }); test("read", 4, function() { library.fetch(); diff --git a/test/vendor/qunit.css b/test/vendor/qunit.css index d7fc0c8e..7ba3f9a3 100755 --- a/test/vendor/qunit.css +++ b/test/vendor/qunit.css @@ -1,5 +1,5 @@ /** - * QUnit v1.11.0 - A JavaScript Unit Testing Framework + * QUnit v1.12.0 - A JavaScript Unit Testing Framework * * http://qunitjs.com * diff --git a/test/vendor/qunit.js b/test/vendor/qunit.js index 302545f4..84c73907 100755 --- a/test/vendor/qunit.js +++ b/test/vendor/qunit.js @@ -1,11 +1,11 @@ /** - * QUnit v1.11.0 - A JavaScript Unit Testing Framework + * QUnit v1.12.0 - A JavaScript Unit Testing Framework * * http://qunitjs.com * - * Copyright 2012 jQuery Foundation and other contributors + * Copyright 2013 jQuery Foundation and other contributors * Released under the MIT license. - * http://jquery.org/license + * https://jquery.org/license/ */ (function( window ) { @@ -20,6 +20,7 @@ var QUnit, hasOwn = Object.prototype.hasOwnProperty, // Keep a local reference to Date (GH-283) Date = window.Date, + setTimeout = window.setTimeout, defined = { setTimeout: typeof window.setTimeout !== "undefined", sessionStorage: (function() { @@ -115,8 +116,16 @@ Test.prototype = { } }, setup: function() { - if ( this.module !== config.previousModule ) { - if ( config.previousModule ) { + if ( + // Emit moduleStart when we're switching from one module to another + this.module !== config.previousModule || + // They could be equal (both undefined) but if the previousModule property doesn't + // yet exist it means this is the first test in a suite that isn't wrapped in a + // module, in which case we'll just emit a moduleStart event for 'undefined'. + // Without this, reporters can get testStart before moduleStart which is a problem. + !hasOwn.call( config, "previousModule" ) + ) { + if ( hasOwn.call( config, "previousModule" ) ) { runLoggingCallbacks( "moduleDone", QUnit, { name: config.previousModule, failed: config.moduleStats.bad, @@ -129,10 +138,6 @@ Test.prototype = { runLoggingCallbacks( "moduleStart", QUnit, { name: this.module }); - } else if ( config.autorun ) { - runLoggingCallbacks( "moduleStart", QUnit, { - name: this.module - }); } config.current = this; @@ -148,19 +153,27 @@ Test.prototype = { module: this.module }); - // allow utility functions to access the current test environment - // TODO why?? + /*jshint camelcase:false */ + + + /** + * Expose the current test environment. + * + * @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead. + */ QUnit.current_testEnvironment = this.testEnvironment; + /*jshint camelcase:true */ + if ( !config.pollution ) { saveGlobal(); } if ( config.notrycatch ) { - this.testEnvironment.setup.call( this.testEnvironment ); + this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert ); return; } try { - this.testEnvironment.setup.call( this.testEnvironment ); + this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert ); } catch( e ) { QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); } @@ -208,11 +221,11 @@ Test.prototype = { if ( typeof this.callbackRuntime === "undefined" ) { this.callbackRuntime = +new Date() - this.callbackStarted; } - this.testEnvironment.teardown.call( this.testEnvironment ); + this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert ); return; } else { try { - this.testEnvironment.teardown.call( this.testEnvironment ); + this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert ); } catch( e ) { QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); } @@ -419,7 +432,7 @@ QUnit = { test.queue(); }, - // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. + // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through. expect: function( asserts ) { if (arguments.length === 1) { config.current.expected = asserts; @@ -454,7 +467,7 @@ QUnit = { } // A slight delay, to avoid any current callbacks if ( defined.setTimeout ) { - window.setTimeout(function() { + setTimeout(function() { if ( config.semaphore > 0 ) { return; } @@ -477,7 +490,7 @@ QUnit = { if ( config.testTimeout && defined.setTimeout ) { clearTimeout( config.timeout ); - config.timeout = window.setTimeout(function() { + config.timeout = setTimeout(function() { QUnit.ok( false, "Test timed out" ); config.semaphore = 1; QUnit.start(); @@ -487,7 +500,7 @@ QUnit = { }; // `assert` initialized at top of scope -// Asssert helpers +// Assert helpers // All of these must either call QUnit.push() or manually do: // - runLoggingCallbacks( "log", .. ); // - config.current.assertions.push({ .. }); @@ -505,6 +518,7 @@ assert = { throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); } result = !!result; + msg = msg || (result ? "okay" : "failed" ); var source, details = { @@ -514,8 +528,7 @@ assert = { message: msg }; - msg = escapeText( msg || (result ? "okay" : "failed" ) ); - msg = "" + msg + ""; + msg = "" + escapeText( msg ) + ""; if ( !result ) { source = sourceFromStacktrace( 2 ); @@ -642,13 +655,13 @@ assert = { QUnit.push( ok, actual, expectedOutput, message ); } else { - QUnit.pushFailure( message, null, 'No exception was thrown.' ); + QUnit.pushFailure( message, null, "No exception was thrown." ); } } }; /** - * @deprecate since 1.8.0 + * @deprecated since 1.8.0 * Kept assertion helpers in root for backwards compatibility. */ extend( QUnit, assert ); @@ -737,7 +750,7 @@ config = { // 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 ); + extend( window, QUnit.constructor.prototype ); // Expose QUnit object window.QUnit = QUnit; @@ -836,6 +849,11 @@ extend( QUnit, { }, // Resets the test setup. Useful for tests that modify the DOM. + /* + DEPRECATED: Use multiple tests instead of resetting inside a test. + Use testStart or testDone for custom cleanup. + This method will throw an error in 2.0, and will be removed in 2.1 + */ reset: function() { var fixture = id( "qunit-fixture" ); if ( fixture ) { @@ -985,11 +1003,10 @@ extend( QUnit, { querystring = "?"; for ( key in params ) { - if ( !hasOwn.call( params, key ) ) { - continue; + if ( hasOwn.call( params, key ) ) { + querystring += encodeURIComponent( key ) + "=" + + encodeURIComponent( params[ key ] ) + "&"; } - querystring += encodeURIComponent( key ) + "=" + - encodeURIComponent( params[ key ] ) + "&"; } return window.location.protocol + "//" + window.location.host + window.location.pathname + querystring.slice( 0, -1 ); @@ -997,7 +1014,10 @@ extend( QUnit, { extend: extend, id: id, - addEvent: addEvent + addEvent: addEvent, + addClass: addClass, + hasClass: hasClass, + removeClass: removeClass // load, equiv, jsDump, diff: Attached later }); @@ -1044,6 +1064,7 @@ QUnit.load = function() { var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter, numModules = 0, + moduleNames = [], moduleFilterHtml = "", urlConfigHtml = "", oldconfig = extend( {}, config ); @@ -1072,18 +1093,24 @@ QUnit.load = function() { "'>"; } - + for ( i in config.modules ) { + if ( config.modules.hasOwnProperty( i ) ) { + moduleNames.push(i); + } + } + numModules = moduleNames.length; + moduleNames.sort( function( a, b ) { + return a.localeCompare( b ); + }); moduleFilterHtml += ""; @@ -1137,7 +1164,7 @@ QUnit.load = function() { // `label` initialized at top of scope label = document.createElement( "label" ); label.setAttribute( "for", "qunit-filter-pass" ); - label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." ); + label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." ); label.innerHTML = "Hide passed tests"; toolbar.appendChild( label ); @@ -1157,14 +1184,19 @@ QUnit.load = function() { toolbar.appendChild( urlConfigCheckboxesContainer ); if (numModules > 1) { - moduleFilter = document.createElement( 'span' ); - moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' ); + moduleFilter = document.createElement( "span" ); + moduleFilter.setAttribute( "id", "qunit-modulefilter-container" ); moduleFilter.innerHTML = moduleFilterHtml; addEvent( moduleFilter.lastChild, "change", function() { var selectBox = moduleFilter.getElementsByTagName("select")[0], selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value); - window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } ); + window.location = QUnit.url({ + module: ( selectedModule === "" ) ? undefined : selectedModule, + // Remove any existing filters + filter: undefined, + testNumber: undefined + }); }); toolbar.appendChild(moduleFilter); } @@ -1188,7 +1220,7 @@ addEvent( window, "load", QUnit.load ); onErrorFnPrev = window.onerror; // Cover uncaught exceptions -// Returning true will surpress the default browser handler, +// Returning true will suppress the default browser handler, // returning false will let it run. window.onerror = function ( error, filePath, linerNr ) { var ret = false; @@ -1197,7 +1229,7 @@ window.onerror = function ( error, filePath, linerNr ) { } // Treat return value as window.onerror itself does, - // Only do our handling if not surpressed. + // Only do our handling if not suppressed. if ( ret !== true ) { if ( QUnit.config.current ) { if ( QUnit.config.current.ignoreGlobalErrors ) { @@ -1227,6 +1259,7 @@ function done() { total: config.moduleStats.all }); } + delete config.previousModule; var i, key, banner = id( "qunit-banner" ), @@ -1386,16 +1419,16 @@ function escapeText( s ) { // Both single quotes and double quotes (for attributes) return s.replace( /['"<>&]/g, function( s ) { switch( s ) { - case '\'': - return '''; - case '"': - return '"'; - case '<': - return '<'; - case '>': - return '>'; - case '&': - return '&'; + case "'": + return "'"; + case "\"": + return """; + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; } }); } @@ -1419,7 +1452,7 @@ function process( last ) { if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { config.queue.shift()(); } else { - window.setTimeout( next, 13 ); + setTimeout( next, 13 ); break; } } @@ -1434,11 +1467,13 @@ function saveGlobal() { if ( config.noglobals ) { for ( var key in window ) { - // in Opera sometimes DOM element ids show up here, ignore them - if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) { - continue; + if ( hasOwn.call( window, key ) ) { + // in Opera sometimes DOM element ids show up here, ignore them + if ( /^qunit-test-output/.test( key ) ) { + continue; + } + config.pollution.push( key ); } - config.pollution.push( key ); } } } @@ -1480,12 +1515,15 @@ function diff( a, b ) { function extend( a, b ) { for ( var prop in b ) { - 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 ]; + if ( hasOwn.call( b, prop ) ) { + // Avoid "Member not found" error in IE8 caused by messing with window.constructor + if ( !( prop === "constructor" && a === window ) ) { + if ( b[ prop ] === undefined ) { + delete a[ prop ]; + } else { + a[ prop ] = b[ prop ]; + } + } } } @@ -1535,8 +1573,8 @@ function removeClass( elem, name ) { while ( set.indexOf(" " + name + " ") > -1 ) { set = set.replace(" " + name + " " , " "); } - // If possible, trim it for prettiness, but not neccecarily - elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set ); + // If possible, trim it for prettiness, but not necessarily + elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, ""); } function id( name ) { @@ -1585,8 +1623,10 @@ QUnit.equiv = (function() { callers = [], // stack to avoiding loops from circular referencing parents = [], + parentsB = [], getProto = Object.getPrototypeOf || function ( obj ) { + /*jshint camelcase:false */ return obj.__proto__; }, callbacks = (function () { @@ -1595,7 +1635,7 @@ QUnit.equiv = (function() { function useStrictEquality( b, a ) { /*jshint eqeqeq:false */ if ( b instanceof a.constructor || a instanceof b.constructor ) { - // to catch short annotaion VS 'new' annotation of a + // to catch short annotation VS 'new' annotation of a // declaration // e.g. var i = 1; // var j = new Number(1); @@ -1624,7 +1664,7 @@ QUnit.equiv = (function() { return QUnit.objectType( b ) === "regexp" && // the regex itself a.source === b.source && - // and its modifers + // and its modifiers a.global === b.global && // (gmi) ... a.ignoreCase === b.ignoreCase && @@ -1641,7 +1681,7 @@ QUnit.equiv = (function() { }, "array": function( b, a ) { - var i, j, len, loop; + var i, j, len, loop, aCircular, bCircular; // b could be an object literal here if ( QUnit.objectType( b ) !== "array" ) { @@ -1656,24 +1696,36 @@ QUnit.equiv = (function() { // track reference to avoid circular references parents.push( a ); + parentsB.push( b ); 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 + aCircular = parents[j] === a[i]; + bCircular = parentsB[j] === b[i]; + if ( aCircular || bCircular ) { + if ( a[i] === b[i] || aCircular && bCircular ) { + loop = true; + } else { + parents.pop(); + parentsB.pop(); + return false; + } } } if ( !loop && !innerEquiv(a[i], b[i]) ) { parents.pop(); + parentsB.pop(); return false; } } parents.pop(); + parentsB.pop(); return true; }, "object": function( b, a ) { - var i, j, loop, + /*jshint forin:false */ + var i, j, loop, aCircular, bCircular, // Default to true eq = true, aProperties = [], @@ -1692,28 +1744,36 @@ QUnit.equiv = (function() { // stack constructor before traversing properties callers.push( a.constructor ); + // track reference to avoid circular references parents.push( a ); + parentsB.push( b ); - for ( i in a ) { // be strict: don't ensures hasOwnProperty - // and go deep + // be strict: don't ensure hasOwnProperty and go deep + for ( i in a ) { loop = false; for ( j = 0; j < parents.length; j++ ) { - if ( parents[j] === a[i] ) { - // don't go down the same path twice - loop = true; + aCircular = parents[j] === a[i]; + bCircular = parentsB[j] === b[i]; + if ( aCircular || bCircular ) { + if ( a[i] === b[i] || aCircular && bCircular ) { + loop = true; + } else { + eq = false; + break; + } } } - aProperties.push(i); // collect a's properties - - if (!loop && !innerEquiv( a[i], b[i] ) ) { + aProperties.push(i); + if ( !loop && !innerEquiv(a[i], b[i]) ) { eq = false; break; } } - callers.pop(); // unstack, we are done parents.pop(); + parentsB.pop(); + callers.pop(); // unstack, we are done for ( i in b ) { bProperties.push( i ); // collect b's properties @@ -1743,7 +1803,7 @@ QUnit.equiv = (function() { } // apply transition with (1..n) arguments - }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) ); + }( args[0], args[1] ) && innerEquiv.apply( this, args.splice(1, args.length - 1 )) ); }; return innerEquiv; @@ -1761,7 +1821,7 @@ QUnit.equiv = (function() { */ QUnit.jsDump = (function() { function quote( str ) { - return '"' + str.toString().replace( /"/g, '\\"' ) + '"'; + return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\""; } function literal( o ) { return o + ""; @@ -1854,13 +1914,13 @@ QUnit.jsDump = (function() { if ( this.HTML ) { chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); } - return new Array( this._depth_ + (extra||0) ).join(chr); + return new Array( this.depth + ( extra || 0 ) ).join(chr); }, up: function( a ) { - this._depth_ += a || 1; + this.depth += a || 1; }, down: function( a ) { - this._depth_ -= a || 1; + this.depth -= a || 1; }, setParser: function( name, parser ) { this.parsers[name] = parser; @@ -1870,7 +1930,7 @@ QUnit.jsDump = (function() { literal: literal, join: join, // - _depth_: 1, + depth: 1, // This is the list of parsers, to modify them, use jsDump.setParser parsers: { window: "[Window]", @@ -1898,6 +1958,7 @@ QUnit.jsDump = (function() { nodelist: array, "arguments": array, object: function( map, stack ) { + /*jshint forin:false */ var ret = [ ], keys, key, val, i; QUnit.jsDump.up(); keys = []; @@ -2036,18 +2097,17 @@ QUnit.diff = (function() { } for ( i in ns ) { - if ( !hasOwn.call( ns, i ) ) { - continue; - } - if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && 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] ], - row: ns[i].rows[0] - }; + if ( hasOwn.call( ns, i ) ) { + if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && 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] ], + row: ns[i].rows[0] + }; + } } } @@ -2143,9 +2203,9 @@ QUnit.diff = (function() { }; }()); -// for CommonJS enviroments, export everything +// for CommonJS environments, export everything if ( typeof exports !== "undefined" ) { - extend( exports, QUnit ); + extend( exports, QUnit.constructor.prototype ); } // get at whatever the global object is, like window in browsers