Paladox has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/154029

Change subject: Update QUnit to 1.15.0
......................................................................

Update QUnit to 1.15.0

Change-Id: I4c0068dd0754f74172f89453251726cd1a21fc68
---
M resources/lib/jquery/jquery.qunit.css
M resources/lib/jquery/jquery.qunit.js
2 files changed, 1,140 insertions(+), 933 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/29/154029/1

diff --git a/resources/lib/jquery/jquery.qunit.css 
b/resources/lib/jquery/jquery.qunit.css
index 93026e3..9437b4b 100644
--- a/resources/lib/jquery/jquery.qunit.css
+++ b/resources/lib/jquery/jquery.qunit.css
@@ -1,12 +1,12 @@
 /*!
- * QUnit 1.14.0
+ * QUnit 1.15.0
  * http://qunitjs.com/
  *
- * Copyright 2013 jQuery Foundation and other contributors
+ * Copyright 2014 jQuery Foundation and other contributors
  * Released under the MIT license
  * http://jquery.org/license
  *
- * Date: 2014-01-31T16:40Z
+ * Date: 2014-08-08T16:00Z
  */
 
 /** Font Family and Sizes */
@@ -62,14 +62,14 @@
 }
 
 #qunit-testrunner-toolbar {
-       padding: 0.5em 0 0.5em 2em;
+       padding: 0.5em 1em 0.5em 1em;
        color: #5E740B;
        background-color: #EEE;
        overflow: hidden;
 }
 
 #qunit-userAgent {
-       padding: 0.5em 0 0.5em 2.5em;
+       padding: 0.5em 1em 0.5em 1em;
        background-color: #2B81AF;
        color: #FFF;
        text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
@@ -86,7 +86,7 @@
 }
 
 #qunit-tests li {
-       padding: 0.4em 0.5em 0.4em 2.5em;
+       padding: 0.4em 1em 0.4em 1em;
        border-bottom: 1px solid #FFF;
        list-style-position: inside;
 }
@@ -215,7 +215,7 @@
 /** Result */
 
 #qunit-testresult {
-       padding: 0.5em 0.5em 0.5em 2.5em;
+       padding: 0.5em 1em 0.5em 1em;
 
        color: #2B81AF;
        background-color: #D2E0E6;
diff --git a/resources/lib/jquery/jquery.qunit.js 
b/resources/lib/jquery/jquery.qunit.js
index 0e279fd..474cfe5 100644
--- a/resources/lib/jquery/jquery.qunit.js
+++ b/resources/lib/jquery/jquery.qunit.js
@@ -1,26 +1,27 @@
 /*!
- * QUnit 1.14.0
+ * QUnit 1.15.0
  * http://qunitjs.com/
  *
- * Copyright 2013 jQuery Foundation and other contributors
+ * Copyright 2014 jQuery Foundation and other contributors
  * Released under the MIT license
  * http://jquery.org/license
  *
- * Date: 2014-01-31T16:40Z
+ * Date: 2014-08-08T16:00Z
  */
 
 (function( window ) {
 
 var QUnit,
-       assert,
        config,
        onErrorFnPrev,
-       testId = 0,
-       fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, 
"").replace(/.+\//, ""),
+       fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, 
"" ).replace( /.+\//, "" ),
        toString = Object.prototype.toString,
        hasOwn = Object.prototype.hasOwnProperty,
        // Keep a local reference to Date (GH-283)
        Date = window.Date,
+       now = Date.now || function() {
+               return new Date().getTime();
+       },
        setTimeout = window.setTimeout,
        clearTimeout = window.clearTimeout,
        defined = {
@@ -32,7 +33,7 @@
                                sessionStorage.setItem( x, x );
                                sessionStorage.removeItem( x );
                                return true;
-                       } catch( e ) {
+                       } catch ( e ) {
                                return false;
                        }
                }())
@@ -74,19 +75,16 @@
         * @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;
+                               val = obj[ key ];
+                               vals[ key ] = val === Object( val ) ? 
objectValues( val ) : val;
                        }
                }
                return vals;
        };
-
 
 // Root QUnit object.
 // `QUnit` initialized at top of scope
@@ -96,7 +94,7 @@
        module: function( name, testEnvironment ) {
                config.currentModule = name;
                config.currentModuleTestEnvironment = testEnvironment;
-               config.modules[name] = true;
+               config.modules[ name ] = true;
        },
 
        asyncTest: function( testName, expected, callback ) {
@@ -109,20 +107,14 @@
        },
 
        test: function( testName, expected, callback, async ) {
-               var test,
-                       nameHtml = "<span class='test-name'>" + escapeText( 
testName ) + "</span>";
+               var test;
 
                if ( arguments.length === 2 ) {
                        callback = expected;
                        expected = null;
                }
 
-               if ( config.currentModule ) {
-                       nameHtml = "<span class='module-name'>" + escapeText( 
config.currentModule ) + "</span>: " + nameHtml;
-               }
-
                test = new Test({
-                       nameHtml: nameHtml,
                        testName: testName,
                        expected: expected,
                        async: async,
@@ -139,16 +131,9 @@
                test.queue();
        },
 
-       // 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;
-               } else {
-                       return config.current.expected;
-               }
-       },
-
        start: function( count ) {
+               var message;
+
                // QUnit hasn't been initialized yet.
                // Note: RequireJS (et al) may delay onLoad
                if ( config.semaphore === undefined ) {
@@ -166,10 +151,21 @@
                if ( config.semaphore > 0 ) {
                        return;
                }
+
+               // Set the starting time when the first test is run
+               QUnit.config.started = QUnit.config.started || now();
                // 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) 
);
+
+                       message = "Called start() while already started 
(QUnit.config.semaphore was 0 already)";
+
+                       if ( config.current ) {
+                               QUnit.pushFailure( message, 
sourceFromStacktrace( 2 ) );
+                       } else {
+                               throw new Error( message );
+                       }
+
                        return;
                }
                // A slight delay, to avoid any current callbacks
@@ -184,7 +180,7 @@
 
                                config.blocking = false;
                                process( true );
-                       }, 13);
+                       }, 13 );
                } else {
                        config.blocking = false;
                        process( true );
@@ -212,6 +208,7 @@
        function F() {}
        F.prototype = QUnit;
        QUnit = new F();
+
        // Make F QUnit's constructor so that we can add to the prototype later
        QUnit.constructor = F;
 }());
@@ -263,14 +260,7 @@
        // Set of all modules.
        modules: {},
 
-       // logging callback queues
-       begin: [],
-       done: [],
-       log: [],
-       testStart: [],
-       testDone: [],
-       moduleStart: [],
-       moduleDone: []
+       callbacks: {}
 };
 
 // Initialize more QUnit.config and QUnit.urlParams
@@ -323,71 +313,6 @@
 
        config: config,
 
-       // Initialize the configuration options
-       init: function() {
-               extend( config, {
-                       stats: { all: 0, bad: 0 },
-                       moduleStats: { all: 0, bad: 0 },
-                       started: +new Date(),
-                       updateRate: 1000,
-                       blocking: false,
-                       autostart: true,
-                       autorun: false,
-                       filter: "",
-                       queue: [],
-                       semaphore: 1
-               });
-
-               var tests, banner, result,
-                       qunit = id( "qunit" );
-
-               if ( qunit ) {
-                       qunit.innerHTML =
-                               "<h1 id='qunit-header'>" + escapeText( 
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 ) {
-                       tests.innerHTML = "";
-               }
-
-               if ( banner ) {
-                       banner.className = "";
-               }
-
-               if ( result ) {
-                       result.parentNode.removeChild( result );
-               }
-
-               if ( tests ) {
-                       result = document.createElement( "p" );
-                       result.id = "qunit-testresult";
-                       result.className = "result";
-                       tests.parentNode.insertBefore( result, tests );
-                       result.innerHTML = "Running...<br/>&nbsp;";
-               }
-       },
-
-       // 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 ) {
-                       fixture.innerHTML = config.fixture;
-               }
-       },
-
        // Safe object type checking
        is: function( type, obj ) {
                return QUnit.objectType( obj ) === type;
@@ -403,12 +328,12 @@
                        return "null";
                }
 
-               var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
-                       type = match && match[1] || "";
+               var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ),
+                       type = match && match[ 1 ] || "";
 
                switch ( type ) {
                        case "Number":
-                               if ( isNaN(obj) ) {
+                               if ( isNaN( obj ) ) {
                                        return "nan";
                                }
                                return "number";
@@ -426,91 +351,6 @@
                return undefined;
        },
 
-       push: function( result, actual, expected, message ) {
-               if ( !config.current ) {
-                       throw new Error( "assertion outside test context, was " 
+ sourceFromStacktrace() );
-               }
-
-               var output, source,
-                       details = {
-                               module: config.current.module,
-                               name: config.current.testName,
-                               result: result,
-                               message: message,
-                               actual: actual,
-                               expected: expected
-                       };
-
-               message = escapeText( message ) || ( result ? "okay" : "failed" 
);
-               message = "<span class='test-message'>" + message + "</span>";
-               output = message;
-
-               if ( !result ) {
-                       expected = escapeText( QUnit.jsDump.parse(expected) );
-                       actual = escapeText( 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>" + escapeText( source ) + "</pre></td></tr>";
-                       }
-
-                       output += "</table>";
-               }
-
-               runLoggingCallbacks( "log", QUnit, details );
-
-               config.current.assertions.push({
-                       result: !!result,
-                       message: output
-               });
-       },
-
-       pushFailure: function( message, source, actual ) {
-               if ( !config.current ) {
-                       throw new Error( "pushFailure() assertion outside test 
context, was " + sourceFromStacktrace(2) );
-               }
-
-               var output,
-                       details = {
-                               module: config.current.module,
-                               name: config.current.testName,
-                               result: false,
-                               message: message
-                       };
-
-               message = escapeText( message ) || "error";
-               message = "<span class='test-message'>" + message + "</span>";
-               output = message;
-
-               output += "<table>";
-
-               if ( actual ) {
-                       output += "<tr class='test-actual'><th>Result: 
</th><td><pre>" + escapeText( actual ) + "</pre></td></tr>";
-               }
-
-               if ( source ) {
-                       details.source = source;
-                       output += "<tr class='test-source'><th>Source: 
</th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
-               }
-
-               output += "</table>";
-
-               runLoggingCallbacks( "log", QUnit, details );
-
-               config.current.assertions.push({
-                       result: false,
-                       message: output
-               });
-       },
-
        url: function( params ) {
                params = extend( extend( {}, QUnit.urlParams ), params );
                var key,
@@ -526,13 +366,7 @@
                        window.location.pathname + querystring.slice( 0, -1 );
        },
 
-       extend: extend,
-       id: id,
-       addEvent: addEvent,
-       addClass: addClass,
-       hasClass: hasClass,
-       removeClass: removeClass
-       // load, equiv, jsDump, diff: Attached later
+       extend: extend
 });
 
 /**
@@ -567,214 +401,28 @@
        moduleDone: registerLoggingCallback( "moduleDone" )
 });
 
-if ( !defined.document || document.readyState === "complete" ) {
-       config.autorun = true;
-}
-
 QUnit.load = function() {
-       runLoggingCallbacks( "begin", QUnit, {} );
+       runLoggingCallbacks( "begin", {
+               totalTests: Test.count
+       });
 
-       // Initialize the config, saving the execution queue
-       var banner, filter, i, j, label, len, main, ol, toolbar, val, selection,
-               urlConfigContainer, moduleFilter, userAgent,
-               numModules = 0,
-               moduleNames = [],
-               moduleFilterHtml = "",
-               urlConfigHtml = "",
-               oldconfig = extend( {}, config );
-
-       QUnit.init();
-       extend(config, oldconfig);
+       // Initialize the configuration options
+       extend( config, {
+               stats: { all: 0, bad: 0 },
+               moduleStats: { all: 0, bad: 0 },
+               started: 0,
+               updateRate: 1000,
+               autostart: true,
+               filter: "",
+               semaphore: 1
+       }, true );
 
        config.blocking = false;
-
-       len = config.urlConfig.length;
-
-       for ( i = 0; i < len; i++ ) {
-               val = config.urlConfig[i];
-               if ( typeof val === "string" ) {
-                       val = {
-                               id: val,
-                               label: val
-                       };
-               }
-               config[ val.id ] = QUnit.urlParams[ val.id ];
-               if ( !val.value || typeof val.value === "string" ) {
-                       urlConfigHtml += "<input id='qunit-urlconfig-" + 
escapeText( val.id ) +
-                               "' name='" + escapeText( val.id ) +
-                               "' type='checkbox'" +
-                               ( val.value ? " value='" + escapeText( 
val.value ) + "'" : "" ) +
-                               ( config[ val.id ] ? " checked='checked'" : "" 
) +
-                               " title='" + escapeText( val.tooltip ) +
-                               "'><label for='qunit-urlconfig-" + escapeText( 
val.id ) +
-                               "' title='" + escapeText( val.tooltip ) + "'>" 
+ val.label + "</label>";
-               } else {
-                       urlConfigHtml += "<label for='qunit-urlconfig-" + 
escapeText( val.id ) +
-                               "' title='" + escapeText( val.tooltip ) +
-                               "'>" + val.label +
-                               ": </label><select id='qunit-urlconfig-" + 
escapeText( val.id ) +
-                               "' name='" + escapeText( val.id ) +
-                               "' title='" + escapeText( val.tooltip ) +
-                               "'><option></option>";
-                       selection = false;
-                       if ( QUnit.is( "array", val.value ) ) {
-                               for ( j = 0; j < val.value.length; j++ ) {
-                                       urlConfigHtml += "<option value='" + 
escapeText( val.value[j] ) + "'" +
-                                               ( config[ val.id ] === 
val.value[j] ?
-                                                       (selection = true) && " 
selected='selected'" :
-                                                       "" ) +
-                                               ">" + escapeText( val.value[j] 
) + "</option>";
-                               }
-                       } else {
-                               for ( j in val.value ) {
-                                       if ( hasOwn.call( val.value, j ) ) {
-                                               urlConfigHtml += "<option 
value='" + escapeText( j ) + "'" +
-                                                       ( config[ val.id ] === 
j ?
-                                                               (selection = 
true) && " selected='selected'" :
-                                                               "" ) +
-                                                       ">" + escapeText( 
val.value[j] ) + "</option>";
-                                       }
-                               }
-                       }
-                       if ( config[ val.id ] && !selection ) {
-                               urlConfigHtml += "<option value='" + 
escapeText( config[ val.id ] ) +
-                                       "' selected='selected' 
disabled='disabled'>" +
-                                       escapeText( config[ val.id ] ) +
-                                       "</option>";
-                       }
-                       urlConfigHtml += "</select>";
-               }
-       }
-       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 += "<label for='qunit-modulefilter'>Module: 
</label><select id='qunit-modulefilter' name='modulefilter'><option value='' " +
-               ( config.module === undefined  ? "selected='selected'" : "" ) +
-               ">< All Modules ></option>";
-
-
-       for ( i = 0; i < numModules; i++) {
-                       moduleFilterHtml += "<option value='" + escapeText( 
encodeURIComponent(moduleNames[i]) ) + "' " +
-                               ( config.module === moduleNames[i] ? 
"selected='selected'" : "" ) +
-                               ">" + escapeText(moduleNames[i]) + "</option>";
-       }
-       moduleFilterHtml += "</select>";
-
-       // `userAgent` initialized at top of scope
-       userAgent = id( "qunit-userAgent" );
-       if ( userAgent ) {
-               userAgent.innerHTML = navigator.userAgent;
-       }
-
-       // `banner` initialized at top of scope
-       banner = id( "qunit-header" );
-       if ( banner ) {
-               banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined, 
module: undefined, testNumber: undefined }) + "'>" + banner.innerHTML + "</a> ";
-       }
-
-       // `toolbar` initialized at top of scope
-       toolbar = id( "qunit-testrunner-toolbar" );
-       if ( toolbar ) {
-               // `filter` initialized at top of scope
-               filter = document.createElement( "input" );
-               filter.type = "checkbox";
-               filter.id = "qunit-filter-pass";
-
-               addEvent( filter, "click", function() {
-                       var tmp,
-                               ol = id( "qunit-tests" );
-
-                       if ( filter.checked ) {
-                               ol.className = ol.className + " hidepass";
-                       } else {
-                               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" );
-                               } else {
-                                       sessionStorage.removeItem( 
"qunit-filter-passed-tests" );
-                               }
-                       }
-               });
-
-               if ( config.hidepassed || defined.sessionStorage && 
sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
-                       filter.checked = true;
-                       // `ol` initialized at top of scope
-                       ol = id( "qunit-tests" );
-                       ol.className = ol.className + " hidepass";
-               }
-               toolbar.appendChild( filter );
-
-               // `label` initialized at top of scope
-               label = document.createElement( "label" );
-               label.setAttribute( "for", "qunit-filter-pass" );
-               label.setAttribute( "title", "Only show tests and assertions 
that fail. Stored in sessionStorage." );
-               label.innerHTML = "Hide passed tests";
-               toolbar.appendChild( label );
-
-               urlConfigContainer = document.createElement("span");
-               urlConfigContainer.innerHTML = urlConfigHtml;
-               // For oldIE support:
-               // * Add handlers to the individual elements instead of the 
container
-               // * Use "click" instead of "change" for checkboxes
-               // * Fallback from event.target to event.srcElement
-               addEvents( urlConfigContainer.getElementsByTagName("input"), 
"click", function( event ) {
-                       var params = {},
-                               target = event.target || event.srcElement;
-                       params[ target.name ] = target.checked ?
-                               target.defaultValue || true :
-                               undefined;
-                       window.location = QUnit.url( params );
-               });
-               addEvents( urlConfigContainer.getElementsByTagName("select"), 
"change", function( event ) {
-                       var params = {},
-                               target = event.target || event.srcElement;
-                       params[ target.name ] = target.options[ 
target.selectedIndex ].value || undefined;
-                       window.location = QUnit.url( params );
-               });
-               toolbar.appendChild( urlConfigContainer );
-
-               if (numModules > 1) {
-                       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,
-                                       // Remove any existing filters
-                                       filter: undefined,
-                                       testNumber: undefined
-                               });
-                       });
-                       toolbar.appendChild(moduleFilter);
-               }
-       }
-
-       // `main` initialized at top of scope
-       main = id( "qunit-fixture" );
-       if ( main ) {
-               config.fixture = main.innerHTML;
-       }
 
        if ( config.autostart ) {
                QUnit.start();
        }
 };
-
-if ( defined.document ) {
-       addEvent( window, "load", QUnit.load );
-}
 
 // `onErrorFnPrev` initialized at top of scope
 // Preserve other handlers
@@ -783,7 +431,7 @@
 // Cover uncaught exceptions
 // Returning true will suppress the default browser handler,
 // returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
+window.onerror = function( error, filePath, linerNr ) {
        var ret = false;
        if ( onErrorFnPrev ) {
                ret = onErrorFnPrev( error, filePath, linerNr );
@@ -798,7 +446,7 @@
                        }
                        QUnit.pushFailure( error, filePath + ":" + linerNr );
                } else {
-                       QUnit.test( "global failure", extend( function() {
+                       QUnit.test( "global failure", extend(function() {
                                QUnit.pushFailure( error, filePath + ":" + 
linerNr );
                        }, { validTest: validTest } ) );
                }
@@ -813,7 +461,7 @@
 
        // Log the last module results
        if ( config.previousModule ) {
-               runLoggingCallbacks( "moduleDone", QUnit, {
+               runLoggingCallbacks( "moduleDone", {
                        name: config.previousModule,
                        failed: config.moduleStats.bad,
                        passed: config.moduleStats.all - config.moduleStats.bad,
@@ -822,58 +470,10 @@
        }
        delete config.previousModule;
 
-       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 ",
-                       runtime,
-                       " milliseconds.<br/>",
-                       "<span class='passed'>",
-                       passed,
-                       "</span> assertions of <span class='total'>",
-                       config.stats.all,
-                       "</span> passed, <span class='failed'>",
-                       config.stats.bad,
-                       "</span> failed."
-               ].join( "" );
+       var runtime = now() - config.started,
+               passed = config.stats.all - config.stats.bad;
 
-       if ( banner ) {
-               banner.className = ( config.stats.bad ? "qunit-fail" : 
"qunit-pass" );
-       }
-
-       if ( tests ) {
-               id( "qunit-testresult" ).innerHTML = html;
-       }
-
-       if ( config.altertitle && defined.document && document.title ) {
-               // show ✖ for good, ✔ for bad suite result in title
-               // use escape sequences in case file gets loaded with 
non-utf-8-charset
-               document.title = [
-                       ( config.stats.bad ? "\u2716" : "\u2714" ),
-                       document.title.replace( /^[\u2714\u2716] /i, "" )
-               ].join( " " );
-       }
-
-       // 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 );
-                       }
-               }
-       }
-
-       // scroll back to top to show results
-       if ( config.scrolltop && window.scrollTo ) {
-               window.scrollTo(0, 0);
-       }
-
-       runLoggingCallbacks( "done", QUnit, {
+       runLoggingCallbacks( "done", {
                failed: config.stats.bad,
                passed: passed,
                total: config.stats.all,
@@ -922,21 +522,22 @@
        return !include;
 }
 
-// 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
+// Doesn't support IE6 to IE9
 // See also 
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
 function extractStacktrace( e, offset ) {
-       offset = offset === undefined ? 3 : offset;
+       offset = offset === undefined ? 4 : offset;
 
        var stack, include, i;
 
        if ( e.stacktrace ) {
-               // Opera
+
+               // Opera 12.x
                return e.stacktrace.split( "\n" )[ offset + 3 ];
        } else if ( e.stack ) {
-               // Firefox, Chrome
+
+               // Firefox, Chrome, Safari 6+, IE10+, PhantomJS and Node
                stack = e.stack.split( "\n" );
-               if (/^error$/i.test( stack[0] ) ) {
+               if ( /^error$/i.test( stack[ 0 ] ) ) {
                        stack.shift();
                }
                if ( fileName ) {
@@ -953,12 +554,13 @@
                }
                return stack[ offset ];
        } else if ( e.sourceURL ) {
-               // Safari, PhantomJS
-               // hopefully one day Safari provides actual stacktraces
+
+               // Safari < 6
                // 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;
        }
@@ -969,31 +571,6 @@
        } catch ( e ) {
                return extractStacktrace( e, offset );
        }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
-       if ( !s ) {
-               return "";
-       }
-       s = s + "";
-       // Both single quotes and double quotes (for attributes)
-       return s.replace( /['"<>&]/g, function( s ) {
-               switch( s ) {
-                       case "'":
-                               return "&#039;";
-                       case "\"":
-                               return "&quot;";
-                       case "<":
-                               return "&lt;";
-                       case ">":
-                               return "&gt;";
-                       case "&":
-                               return "&amp;";
-               }
-       });
 }
 
 function synchronize( callback, last ) {
@@ -1008,11 +585,11 @@
        function next() {
                process( last );
        }
-       var start = new Date().getTime();
+       var start = now();
        config.depth = config.depth ? config.depth + 1 : 1;
 
        while ( config.queue.length && !config.blocking ) {
-               if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new 
Date().getTime() - start ) < config.updateRate ) ) {
+               if ( !defined.setTimeout || config.updateRate <= 0 || ( ( now() 
- start ) < config.updateRate ) ) {
                        config.queue.shift()();
                } else {
                        setTimeout( next, 13 );
@@ -1050,12 +627,12 @@
 
        newGlobals = diff( config.pollution, old );
        if ( newGlobals.length > 0 ) {
-               QUnit.pushFailure( "Introduced global variable(s): " + 
newGlobals.join(", ") );
+               QUnit.pushFailure( "Introduced global variable(s): " + 
newGlobals.join( ", " ) );
        }
 
        deletedGlobals = diff( old, config.pollution );
        if ( deletedGlobals.length > 0 ) {
-               QUnit.pushFailure( "Deleted global variable(s): " + 
deletedGlobals.join(", ") );
+               QUnit.pushFailure( "Deleted global variable(s): " + 
deletedGlobals.join( ", " ) );
        }
 }
 
@@ -1066,7 +643,7 @@
 
        for ( i = 0; i < result.length; i++ ) {
                for ( j = 0; j < b.length; j++ ) {
-                       if ( result[i] === b[j] ) {
+                       if ( result[ i ] === b[ j ] ) {
                                result.splice( i, 1 );
                                i--;
                                break;
@@ -1076,14 +653,15 @@
        return result;
 }
 
-function extend( a, b ) {
+function extend( a, b, undefOnly ) {
        for ( var prop in b ) {
                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 {
+                               } else if ( !( undefOnly && typeof a[ prop ] 
!== "undefined" ) ) {
                                        a[ prop ] = b[ prop ];
                                }
                        }
@@ -1093,79 +671,24 @@
        return a;
 }
 
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
-       if ( elem.addEventListener ) {
-
-               // Standards-based browsers
-               elem.addEventListener( type, fn, false );
-       } else if ( elem.attachEvent ) {
-
-               // support: IE <9
-               elem.attachEvent( "on" + type, fn );
-       } else {
-
-               // Caller must ensure support for event listeners is present
-               throw new Error( "addEvent() was called in a context without 
event listener support" );
-       }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
-       var i = elems.length;
-       while ( i-- ) {
-               addEvent( elems[i], type, fn );
-       }
-}
-
-function hasClass( elem, name ) {
-       return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
-       if ( !hasClass( elem, name ) ) {
-               elem.className += (elem.className ? " " : "") + name;
-       }
-}
-
-function removeClass( elem, name ) {
-       var set = " " + elem.className + " ";
-       // Class name may appear multiple times
-       while ( set.indexOf(" " + name + " ") > -1 ) {
-               set = set.replace(" " + name + " " , " ");
-       }
-       // 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 ) {
-       return defined.document && document.getElementById && 
document.getElementById( name );
-}
-
 function registerLoggingCallback( key ) {
+
+       // Initialize key collection of logging callback
+       if ( QUnit.objectType( config.callbacks[ key ] ) === "undefined" ) {
+               config.callbacks[ key ] = [];
+       }
+
        return function( callback ) {
-               config[key].push( callback );
+               config.callbacks[ key ].push( callback );
        };
 }
 
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
-       var i, callbacks;
-       if ( QUnit.hasOwnProperty( key ) ) {
-               QUnit[ key ].call(scope, args );
-       } else {
-               callbacks = config[ key ];
-               for ( i = 0; i < callbacks.length; i++ ) {
-                       callbacks[ i ].call( scope, args );
-               }
+function runLoggingCallbacks( key, args ) {
+       var i, l, callbacks;
+
+       callbacks = config.callbacks[ key ];
+       for ( i = 0, l = callbacks.length; i < l; i++ ) {
+               callbacks[ i ]( args );
        }
 }
 
@@ -1186,6 +709,7 @@
 
 function Test( settings ) {
        extend( this, settings );
+       this.assert = new Assert( this );
        this.assertions = [];
        this.testNumber = ++Test.count;
 }
@@ -1193,32 +717,12 @@
 Test.count = 0;
 
 Test.prototype = {
-       init: function() {
-               var a, b, li,
-                       tests = id( "qunit-tests" );
-
-               if ( tests ) {
-                       b = document.createElement( "strong" );
-                       b.innerHTML = this.nameHtml;
-
-                       // `a` initialized at top of scope
-                       a = document.createElement( "a" );
-                       a.innerHTML = "Rerun";
-                       a.href = QUnit.url({ testNumber: this.testNumber });
-
-                       li = document.createElement( "li" );
-                       li.appendChild( b );
-                       li.appendChild( a );
-                       li.className = "running";
-                       li.id = this.id = "qunit-test-output" + testId++;
-
-                       tests.appendChild( li );
-               }
-       },
        setup: function() {
                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'.
@@ -1226,7 +730,7 @@
                                !hasOwn.call( config, "previousModule" )
                ) {
                        if ( hasOwn.call( config, "previousModule" ) ) {
-                               runLoggingCallbacks( "moduleDone", QUnit, {
+                               runLoggingCallbacks( "moduleDone", {
                                        name: config.previousModule,
                                        failed: config.moduleStats.bad,
                                        passed: config.moduleStats.all - 
config.moduleStats.bad,
@@ -1235,7 +739,7 @@
                        }
                        config.previousModule = this.module;
                        config.moduleStats = { all: 0, bad: 0 };
-                       runLoggingCallbacks( "moduleStart", QUnit, {
+                       runLoggingCallbacks( "moduleStart", {
                                name: this.module
                        });
                }
@@ -1247,65 +751,49 @@
                        teardown: function() {}
                }, this.moduleTestEnvironment );
 
-               this.started = +new Date();
-               runLoggingCallbacks( "testStart", QUnit, {
+               this.started = now();
+               runLoggingCallbacks( "testStart", {
                        name: this.testName,
-                       module: this.module
+                       module: this.module,
+                       testNumber: this.testNumber
                });
-
-               /*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, 
QUnit.assert );
+                       this.testEnvironment.setup.call( this.testEnvironment, 
this.assert );
                        return;
                }
                try {
-                       this.testEnvironment.setup.call( this.testEnvironment, 
QUnit.assert );
-               } catch( e ) {
-                       QUnit.pushFailure( "Setup failed on " + this.testName + 
": " + ( e.message || e ), extractStacktrace( e, 1 ) );
+                       this.testEnvironment.setup.call( this.testEnvironment, 
this.assert );
+               } catch ( e ) {
+                       this.pushFailure( "Setup failed on " + this.testName + 
": " + ( e.message || e ), extractStacktrace( e, 0 ) );
                }
        },
        run: function() {
                config.current = this;
 
-               var running = id( "qunit-testresult" );
-
-               if ( running ) {
-                       running.innerHTML = "Running: <br/>" + this.nameHtml;
-               }
-
                if ( this.async ) {
                        QUnit.stop();
                }
 
-               this.callbackStarted = +new Date();
+               this.callbackStarted = now();
 
                if ( config.notrycatch ) {
-                       this.callback.call( this.testEnvironment, QUnit.assert 
);
-                       this.callbackRuntime = +new Date() - 
this.callbackStarted;
+                       this.callback.call( this.testEnvironment, this.assert );
+                       this.callbackRuntime = now() - this.callbackStarted;
                        return;
                }
 
                try {
-                       this.callback.call( this.testEnvironment, QUnit.assert 
);
-                       this.callbackRuntime = +new Date() - 
this.callbackStarted;
-               } catch( e ) {
-                       this.callbackRuntime = +new Date() - 
this.callbackStarted;
+                       this.callback.call( this.testEnvironment, this.assert );
+                       this.callbackRuntime = now() - this.callbackStarted;
+               } catch ( e ) {
+                       this.callbackRuntime = now() - this.callbackStarted;
 
-                       QUnit.pushFailure( "Died on test #" + 
(this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), 
extractStacktrace( e, 0 ) );
+                       this.pushFailure( "Died on test #" + ( 
this.assertions.length + 1 ) + " " + this.stack + ": " + ( e.message || e ), 
extractStacktrace( e, 0 ) );
+
                        // else next test will carry the responsibility
                        saveGlobal();
 
@@ -1319,15 +807,15 @@
                config.current = this;
                if ( config.notrycatch ) {
                        if ( typeof this.callbackRuntime === "undefined" ) {
-                               this.callbackRuntime = +new Date() - 
this.callbackStarted;
+                               this.callbackRuntime = now() - 
this.callbackStarted;
                        }
-                       this.testEnvironment.teardown.call( 
this.testEnvironment, QUnit.assert );
+                       this.testEnvironment.teardown.call( 
this.testEnvironment, this.assert );
                        return;
                } else {
                        try {
-                               this.testEnvironment.teardown.call( 
this.testEnvironment, QUnit.assert );
-                       } catch( e ) {
-                               QUnit.pushFailure( "Teardown failed on " + 
this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
+                               this.testEnvironment.teardown.call( 
this.testEnvironment, this.assert );
+                       } catch ( e ) {
+                               this.pushFailure( "Teardown failed on " + 
this.testName + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
                        }
                }
                checkPollution();
@@ -1335,114 +823,43 @@
        finish: function() {
                config.current = this;
                if ( config.requireExpects && this.expected === null ) {
-                       QUnit.pushFailure( "Expected number of assertions to be 
defined, but expect() was not called.", this.stack );
+                       this.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 ) {
-                       QUnit.pushFailure( "Expected " + this.expected + " 
assertions, but " + this.assertions.length + " were run", this.stack );
+                       this.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 );
+                       this.pushFailure( "Expected at least one assertion, but 
none were run - call expect(0) to accept zero assertions.", this.stack );
                }
 
-               var i, assertion, a, b, time, li, ol,
-                       test = this,
-                       good = 0,
-                       bad = 0,
-                       tests = id( "qunit-tests" );
+               var i,
+                       bad = 0;
 
-               this.runtime = +new Date() - this.started;
+               this.runtime = now() - 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];
-
-                               li = document.createElement( "li" );
-                               li.className = assertion.result ? "pass" : 
"fail";
-                               li.innerHTML = assertion.message || ( 
assertion.result ? "okay" : "failed" );
-                               ol.appendChild( li );
-
-                               if ( assertion.result ) {
-                                       good++;
-                               } else {
-                                       bad++;
-                                       config.stats.bad++;
-                                       config.moduleStats.bad++;
-                               }
-                       }
-
-                       // store result when possible
-                       if ( QUnit.config.reorder && defined.sessionStorage ) {
-                               if ( bad ) {
-                                       sessionStorage.setItem( "qunit-test-" + 
this.module + "-" + this.testName, bad );
-                               } else {
-                                       sessionStorage.removeItem( 
"qunit-test-" + this.module + "-" + this.testName );
-                               }
-                       }
-
-                       if ( bad === 0 ) {
-                               addClass( ol, "qunit-collapsed" );
-                       }
-
-                       // `b` initialized at top of scope
-                       b = document.createElement( "strong" );
-                       b.innerHTML = this.nameHtml + " <b class='counts'>(<b 
class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + 
this.assertions.length + ")</b>";
-
-                       addEvent(b, "click", function() {
-                               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" ) {
-                                       target = target.parentNode;
-                               }
-                               if ( window.location && 
target.nodeName.toLowerCase() === "strong" ) {
-                                       window.location = QUnit.url({ 
testNumber: test.testNumber });
-                               }
-                       });
-
-                       // `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( time );
-                       li.appendChild( ol );
-
-               } else {
-                       for ( i = 0; i < this.assertions.length; i++ ) {
-                               if ( !this.assertions[i].result ) {
-                                       bad++;
-                                       config.stats.bad++;
-                                       config.moduleStats.bad++;
-                               }
+               for ( i = 0; i < this.assertions.length; i++ ) {
+                       if ( !this.assertions[ i ].result ) {
+                               bad++;
+                               config.stats.bad++;
+                               config.moduleStats.bad++;
                        }
                }
 
-               runLoggingCallbacks( "testDone", QUnit, {
+               runLoggingCallbacks( "testDone", {
                        name: this.testName,
                        module: this.module,
                        failed: bad,
                        passed: this.assertions.length - bad,
                        total: this.assertions.length,
                        runtime: this.runtime,
+
+                       // HTML Reporter use
+                       assertions: this.assertions,
+                       testNumber: this.testNumber,
+
                        // DEPRECATED: this property will be removed in 2.0.0, 
use runtime instead
                        duration: this.runtime
                });
-
-               QUnit.reset();
 
                config.current = undefined;
        },
@@ -1451,9 +868,6 @@
                var bad,
                        test = this;
 
-               synchronize(function() {
-                       test.init();
-               });
                function run() {
                        // each of these can by async
                        synchronize(function() {
@@ -1473,59 +887,129 @@
                // `bad` initialized at top of scope
                // defer when previous test run passed, if storage is available
                bad = QUnit.config.reorder && defined.sessionStorage &&
-                                               +sessionStorage.getItem( 
"qunit-test-" + this.module + "-" + this.testName );
+                               +sessionStorage.getItem( "qunit-test-" + 
this.module + "-" + this.testName );
 
                if ( bad ) {
                        run();
                } else {
                        synchronize( run, true );
                }
+       },
+
+       push: function( result, actual, expected, message ) {
+               var source,
+                       details = {
+                               module: this.module,
+                               name: this.testName,
+                               result: result,
+                               message: message,
+                               actual: actual,
+                               expected: expected,
+                               testNumber: this.testNumber
+                       };
+
+               if ( !result ) {
+                       source = sourceFromStacktrace();
+
+                       if ( source ) {
+                               details.source = source;
+                       }
+               }
+
+               runLoggingCallbacks( "log", details );
+
+               this.assertions.push({
+                       result: !!result,
+                       message: message
+               });
+       },
+
+       pushFailure: function( message, source, actual ) {
+               if ( !this instanceof Test ) {
+                       throw new Error( "pushFailure() assertion outside test 
context, was " + sourceFromStacktrace( 2 ) );
+               }
+
+               var details = {
+                               module: this.module,
+                               name: this.testName,
+                               result: false,
+                               message: message || "error",
+                               actual: actual || null,
+                               testNumber: this.testNumber
+                       };
+
+               if ( source ) {
+                       details.source = source;
+               }
+
+               runLoggingCallbacks( "log", details );
+
+               this.assertions.push({
+                       result: false,
+                       message: message
+               });
        }
 };
 
-// `assert` initialized at top of scope
+QUnit.pushFailure = function() {
+       if ( !QUnit.config.current ) {
+               throw new Error( "pushFailure() assertion outside test context, 
in " + sourceFromStacktrace( 2 ) );
+       }
+
+       // Gets current test obj
+       var currentTest = QUnit.config.current.assert.test;
+
+       return currentTest.pushFailure.apply( currentTest, arguments );
+};
+
+function Assert( testContext ) {
+       this.test = testContext;
+}
+
 // Assert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-assert = QUnit.assert = {
+QUnit.assert = Assert.prototype = {
+
+       // 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 ) {
+                       this.test.expected = asserts;
+               } else {
+                       return this.test.expected;
+               }
+       },
+
+       // Exports test.push() to the user API
+       push: function() {
+               var assert = this;
+
+               // Backwards compatibility fix.
+               // Allows the direct use of global exported assertions and 
QUnit.assert.*
+               // Although, it's use is not recommended as it can leak 
assertions
+               // to other tests from async tests, because we only get a 
reference to the current test,
+               // not exactly the test where assertion were intended to be 
called.
+               if ( !QUnit.config.current ) {
+                       throw new Error( "assertion outside test context, in " 
+ sourceFromStacktrace( 2 ) );
+               }
+               if ( !( assert instanceof Assert ) ) {
+                       assert = QUnit.config.current.assert;
+               }
+               return assert.test.push.apply( assert.test, arguments );
+       },
+
        /**
         * Asserts rough true-ish result.
         * @name ok
         * @function
         * @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) );
+       ok: function( result, message ) {
+               message = message || ( result ? "okay" : "failed, expected 
argument to be truthy, was: " +
+                       QUnit.dump.parse( result ) );
+               if ( !!result ) {
+                       this.push( true, result, true, message );
+               } else {
+                       this.test.pushFailure( message, null, result );
                }
-               result = !!result;
-               msg = msg || ( result ? "okay" : "failed" );
-
-               var source,
-                       details = {
-                               module: config.current.module,
-                               name: config.current.testName,
-                               result: result,
-                               message: msg
-                       };
-
-               msg = "<span class='test-message'>" + escapeText( msg ) + 
"</span>";
-
-               if ( !result ) {
-                       source = sourceFromStacktrace( 2 );
-                       if ( source ) {
-                               details.source = source;
-                               msg += "<table><tr 
class='test-source'><th>Source: </th><td><pre>" +
-                                       escapeText( source ) +
-                                       "</pre></td></tr></table>";
-                       }
-               }
-               runLoggingCallbacks( "log", QUnit, details );
-               config.current.assertions.push({
-                       result: result,
-                       message: msg
-               });
        },
 
        /**
@@ -1537,7 +1021,7 @@
         */
        equal: function( actual, expected, message ) {
                /*jshint eqeqeq:false */
-               QUnit.push( expected == actual, actual, expected, message );
+               this.push( expected == actual, actual, expected, message );
        },
 
        /**
@@ -1546,7 +1030,7 @@
         */
        notEqual: function( actual, expected, message ) {
                /*jshint eqeqeq:false */
-               QUnit.push( expected != actual, actual, expected, message );
+               this.push( expected != actual, actual, expected, message );
        },
 
        /**
@@ -1554,9 +1038,9 @@
         * @function
         */
        propEqual: function( actual, expected, message ) {
-               actual = objectValues(actual);
-               expected = objectValues(expected);
-               QUnit.push( QUnit.equiv(actual, expected), actual, expected, 
message );
+               actual = objectValues( actual );
+               expected = objectValues( expected );
+               this.push( QUnit.equiv( actual, expected ), actual, expected, 
message );
        },
 
        /**
@@ -1564,9 +1048,9 @@
         * @function
         */
        notPropEqual: function( actual, expected, message ) {
-               actual = objectValues(actual);
-               expected = objectValues(expected);
-               QUnit.push( !QUnit.equiv(actual, expected), actual, expected, 
message );
+               actual = objectValues( actual );
+               expected = objectValues( expected );
+               this.push( !QUnit.equiv( actual, expected ), actual, expected, 
message );
        },
 
        /**
@@ -1574,7 +1058,7 @@
         * @function
         */
        deepEqual: function( actual, expected, message ) {
-               QUnit.push( QUnit.equiv(actual, expected), actual, expected, 
message );
+               this.push( QUnit.equiv( actual, expected ), actual, expected, 
message );
        },
 
        /**
@@ -1582,7 +1066,7 @@
         * @function
         */
        notDeepEqual: function( actual, expected, message ) {
-               QUnit.push( !QUnit.equiv(actual, expected), actual, expected, 
message );
+               this.push( !QUnit.equiv( actual, expected ), actual, expected, 
message );
        },
 
        /**
@@ -1590,7 +1074,7 @@
         * @function
         */
        strictEqual: function( actual, expected, message ) {
-               QUnit.push( expected === actual, actual, expected, message );
+               this.push( expected === actual, actual, expected, message );
        },
 
        /**
@@ -1598,89 +1082,65 @@
         * @function
         */
        notStrictEqual: function( actual, expected, message ) {
-               QUnit.push( expected !== actual, actual, expected, message );
+               this.push( expected !== actual, actual, expected, message );
        },
 
        "throws": function( block, expected, message ) {
-               var actual,
+               var actual, expectedType,
                        expectedOutput = expected,
                        ok = false;
 
-               // 'expected' is optional
-               if ( !message && typeof expected === "string" ) {
+               // 'expected' is optional unless doing string comparison
+               if ( message == null && typeof expected === "string" ) {
                        message = expected;
                        expected = null;
                }
 
-               config.current.ignoreGlobalErrors = true;
+               this.test.ignoreGlobalErrors = true;
                try {
-                       block.call( config.current.testEnvironment );
+                       block.call( this.test.testEnvironment );
                } catch (e) {
                        actual = e;
                }
-               config.current.ignoreGlobalErrors = false;
+               this.test.ignoreGlobalErrors = false;
 
                if ( actual ) {
+                       expectedType = QUnit.objectType( expected );
 
                        // we don't want to validate thrown error
                        if ( !expected ) {
                                ok = true;
                                expectedOutput = null;
 
-                       // expected is an Error object
-                       } else if ( expected instanceof Error ) {
-                               ok = actual instanceof Error &&
-                                        actual.name === expected.name &&
-                                        actual.message === expected.message;
-
                        // expected is a regexp
-                       } else if ( QUnit.objectType( expected ) === "regexp" ) 
{
+                       } else if ( expectedType === "regexp" ) {
                                ok = expected.test( errorString( actual ) );
 
                        // expected is a string
-                       } else if ( QUnit.objectType( expected ) === "string" ) 
{
+                       } else if ( expectedType === "string" ) {
                                ok = expected === errorString( actual );
 
-                       // expected is a constructor
-                       } else if ( actual instanceof expected ) {
+                       // expected is a constructor, maybe an Error constructor
+                       } else if ( expectedType === "function" && actual 
instanceof expected ) {
                                ok = true;
 
-                       // expected is a validation function which returns true 
is validation passed
-                       } else if ( expected.call( {}, actual ) === true ) {
+                       // expected is an Error object
+                       } else if ( expectedType === "object" ) {
+                               ok = actual instanceof expected.constructor &&
+                                       actual.name === expected.name &&
+                                       actual.message === expected.message;
+
+                       // expected is a validation function which returns true 
if validation passed
+                       } else if ( expectedType === "function" && 
expected.call( {}, actual ) === true ) {
                                expectedOutput = null;
                                ok = true;
                        }
 
-                       QUnit.push( ok, actual, expectedOutput, message );
+                       this.push( ok, actual, expectedOutput, message );
                } else {
-                       QUnit.pushFailure( message, null, "No exception was 
thrown." );
+                       this.test.pushFailure( message, null, "No exception was 
thrown." );
                }
        }
-};
-
-/**
- * @deprecated since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit.constructor.prototype, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.constructor.prototype.raises = function() {
-       QUnit.push( false, false, false, "QUnit.raises has been deprecated 
since 2012 (fad3c1ea), use QUnit.throws instead" );
-};
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.constructor.prototype.equals = function() {
-       QUnit.push( false, false, false, "QUnit.equals has been deprecated 
since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.constructor.prototype.same = function() {
-       QUnit.push( false, false, false, "QUnit.same has been deprecated since 
2009 (e88049a0), use QUnit.deepEqual instead" );
 };
 
 // Test for equality any JavaScript type.
@@ -1701,22 +1161,26 @@
 
        // the real equiv function
        var innerEquiv,
+
                // stack to decide between skip/abort functions
                callers = [],
+
                // stack to avoiding loops from circular referencing
                parents = [],
                parentsB = [],
 
-               getProto = Object.getPrototypeOf || function ( obj ) {
-                       /*jshint camelcase:false */
+               getProto = Object.getPrototypeOf || function( obj ) {
+                       /* jshint camelcase: false, proto: true */
                        return obj.__proto__;
                },
-               callbacks = (function () {
+               callbacks = (function() {
 
                        // for string, boolean, number and null
                        function useStrictEquality( b, a ) {
+
                                /*jshint eqeqeq:false */
                                if ( b instanceof a.constructor || a instanceof 
b.constructor ) {
+
                                        // to catch short annotation VS 'new' 
annotation of a
                                        // declaration
                                        // e.g. var i = 1;
@@ -1744,10 +1208,13 @@
 
                                "regexp": function( b, a ) {
                                        return QUnit.objectType( b ) === 
"regexp" &&
+
                                                // the regex itself
                                                a.source === b.source &&
+
                                                // and its modifiers
                                                a.global === b.global &&
+
                                                // (gmi) ...
                                                a.ignoreCase === b.ignoreCase &&
                                                a.multiline === b.multiline &&
@@ -1758,7 +1225,7 @@
                                // - abort otherwise,
                                // initial === would have catch identical 
references anyway
                                "function": function() {
-                                       var caller = callers[callers.length - 
1];
+                                       var caller = callers[ callers.length - 
1 ];
                                        return caller !== Object && typeof 
caller !== "undefined";
                                },
 
@@ -1782,10 +1249,10 @@
                                        for ( i = 0; i < len; i++ ) {
                                                loop = false;
                                                for ( j = 0; j < 
parents.length; j++ ) {
-                                                       aCircular = parents[j] 
=== a[i];
-                                                       bCircular = parentsB[j] 
=== b[i];
+                                                       aCircular = parents[ j 
] === a[ i ];
+                                                       bCircular = parentsB[ j 
] === b[ i ];
                                                        if ( aCircular || 
bCircular ) {
-                                                               if ( a[i] === 
b[i] || aCircular && bCircular ) {
+                                                               if ( a[ i ] === 
b[ i ] || aCircular && bCircular ) {
                                                                        loop = 
true;
                                                                } else {
                                                                        
parents.pop();
@@ -1794,7 +1261,7 @@
                                                                }
                                                        }
                                                }
-                                               if ( !loop && !innerEquiv(a[i], 
b[i]) ) {
+                                               if ( !loop && !innerEquiv( a[ i 
], b[ i ] ) ) {
                                                        parents.pop();
                                                        parentsB.pop();
                                                        return false;
@@ -1806,6 +1273,7 @@
                                },
 
                                "object": function( b, a ) {
+
                                        /*jshint forin:false */
                                        var i, j, loop, aCircular, bCircular,
                                                // Default to true
@@ -1816,11 +1284,12 @@
                                        // 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;
+                                               if ( !( ( getProto( a ) === 
null && getProto( b ) === Object.prototype ) ||
+                                                       ( getProto( b ) === 
null && getProto( a ) === Object.prototype ) ) ) {
+                                                       return false;
                                                }
                                        }
 
@@ -1835,10 +1304,10 @@
                                        for ( i in a ) {
                                                loop = false;
                                                for ( j = 0; j < 
parents.length; j++ ) {
-                                                       aCircular = parents[j] 
=== a[i];
-                                                       bCircular = parentsB[j] 
=== b[i];
+                                                       aCircular = parents[ j 
] === a[ i ];
+                                                       bCircular = parentsB[ j 
] === b[ i ];
                                                        if ( aCircular || 
bCircular ) {
-                                                               if ( a[i] === 
b[i] || aCircular && bCircular ) {
+                                                               if ( a[ i ] === 
b[ i ] || aCircular && bCircular ) {
                                                                        loop = 
true;
                                                                } else {
                                                                        eq = 
false;
@@ -1846,8 +1315,8 @@
                                                                }
                                                        }
                                                }
-                                               aProperties.push(i);
-                                               if ( !loop && !innerEquiv(a[i], 
b[i]) ) {
+                                               aProperties.push( i );
+                                               if ( !loop && !innerEquiv( a[ i 
], b[ i ] ) ) {
                                                        eq = false;
                                                        break;
                                                }
@@ -1873,35 +1342,29 @@
                        return true; // end transition
                }
 
-               return (function( 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) ) {
-                               return false; // don't lose time with error 
prone cases
+                                       QUnit.objectType( a ) !== 
QUnit.objectType( b ) ) {
+
+                               // don't lose time with error prone cases
+                               return false;
                        } else {
-                               return bindCallbacks(a, callbacks, [ b, a ]);
+                               return bindCallbacks( a, callbacks, [ b, a ] );
                        }
 
                        // apply transition with (1..n) arguments
-               }( args[0], args[1] ) && innerEquiv.apply( this, args.splice(1, 
args.length - 1 )) );
+               }( args[ 0 ], args[ 1 ] ) ) && innerEquiv.apply( this, 
args.splice( 1, args.length - 1 ) ) );
        };
 
        return innerEquiv;
 }());
 
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link 
{http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
+// Based on jsDump by Ariel Flesler
+// 
http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html
+QUnit.dump = (function() {
        function quote( str ) {
                return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\"";
        }
@@ -1909,42 +1372,43 @@
                return o + "";
        }
        function join( pre, arr, post ) {
-               var s = jsDump.separator(),
-                       base = jsDump.indent(),
-                       inner = jsDump.indent(1);
+               var s = dump.separator(),
+                       base = dump.indent(),
+                       inner = dump.indent( 1 );
                if ( arr.join ) {
                        arr = arr.join( "," + s + inner );
                }
                if ( !arr ) {
                        return pre + post;
                }
-               return [ pre, inner + arr, base + post ].join(s);
+               return [ pre, inner + arr, base + post ].join( s );
        }
        function array( arr, stack ) {
-               var i = arr.length, ret = new Array(i);
+               var i = arr.length,
+                       ret = new Array( i );
                this.up();
                while ( i-- ) {
-                       ret[i] = this.parse( arr[i] , undefined , stack);
+                       ret[ i ] = this.parse( arr[ i ], undefined, stack );
                }
                this.down();
                return join( "[", ret, "]" );
        }
 
        var reName = /^function (\w+)/,
-               jsDump = {
+               dump = {
                        // type is used mostly internally, you can fix a 
(custom)type in advance
                        parse: function( obj, type, stack ) {
-                               stack = stack || [ ];
+                               stack = stack || [];
                                var inStack, res,
-                                       parser = this.parsers[ type || 
this.typeOf(obj) ];
+                                       parser = this.parsers[ type || 
this.typeOf( obj ) ];
 
                                type = typeof parser;
                                inStack = inArray( obj, stack );
 
                                if ( inStack !== -1 ) {
-                                       return "recursion(" + (inStack - 
stack.length) + ")";
+                                       return "recursion(" + ( inStack - 
stack.length ) + ")";
                                }
-                               if ( type === "function" )  {
+                               if ( type === "function" ) {
                                        stack.push( obj );
                                        res = parser.call( this, obj, stack );
                                        stack.pop();
@@ -1958,11 +1422,11 @@
                                        type = "null";
                                } else if ( typeof obj === "undefined" ) {
                                        type = "undefined";
-                               } else if ( QUnit.is( "regexp", obj) ) {
+                               } else if ( QUnit.is( "regexp", obj ) ) {
                                        type = "regexp";
-                               } else if ( QUnit.is( "date", obj) ) {
+                               } else if ( QUnit.is( "date", obj ) ) {
                                        type = "date";
-                               } else if ( QUnit.is( "function", obj) ) {
+                               } else if ( QUnit.is( "function", obj ) ) {
                                        type = "function";
                                } else if ( typeof obj.setInterval !== 
undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === 
"undefined" ) {
                                        type = "window";
@@ -1971,10 +1435,12 @@
                                } 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" ) ) )
+                                       ( 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 if ( obj.constructor === 
Error.prototype.constructor ) {
@@ -1985,7 +1451,7 @@
                                return type;
                        },
                        separator: function() {
-                               return this.multiline ? this.HTML ? "<br />" : 
"\n" : this.HTML ? "&nbsp;" : " ";
+                               return this.multiline ? this.HTML ? "<br />" : 
"\n" : this.HTML ? "&nbsp;" : " ";
                        },
                        // extra can be a number, shortcut for 
increasing-calling-decreasing
                        indent: function( extra ) {
@@ -1996,7 +1462,7 @@
                                if ( this.HTML ) {
                                        chr = chr.replace( /\t/g, "   " 
).replace( / /g, "&nbsp;" );
                                }
-                               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;
@@ -2005,7 +1471,7 @@
                                this.depth -= a || 1;
                        },
                        setParser: function( name, parser ) {
-                               this.parsers[name] = parser;
+                               this.parsers[ name ] = parser;
                        },
                        // The next 3 are exposed so you can use them
                        quote: quote,
@@ -2013,11 +1479,11 @@
                        join: join,
                        //
                        depth: 1,
-                       // This is the list of parsers, to modify them, use 
jsDump.setParser
+                       // This is the list of parsers, to modify them, use 
dump.setParser
                        parsers: {
                                window: "[Window]",
                                document: "[Document]",
-                               error: function(error) {
+                               error: function( error ) {
                                        return "Error(\"" + error.message + 
"\")";
                                },
                                unknown: "[Unknown]",
@@ -2026,51 +1492,61 @@
                                "function": function( fn ) {
                                        var ret = "function",
                                                // functions never have name in 
IE
-                                               name = "name" in fn ? fn.name : 
(reName.exec(fn) || [])[1];
+                                               name = "name" in fn ? fn.name : 
( reName.exec( fn ) || [] )[ 1 ];
 
                                        if ( name ) {
                                                ret += " " + name;
                                        }
                                        ret += "( ";
 
-                                       ret = [ ret, QUnit.jsDump.parse( fn, 
"functionArgs" ), "){" ].join( "" );
-                                       return join( ret, 
QUnit.jsDump.parse(fn,"functionCode" ), "}" );
+                                       ret = [ ret, dump.parse( fn, 
"functionArgs" ), "){" ].join( "" );
+                                       return join( ret, dump.parse( fn, 
"functionCode" ), "}" );
                                },
                                array: array,
                                nodelist: array,
                                "arguments": array,
                                object: function( map, stack ) {
                                        /*jshint forin:false */
-                                       var ret = [ ], keys, key, val, i;
-                                       QUnit.jsDump.up();
+                                       var ret = [], keys, key, val, i, 
nonEnumerableProperties;
+                                       dump.up();
                                        keys = [];
                                        for ( key in map ) {
                                                keys.push( key );
+                                       }
+
+                                       // Some properties are not always 
enumerable on Error objects.
+                                       nonEnumerableProperties = [ "message", 
"name" ];
+                                       for ( i in nonEnumerableProperties ) {
+                                               key = nonEnumerableProperties[ 
i ];
+                                               if ( key in map && !( key in 
keys ) ) {
+                                                       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 ) );
+                                               ret.push( dump.parse( key, 
"key" ) + ": " + dump.parse( val, undefined, stack ) );
                                        }
-                                       QUnit.jsDump.down();
+                                       dump.down();
                                        return join( "{", ret, "}" );
                                },
                                node: function( node ) {
                                        var len, i, val,
-                                               open = QUnit.jsDump.HTML ? 
"&lt;" : "<",
-                                               close = QUnit.jsDump.HTML ? 
"&gt;" : ">",
+                                               open = dump.HTML ? "&lt;" : "<",
+                                               close = dump.HTML ? "&gt;" : 
">",
                                                tag = 
node.nodeName.toLowerCase(),
                                                ret = open + tag,
                                                attrs = node.attributes;
 
                                        if ( attrs ) {
                                                for ( i = 0, len = 
attrs.length; i < len; i++ ) {
-                                                       val = 
attrs[i].nodeValue;
+                                                       val = attrs[ i 
].nodeValue;
+
                                                        // IE6 includes all 
attributes in .attributes, even ones not explicitly set.
                                                        // Those have values 
like undefined, null, 0, false, "" or "inherit".
                                                        if ( val && val !== 
"inherit" ) {
-                                                               ret += " " + 
attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
+                                                               ret += " " + 
attrs[ i ].nodeName + "=" + dump.parse( val, "attribute" );
                                                        }
                                                }
                                        }
@@ -2083,6 +1559,7 @@
 
                                        return ret + open + "/" + tag + close;
                                },
+
                                // function calls it internally, it's the 
arguments part of the function
                                functionArgs: function( fn ) {
                                        var args,
@@ -2092,10 +1569,11 @@
                                                return "";
                                        }
 
-                                       args = new Array(l);
+                                       args = new Array( l );
                                        while ( l-- ) {
+
                                                // 97 is 'a'
-                                               args[l] = 
String.fromCharCode(97+l);
+                                               args[ l ] = 
String.fromCharCode( 97 + l );
                                        }
                                        return " " + args.join( ", " ) + " ";
                                },
@@ -2119,9 +1597,73 @@
                        multiline: true
                };
 
-       return jsDump;
+       return dump;
 }());
 
+// back compat
+QUnit.jsDump = QUnit.dump;
+
+// For browser, export only select globals
+if ( typeof window !== "undefined" ) {
+
+       // Deprecated
+       // Extend assert methods to QUnit and Global scope through Backwards 
compatibility
+       (function() {
+               var i,
+                       assertions = Assert.prototype;
+
+               function applyCurrent( current ) {
+                       return function() {
+                               var assert = new Assert( QUnit.config.current );
+                               current.apply( assert, arguments );
+                       };
+               }
+
+               for ( i in assertions ) {
+                       QUnit[ i ] = applyCurrent( assertions[ i ] );
+               }
+       })();
+
+       (function() {
+               var i, l,
+                       keys = [
+                               "test",
+                               "module",
+                               "expect",
+                               "asyncTest",
+                               "start",
+                               "stop",
+                               "ok",
+                               "equal",
+                               "notEqual",
+                               "propEqual",
+                               "notPropEqual",
+                               "deepEqual",
+                               "notDeepEqual",
+                               "strictEqual",
+                               "notStrictEqual",
+                               "throws"
+                       ];
+
+               for ( i = 0, l = keys.length; i < l; i++ ) {
+                       window[ keys[ i ] ] = QUnit[ keys[ i ] ];
+               }
+       })();
+
+       window.QUnit = QUnit;
+}
+
+// For CommonJS environments, export everything
+if ( typeof module !== "undefined" && module.exports ) {
+       module.exports = QUnit;
+}
+
+// Get a reference to the global object, like window in browsers
+}( (function() {
+       return this;
+})() ));
+
+/*istanbul ignore next */
 /*
  * Javascript Diff Algorithm
  *  By John Resig (http://ejohn.org/)
@@ -2137,6 +1679,8 @@
  * 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() {
+       var hasOwn = Object.prototype.hasOwnProperty;
+
        /*jshint eqeqeq:false, eqnull:true */
        function diff( o, n ) {
                var i,
@@ -2144,65 +1688,65 @@
                        os = {};
 
                for ( i = 0; i < n.length; i++ ) {
-                       if ( !hasOwn.call( ns, n[i] ) ) {
-                               ns[ n[i] ] = {
+                       if ( !hasOwn.call( ns, n[ i ] ) ) {
+                               ns[ n[ i ] ] = {
                                        rows: [],
                                        o: null
                                };
                        }
-                       ns[ n[i] ].rows.push( i );
+                       ns[ n[ i ] ].rows.push( i );
                }
 
                for ( i = 0; i < o.length; i++ ) {
-                       if ( !hasOwn.call( os, o[i] ) ) {
-                               os[ o[i] ] = {
+                       if ( !hasOwn.call( os, o[ i ] ) ) {
+                               os[ o[ i ] ] = {
                                        rows: [],
                                        n: null
                                };
                        }
-                       os[ o[i] ].rows.push( i );
+                       os[ o[ i ] ].rows.push( i );
                }
 
                for ( i in ns ) {
                        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]
+                               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]
+                                       o[ os[ i ].rows[ 0 ] ] = {
+                                               text: o[ os[ i ].rows[ 0 ] ],
+                                               row: ns[ i ].rows[ 0 ]
                                        };
                                }
                        }
                }
 
                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 ] 
) {
+                       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
+                                       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
                                };
                        }
                }
 
                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 
]) {
+                       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
+                                       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
                                };
                        }
@@ -2220,48 +1764,45 @@
 
                var i, pre,
                        str = "",
-                       out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? 
[] : n.split(/\s+/) ),
-                       oSpace = o.match(/\s+/g),
-                       nSpace = n.match(/\s+/g);
+                       out = diff( o === "" ? [] : o.split( /\s+/ ), n === "" 
? [] : n.split( /\s+/ ) ),
+                       oSpace = o.match( /\s+/g ),
+                       nSpace = n.match( /\s+/g );
 
                if ( oSpace == null ) {
                        oSpace = [ " " ];
-               }
-               else {
+               } else {
                        oSpace.push( " " );
                }
 
                if ( nSpace == null ) {
                        nSpace = [ " " ];
-               }
-               else {
+               } else {
                        nSpace.push( " " );
                }
 
                if ( out.n.length === 0 ) {
                        for ( i = 0; i < out.o.length; i++ ) {
-                               str += "<del>" + out.o[i] + oSpace[i] + 
"</del>";
+                               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>";
+               } 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>";
                                }
                        }
 
                        for ( i = 0; i < out.n.length; i++ ) {
-                               if (out.n[i].text == null) {
-                                       str += "<ins>" + out.n[i] + nSpace[i] + 
"</ins>";
-                               }
-                               else {
+                               if ( out.n[ i ].text == null ) {
+                                       str += "<ins>" + out.n[ i ] + nSpace[ i 
] + "</ins>";
+                               } else {
+
                                        // `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>";
                                        }
-                                       str += " " + out.n[i].text + nSpace[i] 
+ pre;
+                                       str += " " + out.n[ i ].text + nSpace[ 
i ] + pre;
                                }
                        }
                }
@@ -2270,19 +1811,685 @@
        };
 }());
 
-// For browser, export only select globals
-if ( typeof window !== "undefined" ) {
-       extend( window, QUnit.constructor.prototype );
-       window.QUnit = QUnit;
+(function() {
+
+// Deprecated QUnit.init - Ref #530
+// Re-initialize the configuration options
+QUnit.init = function() {
+       var tests, banner, result, qunit,
+               config = QUnit.config;
+
+       config.stats = { all: 0, bad: 0 };
+       config.moduleStats = { all: 0, bad: 0 };
+       config.started = 0;
+       config.updateRate = 1000;
+       config.blocking = false;
+       config.autostart = true;
+       config.autorun = false;
+       config.filter = "";
+       config.queue = [];
+       config.semaphore = 1;
+
+       // Return on non-browser environments
+       // This is necessary to not break on node tests
+       if ( typeof window === "undefined" ) {
+               return;
+       }
+
+       qunit = id( "qunit" );
+       if ( qunit ) {
+               qunit.innerHTML =
+                       "<h1 id='qunit-header'>" + escapeText( 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 ) {
+               tests.innerHTML = "";
+       }
+
+       if ( banner ) {
+               banner.className = "";
+       }
+
+       if ( result ) {
+               result.parentNode.removeChild( result );
+       }
+
+       if ( tests ) {
+               result = document.createElement( "p" );
+               result.id = "qunit-testresult";
+               result.className = "result";
+               tests.parentNode.insertBefore( result, tests );
+               result.innerHTML = "Running...<br/>&nbsp;";
+       }
+};
+
+// 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
+*/
+QUnit.reset = function() {
+
+       // Return on non-browser environments
+       // This is necessary to not break on node tests
+       if ( typeof window === "undefined" ) {
+               return;
+       }
+
+       var fixture = id( "qunit-fixture" );
+       if ( fixture ) {
+               fixture.innerHTML = config.fixture;
+       }
+};
+
+// Don't load the HTML Reporter on non-Browser environments
+if ( typeof window === "undefined" ) {
+       return;
 }
 
-// For CommonJS environments, export everything
-if ( typeof module !== "undefined" && module.exports ) {
-       module.exports = QUnit;
+var config = QUnit.config,
+       hasOwn = Object.prototype.hasOwnProperty,
+       defined = {
+               document: typeof window.document !== "undefined",
+               sessionStorage: (function() {
+                       var x = "qunit-test-string";
+                       try {
+                               sessionStorage.setItem( x, x );
+                               sessionStorage.removeItem( x );
+                               return true;
+                       } catch ( e ) {
+                               return false;
+                       }
+               }())
+       };
+
+/**
+* Escape text for attribute or text content.
+*/
+function escapeText( s ) {
+       if ( !s ) {
+               return "";
+       }
+       s = s + "";
+
+       // Both single quotes and double quotes (for attributes)
+       return s.replace( /['"<>&]/g, function( s ) {
+               switch ( s ) {
+               case "'":
+                       return "&#039;";
+               case "\"":
+                       return "&quot;";
+               case "<":
+                       return "&lt;";
+               case ">":
+                       return "&gt;";
+               case "&":
+                       return "&amp;";
+               }
+       });
 }
 
+/**
+ * @param {HTMLElement} elem
+ * @param {string} type
+ * @param {Function} fn
+ */
+function addEvent( elem, type, fn ) {
+       if ( elem.addEventListener ) {
 
-// Get a reference to the global object, like window in browsers
-}( (function() {
-       return this;
-})() ));
+               // Standards-based browsers
+               elem.addEventListener( type, fn, false );
+       } else if ( elem.attachEvent ) {
+
+               // support: IE <9
+               elem.attachEvent( "on" + type, fn );
+       }
+}
+
+/**
+ * @param {Array|NodeList} elems
+ * @param {string} type
+ * @param {Function} fn
+ */
+function addEvents( elems, type, fn ) {
+       var i = elems.length;
+       while ( i-- ) {
+               addEvent( elems[ i ], type, fn );
+       }
+}
+
+function hasClass( elem, name ) {
+       return ( " " + elem.className + " " ).indexOf( " " + name + " " ) >= 0;
+}
+
+function addClass( elem, name ) {
+       if ( !hasClass( elem, name ) ) {
+               elem.className += ( elem.className ? " " : "" ) + name;
+       }
+}
+
+function toggleClass( elem, name ) {
+       if ( hasClass( elem, name ) ) {
+               removeClass( elem, name );
+       } else {
+               addClass( elem, name );
+       }
+}
+
+function removeClass( elem, name ) {
+       var set = " " + elem.className + " ";
+
+       // Class name may appear multiple times
+       while ( set.indexOf( " " + name + " " ) >= 0 ) {
+               set = set.replace( " " + name + " ", " " );
+       }
+
+       // trim for prettiness
+       elem.className = typeof set.trim === "function" ? set.trim() : 
set.replace( /^\s+|\s+$/g, "" );
+}
+
+function id( name ) {
+       return defined.document && document.getElementById && 
document.getElementById( name );
+}
+
+function getUrlConfigHtml() {
+       var i, j, val,
+               escaped, escapedTooltip,
+               selection = false,
+               len = config.urlConfig.length,
+               urlConfigHtml = "";
+
+       for ( i = 0; i < len; i++ ) {
+               val = config.urlConfig[ i ];
+               if ( typeof val === "string" ) {
+                       val = {
+                               id: val,
+                               label: val
+                       };
+               }
+
+               escaped = escapeText( val.id );
+               escapedTooltip = escapeText( val.tooltip );
+
+               config[ val.id ] = QUnit.urlParams[ val.id ];
+               if ( !val.value || typeof val.value === "string" ) {
+                       urlConfigHtml += "<input id='qunit-urlconfig-" + 
escaped +
+                               "' name='" + escaped + "' type='checkbox'" +
+                               ( val.value ? " value='" + escapeText( 
val.value ) + "'" : "" ) +
+                               ( config[ val.id ] ? " checked='checked'" : "" 
) +
+                               " title='" + escapedTooltip + "'><label 
for='qunit-urlconfig-" + escaped +
+                               "' title='" + escapedTooltip + "'>" + val.label 
+ "</label>";
+               } else {
+                       urlConfigHtml += "<label for='qunit-urlconfig-" + 
escaped +
+                               "' title='" + escapedTooltip + "'>" + val.label 
+
+                               ": </label><select id='qunit-urlconfig-" + 
escaped +
+                               "' name='" + escaped + "' title='" + 
escapedTooltip + "'><option></option>";
+
+                       if ( QUnit.is( "array", val.value ) ) {
+                               for ( j = 0; j < val.value.length; j++ ) {
+                                       escaped = escapeText( val.value[ j ] );
+                                       urlConfigHtml += "<option value='" + 
escaped + "'" +
+                                               ( config[ val.id ] === 
val.value[ j ] ?
+                                                       ( selection = true ) && 
" selected='selected'" : "" ) +
+                                               ">" + escaped + "</option>";
+                               }
+                       } else {
+                               for ( j in val.value ) {
+                                       if ( hasOwn.call( val.value, j ) ) {
+                                               urlConfigHtml += "<option 
value='" + escapeText( j ) + "'" +
+                                                       ( config[ val.id ] === 
j ?
+                                                               ( selection = 
true ) && " selected='selected'" : "" ) +
+                                                       ">" + escapeText( 
val.value[ j ] ) + "</option>";
+                                       }
+                               }
+                       }
+                       if ( config[ val.id ] && !selection ) {
+                               escaped = escapeText( config[ val.id ] );
+                               urlConfigHtml += "<option value='" + escaped +
+                                       "' selected='selected' 
disabled='disabled'>" + escaped + "</option>";
+                       }
+                       urlConfigHtml += "</select>";
+               }
+       }
+
+       return urlConfigHtml;
+}
+
+function toolbarUrlConfigContainer() {
+       var urlConfigContainer = document.createElement( "span" );
+
+       urlConfigContainer.innerHTML = getUrlConfigHtml();
+
+       // For oldIE support:
+       // * Add handlers to the individual elements instead of the container
+       // * Use "click" instead of "change" for checkboxes
+       // * Fallback from event.target to event.srcElement
+       addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", 
function( event ) {
+               var params = {},
+                       target = event.target || event.srcElement;
+               params[ target.name ] = target.checked ?
+                       target.defaultValue || true :
+                       undefined;
+               window.location = QUnit.url( params );
+       });
+       addEvents( urlConfigContainer.getElementsByTagName( "select" ), 
"change", function( event ) {
+               var params = {},
+                       target = event.target || event.srcElement;
+               params[ target.name ] = target.options[ target.selectedIndex 
].value || undefined;
+               window.location = QUnit.url( params );
+       });
+
+       return urlConfigContainer;
+}
+
+function getModuleNames() {
+       var i,
+               moduleNames = [];
+
+       for ( i in config.modules ) {
+               if ( config.modules.hasOwnProperty( i ) ) {
+                       moduleNames.push( i );
+               }
+       }
+
+       moduleNames.sort(function( a, b ) {
+               return a.localeCompare( b );
+       });
+
+       return moduleNames;
+}
+
+function toolbarModuleFilterHtml() {
+       var i,
+               moduleFilterHtml = "",
+               moduleNames = getModuleNames();
+
+       if ( moduleNames.length <= 1 ) {
+               return false;
+       }
+
+       moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label>" +
+               "<select id='qunit-modulefilter' name='modulefilter'><option 
value='' " +
+               ( config.module === undefined ? "selected='selected'" : "" ) +
+               ">< All Modules ></option>";
+
+       for ( i = 0; i < moduleNames.length; i++ ) {
+               moduleFilterHtml += "<option value='" +
+                       escapeText( encodeURIComponent( moduleNames[ i ] ) ) + 
"' " +
+                       ( config.module === moduleNames[ i ] ? 
"selected='selected'" : "" ) +
+                       ">" + escapeText( moduleNames[ i ] ) + "</option>";
+       }
+       moduleFilterHtml += "</select>";
+
+       return moduleFilterHtml;
+}
+
+function toolbarModuleFilter() {
+       var moduleFilter = document.createElement( "span" ),
+               moduleFilterHtml = toolbarModuleFilterHtml();
+
+       if ( !moduleFilterHtml ) {
+               return false;
+       }
+
+       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,
+
+                       // Remove any existing filters
+                       filter: undefined,
+                       testNumber: undefined
+               });
+       });
+
+       return moduleFilter;
+}
+
+function toolbarFilter() {
+       var testList = id( "qunit-tests" ),
+               filter = document.createElement( "input" );
+
+       filter.type = "checkbox";
+       filter.id = "qunit-filter-pass";
+
+       addEvent( filter, "click", function() {
+               if ( filter.checked ) {
+                       addClass( testList, "hidepass" );
+                       if ( defined.sessionStorage ) {
+                               sessionStorage.setItem( 
"qunit-filter-passed-tests", "true" );
+                       }
+               } else {
+                       removeClass( testList, "hidepass" );
+                       if ( defined.sessionStorage ) {
+                               sessionStorage.removeItem( 
"qunit-filter-passed-tests" );
+                       }
+               }
+       });
+
+       if ( config.hidepassed || defined.sessionStorage &&
+                       sessionStorage.getItem( "qunit-filter-passed-tests" ) ) 
{
+               filter.checked = true;
+
+               addClass( testList, "hidepass" );
+       }
+
+       return filter;
+}
+
+function toolbarLabel() {
+       var label = document.createElement( "label" );
+       label.setAttribute( "for", "qunit-filter-pass" );
+       label.setAttribute( "title", "Only show tests and assertions that fail. 
Stored in sessionStorage." );
+       label.innerHTML = "Hide passed tests";
+
+       return label;
+}
+
+function appendToolbar() {
+       var moduleFilter,
+               toolbar = id( "qunit-testrunner-toolbar" );
+
+       if ( toolbar ) {
+               toolbar.appendChild( toolbarFilter() );
+               toolbar.appendChild( toolbarLabel() );
+               toolbar.appendChild( toolbarUrlConfigContainer() );
+
+               moduleFilter = toolbarModuleFilter();
+               if ( moduleFilter ) {
+                       toolbar.appendChild( moduleFilter );
+               }
+       }
+}
+
+function appendBanner() {
+       var banner = id( "qunit-banner" );
+
+       if ( banner ) {
+               banner.className = "";
+               banner.innerHTML = "<a href='" +
+                       QUnit.url({ filter: undefined, module: undefined, 
testNumber: undefined }) +
+                       "'>" + banner.innerHTML + "</a> ";
+       }
+}
+
+function appendTestResults() {
+       var tests = id( "qunit-tests" ),
+               result = id( "qunit-testresult" );
+
+       if ( result ) {
+               result.parentNode.removeChild( result );
+       }
+
+       if ( tests ) {
+               tests.innerHTML = "";
+               result = document.createElement( "p" );
+               result.id = "qunit-testresult";
+               result.className = "result";
+               tests.parentNode.insertBefore( result, tests );
+               result.innerHTML = "Running...<br>&nbsp;";
+       }
+}
+
+function storeFixture() {
+       var fixture = id( "qunit-fixture" );
+       if ( fixture ) {
+               config.fixture = fixture.innerHTML;
+       }
+}
+
+function appendUserAgent() {
+       var userAgent = id( "qunit-userAgent" );
+       if ( userAgent ) {
+               userAgent.innerHTML = navigator.userAgent;
+       }
+}
+
+// HTML Reporter initialization and load
+QUnit.begin(function() {
+       var qunit = id( "qunit" );
+
+       if ( qunit ) {
+               qunit.innerHTML =
+               "<h1 id='qunit-header'>" + escapeText( document.title ) + 
"</h1>" +
+               "<h2 id='qunit-banner'></h2>" +
+               "<div id='qunit-testrunner-toolbar'></div>" +
+               "<h2 id='qunit-userAgent'></h2>" +
+               "<ol id='qunit-tests'></ol>";
+       }
+
+       appendBanner();
+       appendTestResults();
+       appendUserAgent();
+       appendToolbar();
+       storeFixture();
+});
+
+QUnit.done(function( details ) {
+       var i, key,
+               banner = id( "qunit-banner" ),
+               tests = id( "qunit-tests" ),
+               html = [
+                       "Tests completed in ",
+                       details.runtime,
+                       " milliseconds.<br>",
+                       "<span class='passed'>",
+                       details.passed,
+                       "</span> assertions of <span class='total'>",
+                       details.total,
+                       "</span> passed, <span class='failed'>",
+                       details.failed,
+                       "</span> failed."
+               ].join( "" );
+
+       if ( banner ) {
+               banner.className = details.failed ? "qunit-fail" : "qunit-pass";
+       }
+
+       if ( tests ) {
+               id( "qunit-testresult" ).innerHTML = html;
+       }
+
+       if ( config.altertitle && defined.document && document.title ) {
+
+               // show ✖ for good, ✔ for bad suite result in title
+               // use escape sequences in case file gets loaded with 
non-utf-8-charset
+               document.title = [
+                       ( details.failed ? "\u2716" : "\u2714" ),
+                       document.title.replace( /^[\u2714\u2716] /i, "" )
+               ].join( " " );
+       }
+
+       // clear own sessionStorage items if all tests passed
+       if ( config.reorder && defined.sessionStorage && details.failed === 0 ) 
{
+               for ( i = 0; i < sessionStorage.length; i++ ) {
+                       key = sessionStorage.key( i++ );
+                       if ( key.indexOf( "qunit-test-" ) === 0 ) {
+                               sessionStorage.removeItem( key );
+                       }
+               }
+       }
+
+       // scroll back to top to show results
+       if ( config.scrolltop && window.scrollTo ) {
+               window.scrollTo( 0, 0 );
+       }
+});
+
+function getNameHtml( name, module ) {
+       var nameHtml = "";
+
+       if ( module ) {
+               nameHtml = "<span class='module-name'>" + escapeText( module ) 
+ "</span>: ";
+       }
+
+       nameHtml += "<span class='test-name'>" + escapeText( name ) + "</span>";
+
+       return nameHtml;
+}
+
+QUnit.testStart(function( details ) {
+       var a, b, li, running, assertList,
+               name = getNameHtml( details.name, details.module ),
+               tests = id( "qunit-tests" );
+
+       if ( tests ) {
+               b = document.createElement( "strong" );
+               b.innerHTML = name;
+
+               a = document.createElement( "a" );
+               a.innerHTML = "Rerun";
+               a.href = QUnit.url({ testNumber: details.testNumber });
+
+               li = document.createElement( "li" );
+               li.appendChild( b );
+               li.appendChild( a );
+               li.className = "running";
+               li.id = "qunit-test-output" + details.testNumber;
+
+               assertList = document.createElement( "ol" );
+               assertList.className = "qunit-assert-list";
+
+               li.appendChild( assertList );
+
+               tests.appendChild( li );
+       }
+
+       running = id( "qunit-testresult" );
+       if ( running ) {
+               running.innerHTML = "Running: <br>" + name;
+       }
+
+});
+
+QUnit.log(function( details ) {
+       var assertList, assertLi,
+               message, expected, actual,
+               testItem = id( "qunit-test-output" + details.testNumber );
+
+       if ( !testItem ) {
+               return;
+       }
+
+       message = escapeText( details.message ) || ( details.result ? "okay" : 
"failed" );
+       message = "<span class='test-message'>" + message + "</span>";
+
+       // pushFailure doesn't provide details.expected
+       // when it calls, it's implicit to also not show expected and diff stuff
+       // Also, we need to check details.expected existence, as it can exist 
and be undefined
+       if ( !details.result && hasOwn.call( details, "expected" ) ) {
+               expected = escapeText( QUnit.dump.parse( details.expected ) );
+               actual = escapeText( QUnit.dump.parse( details.actual ) );
+               message += "<table><tr class='test-expected'><th>Expected: 
</th><td><pre>" +
+                       expected +
+                       "</pre></td></tr>";
+
+               if ( actual !== expected ) {
+                       message += "<tr class='test-actual'><th>Result: 
</th><td><pre>" +
+                               actual + "</pre></td></tr>" +
+                               "<tr class='test-diff'><th>Diff: 
</th><td><pre>" +
+                               QUnit.diff( expected, actual ) + 
"</pre></td></tr>";
+               }
+
+               if ( details.source ) {
+                       message += "<tr class='test-source'><th>Source: 
</th><td><pre>" +
+                               escapeText( details.source ) + 
"</pre></td></tr>";
+               }
+
+               message += "</table>";
+
+       // this occours when pushFailure is set and we have an extracted stack 
trace
+       } else if ( !details.result && details.source ) {
+               message += "<table>" +
+                       "<tr class='test-source'><th>Source: </th><td><pre>" +
+                       escapeText( details.source ) + "</pre></td></tr>" +
+                       "</table>";
+       }
+
+       assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
+
+       assertLi = document.createElement( "li" );
+       assertLi.className = details.result ? "pass" : "fail";
+       assertLi.innerHTML = message;
+       assertList.appendChild( assertLi );
+});
+
+QUnit.testDone(function( details ) {
+       var testTitle, time, testItem, assertList,
+               good, bad, testCounts,
+               tests = id( "qunit-tests" );
+
+       // QUnit.reset() is deprecated and will be replaced for a new
+       // fixture reset function on QUnit 2.0/2.1.
+       // It's still called here for backwards compatibility handling
+       QUnit.reset();
+
+       if ( !tests ) {
+               return;
+       }
+
+       testItem = id( "qunit-test-output" + details.testNumber );
+       assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
+
+       good = details.passed;
+       bad = details.failed;
+
+       // store result when possible
+       if ( config.reorder && defined.sessionStorage ) {
+               if ( bad ) {
+                       sessionStorage.setItem( "qunit-test-" + details.module 
+ "-" + details.name, bad );
+               } else {
+                       sessionStorage.removeItem( "qunit-test-" + 
details.module + "-" + details.name );
+               }
+       }
+
+       if ( bad === 0 ) {
+               addClass( assertList, "qunit-collapsed" );
+       }
+
+       // testItem.firstChild is the test name
+       testTitle = testItem.firstChild;
+
+       testCounts = bad ?
+               "<b class='failed'>" + bad + "</b>, " + "<b class='passed'>" + 
good + "</b>, " :
+               "";
+
+       testTitle.innerHTML += " <b class='counts'>(" + testCounts +
+               details.assertions.length + ")</b>";
+
+       addEvent( testTitle, "click", function() {
+               toggleClass( assertList, "qunit-collapsed" );
+       });
+
+       time = document.createElement( "span" );
+       time.className = "runtime";
+       time.innerHTML = details.runtime + " ms";
+
+       testItem.className = bad ? "fail" : "pass";
+
+       testItem.insertBefore( time, assertList );
+});
+
+if ( !defined.document || document.readyState === "complete" ) {
+       config.autorun = true;
+}
+
+if ( defined.document ) {
+       addEvent( window, "load", QUnit.load );
+}
+
+})();

-- 
To view, visit https://gerrit.wikimedia.org/r/154029
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I4c0068dd0754f74172f89453251726cd1a21fc68
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Paladox <thomasmulhall...@yahoo.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to