WordPress.org

Make WordPress Core

Ticket #25088: 25088.2.diff

File 25088.2.diff, 68.3 KB (added by jorbin, 5 years ago)

With redundant semicolons and early commas

  • tests/qunit/index.html

     
     1<!DOCTYPE HTML>
     2<html>
     3<head>
     4  <title>WordPress QUnit Test Suite</title>
     5
     6  <!-- jquery -->
     7  <!--<script src="http://code.jquery.com/jquery-1.7.min.js"></script>-->
     8  <script src="../../src/wp-includes/js/jquery/jquery.js"></script>
     9
     10  <!-- qunit -->
     11  <link rel="stylesheet" href="vendor/qunit.css" type="text/css" media="screen" />
     12  <script src="vendor/qunit.js"></script>
     13
     14
     15  <!-- Tested Files -->
     16  <script src="../../src/wp-admin/js/password-strength-meter.js"></script>
     17
     18
     19
     20  <!-- Unit Tests -->
     21  <script src="wp-admin/js/password-strength-meter.js"></script>
     22</head>
     23<body>
     24  <div>
     25    <h1 id="qunit-header">WordPress QUnit Test Suite</h1>
     26    <h2 id="qunit-banner"></h2>
     27    <h2 id="qunit-userAgent"></h2>
     28    <ol id="qunit-tests"></ol>
     29    <div id="qunit-fixture"></div>
     30  </div>
     31</body>
     32</html>
     33
  • tests/qunit/vendor/qunit.css

    Property changes on: tests/qunit/index.html
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1/**
     2 * QUnit v1.12.0 - A JavaScript Unit Testing Framework
     3 *
     4 * http://qunitjs.com
     5 *
     6 * Copyright 2012 jQuery Foundation and other contributors
     7 * Released under the MIT license.
     8 * http://jquery.org/license
     9 */
     10
     11/** Font Family and Sizes */
     12
     13#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
     14        font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
     15}
     16
     17#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
     18#qunit-tests { font-size: smaller; }
     19
     20
     21/** Resets */
     22
     23#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
     24        margin: 0;
     25        padding: 0;
     26}
     27
     28
     29/** Header */
     30
     31#qunit-header {
     32        padding: 0.5em 0 0.5em 1em;
     33
     34        color: #8699a4;
     35        background-color: #0d3349;
     36
     37        font-size: 1.5em;
     38        line-height: 1em;
     39        font-weight: normal;
     40
     41        border-radius: 5px 5px 0 0;
     42        -moz-border-radius: 5px 5px 0 0;
     43        -webkit-border-top-right-radius: 5px;
     44        -webkit-border-top-left-radius: 5px;
     45}
     46
     47#qunit-header a {
     48        text-decoration: none;
     49        color: #c2ccd1;
     50}
     51
     52#qunit-header a:hover,
     53#qunit-header a:focus {
     54        color: #fff;
     55}
     56
     57#qunit-testrunner-toolbar label {
     58        display: inline-block;
     59        padding: 0 .5em 0 .1em;
     60}
     61
     62#qunit-banner {
     63        height: 5px;
     64}
     65
     66#qunit-testrunner-toolbar {
     67        padding: 0.5em 0 0.5em 2em;
     68        color: #5E740B;
     69        background-color: #eee;
     70        overflow: hidden;
     71}
     72
     73#qunit-userAgent {
     74        padding: 0.5em 0 0.5em 2.5em;
     75        background-color: #2b81af;
     76        color: #fff;
     77        text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
     78}
     79
     80#qunit-modulefilter-container {
     81        float: right;
     82}
     83
     84/** Tests: Pass/Fail */
     85
     86#qunit-tests {
     87        list-style-position: inside;
     88}
     89
     90#qunit-tests li {
     91        padding: 0.4em 0.5em 0.4em 2.5em;
     92        border-bottom: 1px solid #fff;
     93        list-style-position: inside;
     94}
     95
     96#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running  {
     97        display: none;
     98}
     99
     100#qunit-tests li strong {
     101        cursor: pointer;
     102}
     103
     104#qunit-tests li a {
     105        padding: 0.5em;
     106        color: #c2ccd1;
     107        text-decoration: none;
     108}
     109#qunit-tests li a:hover,
     110#qunit-tests li a:focus {
     111        color: #000;
     112}
     113
     114#qunit-tests li .runtime {
     115        float: right;
     116        font-size: smaller;
     117}
     118
     119.qunit-assert-list {
     120        margin-top: 0.5em;
     121        padding: 0.5em;
     122
     123        background-color: #fff;
     124
     125        border-radius: 5px;
     126        -moz-border-radius: 5px;
     127        -webkit-border-radius: 5px;
     128}
     129
     130.qunit-collapsed {
     131        display: none;
     132}
     133
     134#qunit-tests table {
     135        border-collapse: collapse;
     136        margin-top: .2em;
     137}
     138
     139#qunit-tests th {
     140        text-align: right;
     141        vertical-align: top;
     142        padding: 0 .5em 0 0;
     143}
     144
     145#qunit-tests td {
     146        vertical-align: top;
     147}
     148
     149#qunit-tests pre {
     150        margin: 0;
     151        white-space: pre-wrap;
     152        word-wrap: break-word;
     153}
     154
     155#qunit-tests del {
     156        background-color: #e0f2be;
     157        color: #374e0c;
     158        text-decoration: none;
     159}
     160
     161#qunit-tests ins {
     162        background-color: #ffcaca;
     163        color: #500;
     164        text-decoration: none;
     165}
     166
     167/*** Test Counts */
     168
     169#qunit-tests b.counts                       { color: black; }
     170#qunit-tests b.passed                       { color: #5E740B; }
     171#qunit-tests b.failed                       { color: #710909; }
     172
     173#qunit-tests li li {
     174        padding: 5px;
     175        background-color: #fff;
     176        border-bottom: none;
     177        list-style-position: inside;
     178}
     179
     180/*** Passing Styles */
     181
     182#qunit-tests li li.pass {
     183        color: #3c510c;
     184        background-color: #fff;
     185        border-left: 10px solid #C6E746;
     186}
     187
     188#qunit-tests .pass                          { color: #528CE0; background-color: #D2E0E6; }
     189#qunit-tests .pass .test-name               { color: #366097; }
     190
     191#qunit-tests .pass .test-actual,
     192#qunit-tests .pass .test-expected           { color: #999999; }
     193
     194#qunit-banner.qunit-pass                    { background-color: #C6E746; }
     195
     196/*** Failing Styles */
     197
     198#qunit-tests li li.fail {
     199        color: #710909;
     200        background-color: #fff;
     201        border-left: 10px solid #EE5757;
     202        white-space: pre;
     203}
     204
     205#qunit-tests > li:last-child {
     206        border-radius: 0 0 5px 5px;
     207        -moz-border-radius: 0 0 5px 5px;
     208        -webkit-border-bottom-right-radius: 5px;
     209        -webkit-border-bottom-left-radius: 5px;
     210}
     211
     212#qunit-tests .fail                          { color: #000000; background-color: #EE5757; }
     213#qunit-tests .fail .test-name,
     214#qunit-tests .fail .module-name             { color: #000000; }
     215
     216#qunit-tests .fail .test-actual             { color: #EE5757; }
     217#qunit-tests .fail .test-expected           { color: green;   }
     218
     219#qunit-banner.qunit-fail                    { background-color: #EE5757; }
     220
     221
     222/** Result */
     223
     224#qunit-testresult {
     225        padding: 0.5em 0.5em 0.5em 2.5em;
     226
     227        color: #2b81af;
     228        background-color: #D2E0E6;
     229
     230        border-bottom: 1px solid white;
     231}
     232#qunit-testresult .module-name {
     233        font-weight: bold;
     234}
     235
     236/** Fixture */
     237
     238#qunit-fixture {
     239        position: absolute;
     240        top: -10000px;
     241        left: -10000px;
     242        width: 1000px;
     243        height: 1000px;
     244}
  • tests/qunit/vendor/qunit.js

    Property changes on: tests/qunit/vendor/qunit.css
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1/**
     2 * QUnit v1.12.0 - A JavaScript Unit Testing Framework
     3 *
     4 * http://qunitjs.com
     5 *
     6 * Copyright 2013 jQuery Foundation and other contributors
     7 * Released under the MIT license.
     8 * https://jquery.org/license/
     9 */
     10
     11(function( window ) {
     12
     13var QUnit,
     14        assert,
     15        config,
     16        onErrorFnPrev,
     17        testId = 0,
     18        fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
     19        toString = Object.prototype.toString,
     20        hasOwn = Object.prototype.hasOwnProperty,
     21        // Keep a local reference to Date (GH-283)
     22        Date = window.Date,
     23        setTimeout = window.setTimeout,
     24        defined = {
     25                setTimeout: typeof window.setTimeout !== "undefined",
     26                sessionStorage: (function() {
     27                        var x = "qunit-test-string";
     28                        try {
     29                                sessionStorage.setItem( x, x );
     30                                sessionStorage.removeItem( x );
     31                                return true;
     32                        } catch( e ) {
     33                                return false;
     34                        }
     35                }())
     36        },
     37        /**
     38         * Provides a normalized error string, correcting an issue
     39         * with IE 7 (and prior) where Error.prototype.toString is
     40         * not properly implemented
     41         *
     42         * Based on http://es5.github.com/#x15.11.4.4
     43         *
     44         * @param {String|Error} error
     45         * @return {String} error message
     46         */
     47        errorString = function( error ) {
     48                var name, message,
     49                        errorString = error.toString();
     50                if ( errorString.substring( 0, 7 ) === "[object" ) {
     51                        name = error.name ? error.name.toString() : "Error";
     52                        message = error.message ? error.message.toString() : "";
     53                        if ( name && message ) {
     54                                return name + ": " + message;
     55                        } else if ( name ) {
     56                                return name;
     57                        } else if ( message ) {
     58                                return message;
     59                        } else {
     60                                return "Error";
     61                        }
     62                } else {
     63                        return errorString;
     64                }
     65        },
     66        /**
     67         * Makes a clone of an object using only Array or Object as base,
     68         * and copies over the own enumerable properties.
     69         *
     70         * @param {Object} obj
     71         * @return {Object} New object with only the own properties (recursively).
     72         */
     73        objectValues = function( obj ) {
     74                // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
     75                /*jshint newcap: false */
     76                var key, val,
     77                        vals = QUnit.is( "array", obj ) ? [] : {};
     78                for ( key in obj ) {
     79                        if ( hasOwn.call( obj, key ) ) {
     80                                val = obj[key];
     81                                vals[key] = val === Object(val) ? objectValues(val) : val;
     82                        }
     83                }
     84                return vals;
     85        };
     86
     87function Test( settings ) {
     88        extend( this, settings );
     89        this.assertions = [];
     90        this.testNumber = ++Test.count;
     91}
     92
     93Test.count = 0;
     94
     95Test.prototype = {
     96        init: function() {
     97                var a, b, li,
     98                        tests = id( "qunit-tests" );
     99
     100                if ( tests ) {
     101                        b = document.createElement( "strong" );
     102                        b.innerHTML = this.nameHtml;
     103
     104                        // `a` initialized at top of scope
     105                        a = document.createElement( "a" );
     106                        a.innerHTML = "Rerun";
     107                        a.href = QUnit.url({ testNumber: this.testNumber });
     108
     109                        li = document.createElement( "li" );
     110                        li.appendChild( b );
     111                        li.appendChild( a );
     112                        li.className = "running";
     113                        li.id = this.id = "qunit-test-output" + testId++;
     114
     115                        tests.appendChild( li );
     116                }
     117        },
     118        setup: function() {
     119                if (
     120                        // Emit moduleStart when we're switching from one module to another
     121                        this.module !== config.previousModule ||
     122                                // They could be equal (both undefined) but if the previousModule property doesn't
     123                                // yet exist it means this is the first test in a suite that isn't wrapped in a
     124                                // module, in which case we'll just emit a moduleStart event for 'undefined'.
     125                                // Without this, reporters can get testStart before moduleStart  which is a problem.
     126                                !hasOwn.call( config, "previousModule" )
     127                ) {
     128                        if ( hasOwn.call( config, "previousModule" ) ) {
     129                                runLoggingCallbacks( "moduleDone", QUnit, {
     130                                        name: config.previousModule,
     131                                        failed: config.moduleStats.bad,
     132                                        passed: config.moduleStats.all - config.moduleStats.bad,
     133                                        total: config.moduleStats.all
     134                                });
     135                        }
     136                        config.previousModule = this.module;
     137                        config.moduleStats = { all: 0, bad: 0 };
     138                        runLoggingCallbacks( "moduleStart", QUnit, {
     139                                name: this.module
     140                        });
     141                }
     142
     143                config.current = this;
     144
     145                this.testEnvironment = extend({
     146                        setup: function() {},
     147                        teardown: function() {}
     148                }, this.moduleTestEnvironment );
     149
     150                this.started = +new Date();
     151                runLoggingCallbacks( "testStart", QUnit, {
     152                        name: this.testName,
     153                        module: this.module
     154                });
     155
     156                /*jshint camelcase:false */
     157
     158
     159                /**
     160                 * Expose the current test environment.
     161                 *
     162                 * @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead.
     163                 */
     164                QUnit.current_testEnvironment = this.testEnvironment;
     165
     166                /*jshint camelcase:true */
     167
     168                if ( !config.pollution ) {
     169                        saveGlobal();
     170                }
     171                if ( config.notrycatch ) {
     172                        this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
     173                        return;
     174                }
     175                try {
     176                        this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
     177                } catch( e ) {
     178                        QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
     179                }
     180        },
     181        run: function() {
     182                config.current = this;
     183
     184                var running = id( "qunit-testresult" );
     185
     186                if ( running ) {
     187                        running.innerHTML = "Running: <br/>" + this.nameHtml;
     188                }
     189
     190                if ( this.async ) {
     191                        QUnit.stop();
     192                }
     193
     194                this.callbackStarted = +new Date();
     195
     196                if ( config.notrycatch ) {
     197                        this.callback.call( this.testEnvironment, QUnit.assert );
     198                        this.callbackRuntime = +new Date() - this.callbackStarted;
     199                        return;
     200                }
     201
     202                try {
     203                        this.callback.call( this.testEnvironment, QUnit.assert );
     204                        this.callbackRuntime = +new Date() - this.callbackStarted;
     205                } catch( e ) {
     206                        this.callbackRuntime = +new Date() - this.callbackStarted;
     207
     208                        QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
     209                        // else next test will carry the responsibility
     210                        saveGlobal();
     211
     212                        // Restart the tests if they're blocking
     213                        if ( config.blocking ) {
     214                                QUnit.start();
     215                        }
     216                }
     217        },
     218        teardown: function() {
     219                config.current = this;
     220                if ( config.notrycatch ) {
     221                        if ( typeof this.callbackRuntime === "undefined" ) {
     222                                this.callbackRuntime = +new Date() - this.callbackStarted;
     223                        }
     224                        this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
     225                        return;
     226                } else {
     227                        try {
     228                                this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
     229                        } catch( e ) {
     230                                QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
     231                        }
     232                }
     233                checkPollution();
     234        },
     235        finish: function() {
     236                config.current = this;
     237                if ( config.requireExpects && this.expected === null ) {
     238                        QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
     239                } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
     240                        QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
     241                } else if ( this.expected === null && !this.assertions.length ) {
     242                        QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
     243                }
     244
     245                var i, assertion, a, b, time, li, ol,
     246                        test = this,
     247                        good = 0,
     248                        bad = 0,
     249                        tests = id( "qunit-tests" );
     250
     251                this.runtime = +new Date() - this.started;
     252                config.stats.all += this.assertions.length;
     253                config.moduleStats.all += this.assertions.length;
     254
     255                if ( tests ) {
     256                        ol = document.createElement( "ol" );
     257                        ol.className = "qunit-assert-list";
     258
     259                        for ( i = 0; i < this.assertions.length; i++ ) {
     260                                assertion = this.assertions[i];
     261
     262                                li = document.createElement( "li" );
     263                                li.className = assertion.result ? "pass" : "fail";
     264                                li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
     265                                ol.appendChild( li );
     266
     267                                if ( assertion.result ) {
     268                                        good++;
     269                                } else {
     270                                        bad++;
     271                                        config.stats.bad++;
     272                                        config.moduleStats.bad++;
     273                                }
     274                        }
     275
     276                        // store result when possible
     277                        if ( QUnit.config.reorder && defined.sessionStorage ) {
     278                                if ( bad ) {
     279                                        sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
     280                                } else {
     281                                        sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
     282                                }
     283                        }
     284
     285                        if ( bad === 0 ) {
     286                                addClass( ol, "qunit-collapsed" );
     287                        }
     288
     289                        // `b` initialized at top of scope
     290                        b = document.createElement( "strong" );
     291                        b.innerHTML = this.nameHtml + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
     292
     293                        addEvent(b, "click", function() {
     294                                var next = b.parentNode.lastChild,
     295                                        collapsed = hasClass( next, "qunit-collapsed" );
     296                                ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
     297                        });
     298
     299                        addEvent(b, "dblclick", function( e ) {
     300                                var target = e && e.target ? e.target : window.event.srcElement;
     301                                if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
     302                                        target = target.parentNode;
     303                                }
     304                                if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
     305                                        window.location = QUnit.url({ testNumber: test.testNumber });
     306                                }
     307                        });
     308
     309                        // `time` initialized at top of scope
     310                        time = document.createElement( "span" );
     311                        time.className = "runtime";
     312                        time.innerHTML = this.runtime + " ms";
     313
     314                        // `li` initialized at top of scope
     315                        li = id( this.id );
     316                        li.className = bad ? "fail" : "pass";
     317                        li.removeChild( li.firstChild );
     318                        a = li.firstChild;
     319                        li.appendChild( b );
     320                        li.appendChild( a );
     321                        li.appendChild( time );
     322                        li.appendChild( ol );
     323
     324                } else {
     325                        for ( i = 0; i < this.assertions.length; i++ ) {
     326                                if ( !this.assertions[i].result ) {
     327                                        bad++;
     328                                        config.stats.bad++;
     329                                        config.moduleStats.bad++;
     330                                }
     331                        }
     332                }
     333
     334                runLoggingCallbacks( "testDone", QUnit, {
     335                        name: this.testName,
     336                        module: this.module,
     337                        failed: bad,
     338                        passed: this.assertions.length - bad,
     339                        total: this.assertions.length,
     340                        duration: this.runtime
     341                });
     342
     343                QUnit.reset();
     344
     345                config.current = undefined;
     346        },
     347
     348        queue: function() {
     349                var bad,
     350                        test = this;
     351
     352                synchronize(function() {
     353                        test.init();
     354                });
     355                function run() {
     356                        // each of these can by async
     357                        synchronize(function() {
     358                                test.setup();
     359                        });
     360                        synchronize(function() {
     361                                test.run();
     362                        });
     363                        synchronize(function() {
     364                                test.teardown();
     365                        });
     366                        synchronize(function() {
     367                                test.finish();
     368                        });
     369                }
     370
     371                // `bad` initialized at top of scope
     372                // defer when previous test run passed, if storage is available
     373                bad = QUnit.config.reorder && defined.sessionStorage &&
     374                                                +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
     375
     376                if ( bad ) {
     377                        run();
     378                } else {
     379                        synchronize( run, true );
     380                }
     381        }
     382};
     383
     384// Root QUnit object.
     385// `QUnit` initialized at top of scope
     386QUnit = {
     387
     388        // call on start of module test to prepend name to all tests
     389        module: function( name, testEnvironment ) {
     390                config.currentModule = name;
     391                config.currentModuleTestEnvironment = testEnvironment;
     392                config.modules[name] = true;
     393        },
     394
     395        asyncTest: function( testName, expected, callback ) {
     396                if ( arguments.length === 2 ) {
     397                        callback = expected;
     398                        expected = null;
     399                }
     400
     401                QUnit.test( testName, expected, callback, true );
     402        },
     403
     404        test: function( testName, expected, callback, async ) {
     405                var test,
     406                        nameHtml = "<span class='test-name'>" + escapeText( testName ) + "</span>";
     407
     408                if ( arguments.length === 2 ) {
     409                        callback = expected;
     410                        expected = null;
     411                }
     412
     413                if ( config.currentModule ) {
     414                        nameHtml = "<span class='module-name'>" + escapeText( config.currentModule ) + "</span>: " + nameHtml;
     415                }
     416
     417                test = new Test({
     418                        nameHtml: nameHtml,
     419                        testName: testName,
     420                        expected: expected,
     421                        async: async,
     422                        callback: callback,
     423                        module: config.currentModule,
     424                        moduleTestEnvironment: config.currentModuleTestEnvironment,
     425                        stack: sourceFromStacktrace( 2 )
     426                });
     427
     428                if ( !validTest( test ) ) {
     429                        return;
     430                }
     431
     432                test.queue();
     433        },
     434
     435        // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through.
     436        expect: function( asserts ) {
     437                if (arguments.length === 1) {
     438                        config.current.expected = asserts;
     439                } else {
     440                        return config.current.expected;
     441                }
     442        },
     443
     444        start: function( count ) {
     445                // QUnit hasn't been initialized yet.
     446                // Note: RequireJS (et al) may delay onLoad
     447                if ( config.semaphore === undefined ) {
     448                        QUnit.begin(function() {
     449                                // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
     450                                setTimeout(function() {
     451                                        QUnit.start( count );
     452                                });
     453                        });
     454                        return;
     455                }
     456
     457                config.semaphore -= count || 1;
     458                // don't start until equal number of stop-calls
     459                if ( config.semaphore > 0 ) {
     460                        return;
     461                }
     462                // ignore if start is called more often then stop
     463                if ( config.semaphore < 0 ) {
     464                        config.semaphore = 0;
     465                        QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
     466                        return;
     467                }
     468                // A slight delay, to avoid any current callbacks
     469                if ( defined.setTimeout ) {
     470                        setTimeout(function() {
     471                                if ( config.semaphore > 0 ) {
     472                                        return;
     473                                }
     474                                if ( config.timeout ) {
     475                                        clearTimeout( config.timeout );
     476                                }
     477
     478                                config.blocking = false;
     479                                process( true );
     480                        }, 13);
     481                } else {
     482                        config.blocking = false;
     483                        process( true );
     484                }
     485        },
     486
     487        stop: function( count ) {
     488                config.semaphore += count || 1;
     489                config.blocking = true;
     490
     491                if ( config.testTimeout && defined.setTimeout ) {
     492                        clearTimeout( config.timeout );
     493                        config.timeout = setTimeout(function() {
     494                                QUnit.ok( false, "Test timed out" );
     495                                config.semaphore = 1;
     496                                QUnit.start();
     497                        }, config.testTimeout );
     498                }
     499        }
     500};
     501
     502// `assert` initialized at top of scope
     503// Assert helpers
     504// All of these must either call QUnit.push() or manually do:
     505// - runLoggingCallbacks( "log", .. );
     506// - config.current.assertions.push({ .. });
     507// We attach it to the QUnit object *after* we expose the public API,
     508// otherwise `assert` will become a global variable in browsers (#341).
     509assert = {
     510        /**
     511         * Asserts rough true-ish result.
     512         * @name ok
     513         * @function
     514         * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
     515         */
     516        ok: function( result, msg ) {
     517                if ( !config.current ) {
     518                        throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
     519                }
     520                result = !!result;
     521                msg = msg || (result ? "okay" : "failed" );
     522
     523                var source,
     524                        details = {
     525                                module: config.current.module,
     526                                name: config.current.testName,
     527                                result: result,
     528                                message: msg
     529                        };
     530
     531                msg = "<span class='test-message'>" + escapeText( msg ) + "</span>";
     532
     533                if ( !result ) {
     534                        source = sourceFromStacktrace( 2 );
     535                        if ( source ) {
     536                                details.source = source;
     537                                msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr></table>";
     538                        }
     539                }
     540                runLoggingCallbacks( "log", QUnit, details );
     541                config.current.assertions.push({
     542                        result: result,
     543                        message: msg
     544                });
     545        },
     546
     547        /**
     548         * Assert that the first two arguments are equal, with an optional message.
     549         * Prints out both actual and expected values.
     550         * @name equal
     551         * @function
     552         * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
     553         */
     554        equal: function( actual, expected, message ) {
     555                /*jshint eqeqeq:false */
     556                QUnit.push( expected == actual, actual, expected, message );
     557        },
     558
     559        /**
     560         * @name notEqual
     561         * @function
     562         */
     563        notEqual: function( actual, expected, message ) {
     564                /*jshint eqeqeq:false */
     565                QUnit.push( expected != actual, actual, expected, message );
     566        },
     567
     568        /**
     569         * @name propEqual
     570         * @function
     571         */
     572        propEqual: function( actual, expected, message ) {
     573                actual = objectValues(actual);
     574                expected = objectValues(expected);
     575                QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
     576        },
     577
     578        /**
     579         * @name notPropEqual
     580         * @function
     581         */
     582        notPropEqual: function( actual, expected, message ) {
     583                actual = objectValues(actual);
     584                expected = objectValues(expected);
     585                QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
     586        },
     587
     588        /**
     589         * @name deepEqual
     590         * @function
     591         */
     592        deepEqual: function( actual, expected, message ) {
     593                QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
     594        },
     595
     596        /**
     597         * @name notDeepEqual
     598         * @function
     599         */
     600        notDeepEqual: function( actual, expected, message ) {
     601                QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
     602        },
     603
     604        /**
     605         * @name strictEqual
     606         * @function
     607         */
     608        strictEqual: function( actual, expected, message ) {
     609                QUnit.push( expected === actual, actual, expected, message );
     610        },
     611
     612        /**
     613         * @name notStrictEqual
     614         * @function
     615         */
     616        notStrictEqual: function( actual, expected, message ) {
     617                QUnit.push( expected !== actual, actual, expected, message );
     618        },
     619
     620        "throws": function( block, expected, message ) {
     621                var actual,
     622                        expectedOutput = expected,
     623                        ok = false;
     624
     625                // 'expected' is optional
     626                if ( typeof expected === "string" ) {
     627                        message = expected;
     628                        expected = null;
     629                }
     630
     631                config.current.ignoreGlobalErrors = true;
     632                try {
     633                        block.call( config.current.testEnvironment );
     634                } catch (e) {
     635                        actual = e;
     636                }
     637                config.current.ignoreGlobalErrors = false;
     638
     639                if ( actual ) {
     640                        // we don't want to validate thrown error
     641                        if ( !expected ) {
     642                                ok = true;
     643                                expectedOutput = null;
     644                        // expected is a regexp
     645                        } else if ( QUnit.objectType( expected ) === "regexp" ) {
     646                                ok = expected.test( errorString( actual ) );
     647                        // expected is a constructor
     648                        } else if ( actual instanceof expected ) {
     649                                ok = true;
     650                        // expected is a validation function which returns true is validation passed
     651                        } else if ( expected.call( {}, actual ) === true ) {
     652                                expectedOutput = null;
     653                                ok = true;
     654                        }
     655
     656                        QUnit.push( ok, actual, expectedOutput, message );
     657                } else {
     658                        QUnit.pushFailure( message, null, "No exception was thrown." );
     659                }
     660        }
     661};
     662
     663/**
     664 * @deprecated since 1.8.0
     665 * Kept assertion helpers in root for backwards compatibility.
     666 */
     667extend( QUnit, assert );
     668
     669/**
     670 * @deprecated since 1.9.0
     671 * Kept root "raises()" for backwards compatibility.
     672 * (Note that we don't introduce assert.raises).
     673 */
     674QUnit.raises = assert[ "throws" ];
     675
     676/**
     677 * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
     678 * Kept to avoid TypeErrors for undefined methods.
     679 */
     680QUnit.equals = function() {
     681        QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
     682};
     683QUnit.same = function() {
     684        QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
     685};
     686
     687// We want access to the constructor's prototype
     688(function() {
     689        function F() {}
     690        F.prototype = QUnit;
     691        QUnit = new F();
     692        // Make F QUnit's constructor so that we can add to the prototype later
     693        QUnit.constructor = F;
     694}());
     695
     696/**
     697 * Config object: Maintain internal state
     698 * Later exposed as QUnit.config
     699 * `config` initialized at top of scope
     700 */
     701config = {
     702        // The queue of tests to run
     703        queue: [],
     704
     705        // block until document ready
     706        blocking: true,
     707
     708        // when enabled, show only failing tests
     709        // gets persisted through sessionStorage and can be changed in UI via checkbox
     710        hidepassed: false,
     711
     712        // by default, run previously failed tests first
     713        // very useful in combination with "Hide passed tests" checked
     714        reorder: true,
     715
     716        // by default, modify document.title when suite is done
     717        altertitle: true,
     718
     719        // when enabled, all tests must call expect()
     720        requireExpects: false,
     721
     722        // add checkboxes that are persisted in the query-string
     723        // when enabled, the id is set to `true` as a `QUnit.config` property
     724        urlConfig: [
     725                {
     726                        id: "noglobals",
     727                        label: "Check for Globals",
     728                        tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
     729                },
     730                {
     731                        id: "notrycatch",
     732                        label: "No try-catch",
     733                        tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
     734                }
     735        ],
     736
     737        // Set of all modules.
     738        modules: {},
     739
     740        // logging callback queues
     741        begin: [],
     742        done: [],
     743        log: [],
     744        testStart: [],
     745        testDone: [],
     746        moduleStart: [],
     747        moduleDone: []
     748};
     749
     750// Export global variables, unless an 'exports' object exists,
     751// in that case we assume we're in CommonJS (dealt with on the bottom of the script)
     752if ( typeof exports === "undefined" ) {
     753        extend( window, QUnit.constructor.prototype );
     754
     755        // Expose QUnit object
     756        window.QUnit = QUnit;
     757}
     758
     759// Initialize more QUnit.config and QUnit.urlParams
     760(function() {
     761        var i,
     762                location = window.location || { search: "", protocol: "file:" },
     763                params = location.search.slice( 1 ).split( "&" ),
     764                length = params.length,
     765                urlParams = {},
     766                current;
     767
     768        if ( params[ 0 ] ) {
     769                for ( i = 0; i < length; i++ ) {
     770                        current = params[ i ].split( "=" );
     771                        current[ 0 ] = decodeURIComponent( current[ 0 ] );
     772                        // allow just a key to turn on a flag, e.g., test.html?noglobals
     773                        current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
     774                        urlParams[ current[ 0 ] ] = current[ 1 ];
     775                }
     776        }
     777
     778        QUnit.urlParams = urlParams;
     779
     780        // String search anywhere in moduleName+testName
     781        config.filter = urlParams.filter;
     782
     783        // Exact match of the module name
     784        config.module = urlParams.module;
     785
     786        config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
     787
     788        // Figure out if we're running the tests from a server or not
     789        QUnit.isLocal = location.protocol === "file:";
     790}());
     791
     792// Extend QUnit object,
     793// these after set here because they should not be exposed as global functions
     794extend( QUnit, {
     795        assert: assert,
     796
     797        config: config,
     798
     799        // Initialize the configuration options
     800        init: function() {
     801                extend( config, {
     802                        stats: { all: 0, bad: 0 },
     803                        moduleStats: { all: 0, bad: 0 },
     804                        started: +new Date(),
     805                        updateRate: 1000,
     806                        blocking: false,
     807                        autostart: true,
     808                        autorun: false,
     809                        filter: "",
     810                        queue: [],
     811                        semaphore: 1
     812                });
     813
     814                var tests, banner, result,
     815                        qunit = id( "qunit" );
     816
     817                if ( qunit ) {
     818                        qunit.innerHTML =
     819                                "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
     820                                "<h2 id='qunit-banner'></h2>" +
     821                                "<div id='qunit-testrunner-toolbar'></div>" +
     822                                "<h2 id='qunit-userAgent'></h2>" +
     823                                "<ol id='qunit-tests'></ol>";
     824                }
     825
     826                tests = id( "qunit-tests" );
     827                banner = id( "qunit-banner" );
     828                result = id( "qunit-testresult" );
     829
     830                if ( tests ) {
     831                        tests.innerHTML = "";
     832                }
     833
     834                if ( banner ) {
     835                        banner.className = "";
     836                }
     837
     838                if ( result ) {
     839                        result.parentNode.removeChild( result );
     840                }
     841
     842                if ( tests ) {
     843                        result = document.createElement( "p" );
     844                        result.id = "qunit-testresult";
     845                        result.className = "result";
     846                        tests.parentNode.insertBefore( result, tests );
     847                        result.innerHTML = "Running...<br/>&nbsp;";
     848                }
     849        },
     850
     851        // Resets the test setup. Useful for tests that modify the DOM.
     852        /*
     853        DEPRECATED: Use multiple tests instead of resetting inside a test.
     854        Use testStart or testDone for custom cleanup.
     855        This method will throw an error in 2.0, and will be removed in 2.1
     856        */
     857        reset: function() {
     858                var fixture = id( "qunit-fixture" );
     859                if ( fixture ) {
     860                        fixture.innerHTML = config.fixture;
     861                }
     862        },
     863
     864        // Trigger an event on an element.
     865        // @example triggerEvent( document.body, "click" );
     866        triggerEvent: function( elem, type, event ) {
     867                if ( document.createEvent ) {
     868                        event = document.createEvent( "MouseEvents" );
     869                        event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
     870                                0, 0, 0, 0, 0, false, false, false, false, 0, null);
     871
     872                        elem.dispatchEvent( event );
     873                } else if ( elem.fireEvent ) {
     874                        elem.fireEvent( "on" + type );
     875                }
     876        },
     877
     878        // Safe object type checking
     879        is: function( type, obj ) {
     880                return QUnit.objectType( obj ) === type;
     881        },
     882
     883        objectType: function( obj ) {
     884                if ( typeof obj === "undefined" ) {
     885                                return "undefined";
     886                // consider: typeof null === object
     887                }
     888                if ( obj === null ) {
     889                                return "null";
     890                }
     891
     892                var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
     893                        type = match && match[1] || "";
     894
     895                switch ( type ) {
     896                        case "Number":
     897                                if ( isNaN(obj) ) {
     898                                        return "nan";
     899                                }
     900                                return "number";
     901                        case "String":
     902                        case "Boolean":
     903                        case "Array":
     904                        case "Date":
     905                        case "RegExp":
     906                        case "Function":
     907                                return type.toLowerCase();
     908                }
     909                if ( typeof obj === "object" ) {
     910                        return "object";
     911                }
     912                return undefined;
     913        },
     914
     915        push: function( result, actual, expected, message ) {
     916                if ( !config.current ) {
     917                        throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
     918                }
     919
     920                var output, source,
     921                        details = {
     922                                module: config.current.module,
     923                                name: config.current.testName,
     924                                result: result,
     925                                message: message,
     926                                actual: actual,
     927                                expected: expected
     928                        };
     929
     930                message = escapeText( message ) || ( result ? "okay" : "failed" );
     931                message = "<span class='test-message'>" + message + "</span>";
     932                output = message;
     933
     934                if ( !result ) {
     935                        expected = escapeText( QUnit.jsDump.parse(expected) );
     936                        actual = escapeText( QUnit.jsDump.parse(actual) );
     937                        output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>";
     938
     939                        if ( actual !== expected ) {
     940                                output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>";
     941                                output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>";
     942                        }
     943
     944                        source = sourceFromStacktrace();
     945
     946                        if ( source ) {
     947                                details.source = source;
     948                                output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
     949                        }
     950
     951                        output += "</table>";
     952                }
     953
     954                runLoggingCallbacks( "log", QUnit, details );
     955
     956                config.current.assertions.push({
     957                        result: !!result,
     958                        message: output
     959                });
     960        },
     961
     962        pushFailure: function( message, source, actual ) {
     963                if ( !config.current ) {
     964                        throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
     965                }
     966
     967                var output,
     968                        details = {
     969                                module: config.current.module,
     970                                name: config.current.testName,
     971                                result: false,
     972                                message: message
     973                        };
     974
     975                message = escapeText( message ) || "error";
     976                message = "<span class='test-message'>" + message + "</span>";
     977                output = message;
     978
     979                output += "<table>";
     980
     981                if ( actual ) {
     982                        output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeText( actual ) + "</pre></td></tr>";
     983                }
     984
     985                if ( source ) {
     986                        details.source = source;
     987                        output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
     988                }
     989
     990                output += "</table>";
     991
     992                runLoggingCallbacks( "log", QUnit, details );
     993
     994                config.current.assertions.push({
     995                        result: false,
     996                        message: output
     997                });
     998        },
     999
     1000        url: function( params ) {
     1001                params = extend( extend( {}, QUnit.urlParams ), params );
     1002                var key,
     1003                        querystring = "?";
     1004
     1005                for ( key in params ) {
     1006                        if ( hasOwn.call( params, key ) ) {
     1007                                querystring += encodeURIComponent( key ) + "=" +
     1008                                        encodeURIComponent( params[ key ] ) + "&";
     1009                        }
     1010                }
     1011                return window.location.protocol + "//" + window.location.host +
     1012                        window.location.pathname + querystring.slice( 0, -1 );
     1013        },
     1014
     1015        extend: extend,
     1016        id: id,
     1017        addEvent: addEvent,
     1018        addClass: addClass,
     1019        hasClass: hasClass,
     1020        removeClass: removeClass
     1021        // load, equiv, jsDump, diff: Attached later
     1022});
     1023
     1024/**
     1025 * @deprecated: Created for backwards compatibility with test runner that set the hook function
     1026 * into QUnit.{hook}, instead of invoking it and passing the hook function.
     1027 * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
     1028 * Doing this allows us to tell if the following methods have been overwritten on the actual
     1029 * QUnit object.
     1030 */
     1031extend( QUnit.constructor.prototype, {
     1032
     1033        // Logging callbacks; all receive a single argument with the listed properties
     1034        // run test/logs.html for any related changes
     1035        begin: registerLoggingCallback( "begin" ),
     1036
     1037        // done: { failed, passed, total, runtime }
     1038        done: registerLoggingCallback( "done" ),
     1039
     1040        // log: { result, actual, expected, message }
     1041        log: registerLoggingCallback( "log" ),
     1042
     1043        // testStart: { name }
     1044        testStart: registerLoggingCallback( "testStart" ),
     1045
     1046        // testDone: { name, failed, passed, total, duration }
     1047        testDone: registerLoggingCallback( "testDone" ),
     1048
     1049        // moduleStart: { name }
     1050        moduleStart: registerLoggingCallback( "moduleStart" ),
     1051
     1052        // moduleDone: { name, failed, passed, total }
     1053        moduleDone: registerLoggingCallback( "moduleDone" )
     1054});
     1055
     1056if ( typeof document === "undefined" || document.readyState === "complete" ) {
     1057        config.autorun = true;
     1058}
     1059
     1060QUnit.load = function() {
     1061        runLoggingCallbacks( "begin", QUnit, {} );
     1062
     1063        // Initialize the config, saving the execution queue
     1064        var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
     1065                urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
     1066                numModules = 0,
     1067                moduleNames = [],
     1068                moduleFilterHtml = "",
     1069                urlConfigHtml = "",
     1070                oldconfig = extend( {}, config );
     1071
     1072        QUnit.init();
     1073        extend(config, oldconfig);
     1074
     1075        config.blocking = false;
     1076
     1077        len = config.urlConfig.length;
     1078
     1079        for ( i = 0; i < len; i++ ) {
     1080                val = config.urlConfig[i];
     1081                if ( typeof val === "string" ) {
     1082                        val = {
     1083                                id: val,
     1084                                label: val,
     1085                                tooltip: "[no tooltip available]"
     1086                        };
     1087                }
     1088                config[ val.id ] = QUnit.urlParams[ val.id ];
     1089                urlConfigHtml += "<input id='qunit-urlconfig-" + escapeText( val.id ) +
     1090                        "' name='" + escapeText( val.id ) +
     1091                        "' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) +
     1092                        " title='" + escapeText( val.tooltip ) +
     1093                        "'><label for='qunit-urlconfig-" + escapeText( val.id ) +
     1094                        "' title='" + escapeText( val.tooltip ) + "'>" + val.label + "</label>";
     1095        }
     1096        for ( i in config.modules ) {
     1097                if ( config.modules.hasOwnProperty( i ) ) {
     1098                        moduleNames.push(i);
     1099                }
     1100        }
     1101        numModules = moduleNames.length;
     1102        moduleNames.sort( function( a, b ) {
     1103                return a.localeCompare( b );
     1104        });
     1105        moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " +
     1106                ( config.module === undefined  ? "selected='selected'" : "" ) +
     1107                ">< All Modules ></option>";
     1108
     1109
     1110        for ( i = 0; i < numModules; i++) {
     1111                        moduleFilterHtml += "<option value='" + escapeText( encodeURIComponent(moduleNames[i]) ) + "' " +
     1112                                ( config.module === moduleNames[i] ? "selected='selected'" : "" ) +
     1113                                ">" + escapeText(moduleNames[i]) + "</option>";
     1114        }
     1115        moduleFilterHtml += "</select>";
     1116
     1117        // `userAgent` initialized at top of scope
     1118        userAgent = id( "qunit-userAgent" );
     1119        if ( userAgent ) {
     1120                userAgent.innerHTML = navigator.userAgent;
     1121        }
     1122
     1123        // `banner` initialized at top of scope
     1124        banner = id( "qunit-header" );
     1125        if ( banner ) {
     1126                banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) + "'>" + banner.innerHTML + "</a> ";
     1127        }
     1128
     1129        // `toolbar` initialized at top of scope
     1130        toolbar = id( "qunit-testrunner-toolbar" );
     1131        if ( toolbar ) {
     1132                // `filter` initialized at top of scope
     1133                filter = document.createElement( "input" );
     1134                filter.type = "checkbox";
     1135                filter.id = "qunit-filter-pass";
     1136
     1137                addEvent( filter, "click", function() {
     1138                        var tmp,
     1139                                ol = document.getElementById( "qunit-tests" );
     1140
     1141                        if ( filter.checked ) {
     1142                                ol.className = ol.className + " hidepass";
     1143                        } else {
     1144                                tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
     1145                                ol.className = tmp.replace( / hidepass /, " " );
     1146                        }
     1147                        if ( defined.sessionStorage ) {
     1148                                if (filter.checked) {
     1149                                        sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
     1150                                } else {
     1151                                        sessionStorage.removeItem( "qunit-filter-passed-tests" );
     1152                                }
     1153                        }
     1154                });
     1155
     1156                if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
     1157                        filter.checked = true;
     1158                        // `ol` initialized at top of scope
     1159                        ol = document.getElementById( "qunit-tests" );
     1160                        ol.className = ol.className + " hidepass";
     1161                }
     1162                toolbar.appendChild( filter );
     1163
     1164                // `label` initialized at top of scope
     1165                label = document.createElement( "label" );
     1166                label.setAttribute( "for", "qunit-filter-pass" );
     1167                label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." );
     1168                label.innerHTML = "Hide passed tests";
     1169                toolbar.appendChild( label );
     1170
     1171                urlConfigCheckboxesContainer = document.createElement("span");
     1172                urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
     1173                urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
     1174                // For oldIE support:
     1175                // * Add handlers to the individual elements instead of the container
     1176                // * Use "click" instead of "change"
     1177                // * Fallback from event.target to event.srcElement
     1178                addEvents( urlConfigCheckboxes, "click", function( event ) {
     1179                        var params = {},
     1180                                target = event.target || event.srcElement;
     1181                        params[ target.name ] = target.checked ? true : undefined;
     1182                        window.location = QUnit.url( params );
     1183                });
     1184                toolbar.appendChild( urlConfigCheckboxesContainer );
     1185
     1186                if (numModules > 1) {
     1187                        moduleFilter = document.createElement( "span" );
     1188                        moduleFilter.setAttribute( "id", "qunit-modulefilter-container" );
     1189                        moduleFilter.innerHTML = moduleFilterHtml;
     1190                        addEvent( moduleFilter.lastChild, "change", function() {
     1191                                var selectBox = moduleFilter.getElementsByTagName("select")[0],
     1192                                        selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
     1193
     1194                                window.location = QUnit.url({
     1195                                        module: ( selectedModule === "" ) ? undefined : selectedModule,
     1196                                        // Remove any existing filters
     1197                                        filter: undefined,
     1198                                        testNumber: undefined
     1199                                });
     1200                        });
     1201                        toolbar.appendChild(moduleFilter);
     1202                }
     1203        }
     1204
     1205        // `main` initialized at top of scope
     1206        main = id( "qunit-fixture" );
     1207        if ( main ) {
     1208                config.fixture = main.innerHTML;
     1209        }
     1210
     1211        if ( config.autostart ) {
     1212                QUnit.start();
     1213        }
     1214};
     1215
     1216addEvent( window, "load", QUnit.load );
     1217
     1218// `onErrorFnPrev` initialized at top of scope
     1219// Preserve other handlers
     1220onErrorFnPrev = window.onerror;
     1221
     1222// Cover uncaught exceptions
     1223// Returning true will suppress the default browser handler,
     1224// returning false will let it run.
     1225window.onerror = function ( error, filePath, linerNr ) {
     1226        var ret = false;
     1227        if ( onErrorFnPrev ) {
     1228                ret = onErrorFnPrev( error, filePath, linerNr );
     1229        }
     1230
     1231        // Treat return value as window.onerror itself does,
     1232        // Only do our handling if not suppressed.
     1233        if ( ret !== true ) {
     1234                if ( QUnit.config.current ) {
     1235                        if ( QUnit.config.current.ignoreGlobalErrors ) {
     1236                                return true;
     1237                        }
     1238                        QUnit.pushFailure( error, filePath + ":" + linerNr );
     1239                } else {
     1240                        QUnit.test( "global failure", extend( function() {
     1241                                QUnit.pushFailure( error, filePath + ":" + linerNr );
     1242                        }, { validTest: validTest } ) );
     1243                }
     1244                return false;
     1245        }
     1246
     1247        return ret;
     1248};
     1249
     1250function done() {
     1251        config.autorun = true;
     1252
     1253        // Log the last module results
     1254        if ( config.currentModule ) {
     1255                runLoggingCallbacks( "moduleDone", QUnit, {
     1256                        name: config.currentModule,
     1257                        failed: config.moduleStats.bad,
     1258                        passed: config.moduleStats.all - config.moduleStats.bad,
     1259                        total: config.moduleStats.all
     1260                });
     1261        }
     1262        delete config.previousModule;
     1263
     1264        var i, key,
     1265                banner = id( "qunit-banner" ),
     1266                tests = id( "qunit-tests" ),
     1267                runtime = +new Date() - config.started,
     1268                passed = config.stats.all - config.stats.bad,
     1269                html = [
     1270                        "Tests completed in ",
     1271                        runtime,
     1272                        " milliseconds.<br/>",
     1273                        "<span class='passed'>",
     1274                        passed,
     1275                        "</span> assertions of <span class='total'>",
     1276                        config.stats.all,
     1277                        "</span> passed, <span class='failed'>",
     1278                        config.stats.bad,
     1279                        "</span> failed."
     1280                ].join( "" );
     1281
     1282        if ( banner ) {
     1283                banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
     1284        }
     1285
     1286        if ( tests ) {
     1287                id( "qunit-testresult" ).innerHTML = html;
     1288        }
     1289
     1290        if ( config.altertitle && typeof document !== "undefined" && document.title ) {
     1291                // show ✖ for good, ✔ for bad suite result in title
     1292                // use escape sequences in case file gets loaded with non-utf-8-charset
     1293                document.title = [
     1294                        ( config.stats.bad ? "\u2716" : "\u2714" ),
     1295                        document.title.replace( /^[\u2714\u2716] /i, "" )
     1296                ].join( " " );
     1297        }
     1298
     1299        // clear own sessionStorage items if all tests passed
     1300        if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
     1301                // `key` & `i` initialized at top of scope
     1302                for ( i = 0; i < sessionStorage.length; i++ ) {
     1303                        key = sessionStorage.key( i++ );
     1304                        if ( key.indexOf( "qunit-test-" ) === 0 ) {
     1305                                sessionStorage.removeItem( key );
     1306                        }
     1307                }
     1308        }
     1309
     1310        // scroll back to top to show results
     1311        if ( window.scrollTo ) {
     1312                window.scrollTo(0, 0);
     1313        }
     1314
     1315        runLoggingCallbacks( "done", QUnit, {
     1316                failed: config.stats.bad,
     1317                passed: passed,
     1318                total: config.stats.all,
     1319                runtime: runtime
     1320        });
     1321}
     1322
     1323/** @return Boolean: true if this test should be ran */
     1324function validTest( test ) {
     1325        var include,
     1326                filter = config.filter && config.filter.toLowerCase(),
     1327                module = config.module && config.module.toLowerCase(),
     1328                fullName = (test.module + ": " + test.testName).toLowerCase();
     1329
     1330        // Internally-generated tests are always valid
     1331        if ( test.callback && test.callback.validTest === validTest ) {
     1332                delete test.callback.validTest;
     1333                return true;
     1334        }
     1335
     1336        if ( config.testNumber ) {
     1337                return test.testNumber === config.testNumber;
     1338        }
     1339
     1340        if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
     1341                return false;
     1342        }
     1343
     1344        if ( !filter ) {
     1345                return true;
     1346        }
     1347
     1348        include = filter.charAt( 0 ) !== "!";
     1349        if ( !include ) {
     1350                filter = filter.slice( 1 );
     1351        }
     1352
     1353        // If the filter matches, we need to honour include
     1354        if ( fullName.indexOf( filter ) !== -1 ) {
     1355                return include;
     1356        }
     1357
     1358        // Otherwise, do the opposite
     1359        return !include;
     1360}
     1361
     1362// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
     1363// Later Safari and IE10 are supposed to support error.stack as well
     1364// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
     1365function extractStacktrace( e, offset ) {
     1366        offset = offset === undefined ? 3 : offset;
     1367
     1368        var stack, include, i;
     1369
     1370        if ( e.stacktrace ) {
     1371                // Opera
     1372                return e.stacktrace.split( "\n" )[ offset + 3 ];
     1373        } else if ( e.stack ) {
     1374                // Firefox, Chrome
     1375                stack = e.stack.split( "\n" );
     1376                if (/^error$/i.test( stack[0] ) ) {
     1377                        stack.shift();
     1378                }
     1379                if ( fileName ) {
     1380                        include = [];
     1381                        for ( i = offset; i < stack.length; i++ ) {
     1382                                if ( stack[ i ].indexOf( fileName ) !== -1 ) {
     1383                                        break;
     1384                                }
     1385                                include.push( stack[ i ] );
     1386                        }
     1387                        if ( include.length ) {
     1388                                return include.join( "\n" );
     1389                        }
     1390                }
     1391                return stack[ offset ];
     1392        } else if ( e.sourceURL ) {
     1393                // Safari, PhantomJS
     1394                // hopefully one day Safari provides actual stacktraces
     1395                // exclude useless self-reference for generated Error objects
     1396                if ( /qunit.js$/.test( e.sourceURL ) ) {
     1397                        return;
     1398                }
     1399                // for actual exceptions, this is useful
     1400                return e.sourceURL + ":" + e.line;
     1401        }
     1402}
     1403function sourceFromStacktrace( offset ) {
     1404        try {
     1405                throw new Error();
     1406        } catch ( e ) {
     1407                return extractStacktrace( e, offset );
     1408        }
     1409}
     1410
     1411/**
     1412 * Escape text for attribute or text content.
     1413 */
     1414function escapeText( s ) {
     1415        if ( !s ) {
     1416                return "";
     1417        }
     1418        s = s + "";
     1419        // Both single quotes and double quotes (for attributes)
     1420        return s.replace( /['"<>&]/g, function( s ) {
     1421                switch( s ) {
     1422                        case "'":
     1423                                return "&#039;";
     1424                        case "\"":
     1425                                return "&quot;";
     1426                        case "<":
     1427                                return "&lt;";
     1428                        case ">":
     1429                                return "&gt;";
     1430                        case "&":
     1431                                return "&amp;";
     1432                }
     1433        });
     1434}
     1435
     1436function synchronize( callback, last ) {
     1437        config.queue.push( callback );
     1438
     1439        if ( config.autorun && !config.blocking ) {
     1440                process( last );
     1441        }
     1442}
     1443
     1444function process( last ) {
     1445        function next() {
     1446                process( last );
     1447        }
     1448        var start = new Date().getTime();
     1449        config.depth = config.depth ? config.depth + 1 : 1;
     1450
     1451        while ( config.queue.length && !config.blocking ) {
     1452                if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
     1453                        config.queue.shift()();
     1454                } else {
     1455                        setTimeout( next, 13 );
     1456                        break;
     1457                }
     1458        }
     1459        config.depth--;
     1460        if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
     1461                done();
     1462        }
     1463}
     1464
     1465function saveGlobal() {
     1466        config.pollution = [];
     1467
     1468        if ( config.noglobals ) {
     1469                for ( var key in window ) {
     1470                        if ( hasOwn.call( window, key ) ) {
     1471                                // in Opera sometimes DOM element ids show up here, ignore them
     1472                                if ( /^qunit-test-output/.test( key ) ) {
     1473                                        continue;
     1474                                }
     1475                                config.pollution.push( key );
     1476                        }
     1477                }
     1478        }
     1479}
     1480
     1481function checkPollution() {
     1482        var newGlobals,
     1483                deletedGlobals,
     1484                old = config.pollution;
     1485
     1486        saveGlobal();
     1487
     1488        newGlobals = diff( config.pollution, old );
     1489        if ( newGlobals.length > 0 ) {
     1490                QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
     1491        }
     1492
     1493        deletedGlobals = diff( old, config.pollution );
     1494        if ( deletedGlobals.length > 0 ) {
     1495                QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
     1496        }
     1497}
     1498
     1499// returns a new Array with the elements that are in a but not in b
     1500function diff( a, b ) {
     1501        var i, j,
     1502                result = a.slice();
     1503
     1504        for ( i = 0; i < result.length; i++ ) {
     1505                for ( j = 0; j < b.length; j++ ) {
     1506                        if ( result[i] === b[j] ) {
     1507                                result.splice( i, 1 );
     1508                                i--;
     1509                                break;
     1510                        }
     1511                }
     1512        }
     1513        return result;
     1514}
     1515
     1516function extend( a, b ) {
     1517        for ( var prop in b ) {
     1518                if ( hasOwn.call( b, prop ) ) {
     1519                        // Avoid "Member not found" error in IE8 caused by messing with window.constructor
     1520                        if ( !( prop === "constructor" && a === window ) ) {
     1521                                if ( b[ prop ] === undefined ) {
     1522                                        delete a[ prop ];
     1523                                } else {
     1524                                        a[ prop ] = b[ prop ];
     1525                                }
     1526                        }
     1527                }
     1528        }
     1529
     1530        return a;
     1531}
     1532
     1533/**
     1534 * @param {HTMLElement} elem
     1535 * @param {string} type
     1536 * @param {Function} fn
     1537 */
     1538function addEvent( elem, type, fn ) {
     1539        // Standards-based browsers
     1540        if ( elem.addEventListener ) {
     1541                elem.addEventListener( type, fn, false );
     1542        // IE
     1543        } else {
     1544                elem.attachEvent( "on" + type, fn );
     1545        }
     1546}
     1547
     1548/**
     1549 * @param {Array|NodeList} elems
     1550 * @param {string} type
     1551 * @param {Function} fn
     1552 */
     1553function addEvents( elems, type, fn ) {
     1554        var i = elems.length;
     1555        while ( i-- ) {
     1556                addEvent( elems[i], type, fn );
     1557        }
     1558}
     1559
     1560function hasClass( elem, name ) {
     1561        return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
     1562}
     1563
     1564function addClass( elem, name ) {
     1565        if ( !hasClass( elem, name ) ) {
     1566                elem.className += (elem.className ? " " : "") + name;
     1567        }
     1568}
     1569
     1570function removeClass( elem, name ) {
     1571        var set = " " + elem.className + " ";
     1572        // Class name may appear multiple times
     1573        while ( set.indexOf(" " + name + " ") > -1 ) {
     1574                set = set.replace(" " + name + " " , " ");
     1575        }
     1576        // If possible, trim it for prettiness, but not necessarily
     1577        elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, "");
     1578}
     1579
     1580function id( name ) {
     1581        return !!( typeof document !== "undefined" && document && document.getElementById ) &&
     1582                document.getElementById( name );
     1583}
     1584
     1585function registerLoggingCallback( key ) {
     1586        return function( callback ) {
     1587                config[key].push( callback );
     1588        };
     1589}
     1590
     1591// Supports deprecated method of completely overwriting logging callbacks
     1592function runLoggingCallbacks( key, scope, args ) {
     1593        var i, callbacks;
     1594        if ( QUnit.hasOwnProperty( key ) ) {
     1595                QUnit[ key ].call(scope, args );
     1596        } else {
     1597                callbacks = config[ key ];
     1598                for ( i = 0; i < callbacks.length; i++ ) {
     1599                        callbacks[ i ].call( scope, args );
     1600                }
     1601        }
     1602}
     1603
     1604// Test for equality any JavaScript type.
     1605// Author: Philippe Rathé <prathe@gmail.com>
     1606QUnit.equiv = (function() {
     1607
     1608        // Call the o related callback with the given arguments.
     1609        function bindCallbacks( o, callbacks, args ) {
     1610                var prop = QUnit.objectType( o );
     1611                if ( prop ) {
     1612                        if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
     1613                                return callbacks[ prop ].apply( callbacks, args );
     1614                        } else {
     1615                                return callbacks[ prop ]; // or undefined
     1616                        }
     1617                }
     1618        }
     1619
     1620        // the real equiv function
     1621        var innerEquiv,
     1622                // stack to decide between skip/abort functions
     1623                callers = [],
     1624                // stack to avoiding loops from circular referencing
     1625                parents = [],
     1626                parentsB = [],
     1627
     1628                getProto = Object.getPrototypeOf || function ( obj ) {
     1629                        /*jshint camelcase:false */
     1630                        return obj.__proto__;
     1631                },
     1632                callbacks = (function () {
     1633
     1634                        // for string, boolean, number and null
     1635                        function useStrictEquality( b, a ) {
     1636                                /*jshint eqeqeq:false */
     1637                                if ( b instanceof a.constructor || a instanceof b.constructor ) {
     1638                                        // to catch short annotation VS 'new' annotation of a
     1639                                        // declaration
     1640                                        // e.g. var i = 1;
     1641                                        // var j = new Number(1);
     1642                                        return a == b;
     1643                                } else {
     1644                                        return a === b;
     1645                                }
     1646                        }
     1647
     1648                        return {
     1649                                "string": useStrictEquality,
     1650                                "boolean": useStrictEquality,
     1651                                "number": useStrictEquality,
     1652                                "null": useStrictEquality,
     1653                                "undefined": useStrictEquality,
     1654
     1655                                "nan": function( b ) {
     1656                                        return isNaN( b );
     1657                                },
     1658
     1659                                "date": function( b, a ) {
     1660                                        return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
     1661                                },
     1662
     1663                                "regexp": function( b, a ) {
     1664                                        return QUnit.objectType( b ) === "regexp" &&
     1665                                                // the regex itself
     1666                                                a.source === b.source &&
     1667                                                // and its modifiers
     1668                                                a.global === b.global &&
     1669                                                // (gmi) ...
     1670                                                a.ignoreCase === b.ignoreCase &&
     1671                                                a.multiline === b.multiline &&
     1672                                                a.sticky === b.sticky;
     1673                                },
     1674
     1675                                // - skip when the property is a method of an instance (OOP)
     1676                                // - abort otherwise,
     1677                                // initial === would have catch identical references anyway
     1678                                "function": function() {
     1679                                        var caller = callers[callers.length - 1];
     1680                                        return caller !== Object && typeof caller !== "undefined";
     1681                                },
     1682
     1683                                "array": function( b, a ) {
     1684                                        var i, j, len, loop, aCircular, bCircular;
     1685
     1686                                        // b could be an object literal here
     1687                                        if ( QUnit.objectType( b ) !== "array" ) {
     1688                                                return false;
     1689                                        }
     1690
     1691                                        len = a.length;
     1692                                        if ( len !== b.length ) {
     1693                                                // safe and faster
     1694                                                return false;
     1695                                        }
     1696
     1697                                        // track reference to avoid circular references
     1698                                        parents.push( a );
     1699                                        parentsB.push( b );
     1700                                        for ( i = 0; i < len; i++ ) {
     1701                                                loop = false;
     1702                                                for ( j = 0; j < parents.length; j++ ) {
     1703                                                        aCircular = parents[j] === a[i];
     1704                                                        bCircular = parentsB[j] === b[i];
     1705                                                        if ( aCircular || bCircular ) {
     1706                                                                if ( a[i] === b[i] || aCircular && bCircular ) {
     1707                                                                        loop = true;
     1708                                                                } else {
     1709                                                                        parents.pop();
     1710                                                                        parentsB.pop();
     1711                                                                        return false;
     1712                                                                }
     1713                                                        }
     1714                                                }
     1715                                                if ( !loop && !innerEquiv(a[i], b[i]) ) {
     1716                                                        parents.pop();
     1717                                                        parentsB.pop();
     1718                                                        return false;
     1719                                                }
     1720                                        }
     1721                                        parents.pop();
     1722                                        parentsB.pop();
     1723                                        return true;
     1724                                },
     1725
     1726                                "object": function( b, a ) {
     1727                                        /*jshint forin:false */
     1728                                        var i, j, loop, aCircular, bCircular,
     1729                                                // Default to true
     1730                                                eq = true,
     1731                                                aProperties = [],
     1732                                                bProperties = [];
     1733
     1734                                        // comparing constructors is more strict than using
     1735                                        // instanceof
     1736                                        if ( a.constructor !== b.constructor ) {
     1737                                                // Allow objects with no prototype to be equivalent to
     1738                                                // objects with Object as their constructor.
     1739                                                if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
     1740                                                        ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
     1741                                                                return false;
     1742                                                }
     1743                                        }
     1744
     1745                                        // stack constructor before traversing properties
     1746                                        callers.push( a.constructor );
     1747
     1748                                        // track reference to avoid circular references
     1749                                        parents.push( a );
     1750                                        parentsB.push( b );
     1751
     1752                                        // be strict: don't ensure hasOwnProperty and go deep
     1753                                        for ( i in a ) {
     1754                                                loop = false;
     1755                                                for ( j = 0; j < parents.length; j++ ) {
     1756                                                        aCircular = parents[j] === a[i];
     1757                                                        bCircular = parentsB[j] === b[i];
     1758                                                        if ( aCircular || bCircular ) {
     1759                                                                if ( a[i] === b[i] || aCircular && bCircular ) {
     1760                                                                        loop = true;
     1761                                                                } else {
     1762                                                                        eq = false;
     1763                                                                        break;
     1764                                                                }
     1765                                                        }
     1766                                                }
     1767                                                aProperties.push(i);
     1768                                                if ( !loop && !innerEquiv(a[i], b[i]) ) {
     1769                                                        eq = false;
     1770                                                        break;
     1771                                                }
     1772                                        }
     1773
     1774                                        parents.pop();
     1775                                        parentsB.pop();
     1776                                        callers.pop(); // unstack, we are done
     1777
     1778                                        for ( i in b ) {
     1779                                                bProperties.push( i ); // collect b's properties
     1780                                        }
     1781
     1782                                        // Ensures identical properties name
     1783                                        return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
     1784                                }
     1785                        };
     1786                }());
     1787
     1788        innerEquiv = function() { // can take multiple arguments
     1789                var args = [].slice.apply( arguments );
     1790                if ( args.length < 2 ) {
     1791                        return true; // end transition
     1792                }
     1793
     1794                return (function( a, b ) {
     1795                        if ( a === b ) {
     1796                                return true; // catch the most you can
     1797                        } else if ( a === null || b === null || typeof a === "undefined" ||
     1798                                        typeof b === "undefined" ||
     1799                                        QUnit.objectType(a) !== QUnit.objectType(b) ) {
     1800                                return false; // don't lose time with error prone cases
     1801                        } else {
     1802                                return bindCallbacks(a, callbacks, [ b, a ]);
     1803                        }
     1804
     1805                        // apply transition with (1..n) arguments
     1806                }( args[0], args[1] ) && innerEquiv.apply( this, args.splice(1, args.length - 1 )) );
     1807        };
     1808
     1809        return innerEquiv;
     1810}());
     1811
     1812/**
     1813 * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
     1814 * http://flesler.blogspot.com Licensed under BSD
     1815 * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
     1816 *
     1817 * @projectDescription Advanced and extensible data dumping for Javascript.
     1818 * @version 1.0.0
     1819 * @author Ariel Flesler
     1820 * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
     1821 */
     1822QUnit.jsDump = (function() {
     1823        function quote( str ) {
     1824                return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\"";
     1825        }
     1826        function literal( o ) {
     1827                return o + "";
     1828        }
     1829        function join( pre, arr, post ) {
     1830                var s = jsDump.separator(),
     1831                        base = jsDump.indent(),
     1832                        inner = jsDump.indent(1);
     1833                if ( arr.join ) {
     1834                        arr = arr.join( "," + s + inner );
     1835                }
     1836                if ( !arr ) {
     1837                        return pre + post;
     1838                }
     1839                return [ pre, inner + arr, base + post ].join(s);
     1840        }
     1841        function array( arr, stack ) {
     1842                var i = arr.length, ret = new Array(i);
     1843                this.up();
     1844                while ( i-- ) {
     1845                        ret[i] = this.parse( arr[i] , undefined , stack);
     1846                }
     1847                this.down();
     1848                return join( "[", ret, "]" );
     1849        }
     1850
     1851        var reName = /^function (\w+)/,
     1852                jsDump = {
     1853                        // type is used mostly internally, you can fix a (custom)type in advance
     1854                        parse: function( obj, type, stack ) {
     1855                                stack = stack || [ ];
     1856                                var inStack, res,
     1857                                        parser = this.parsers[ type || this.typeOf(obj) ];
     1858
     1859                                type = typeof parser;
     1860                                inStack = inArray( obj, stack );
     1861
     1862                                if ( inStack !== -1 ) {
     1863                                        return "recursion(" + (inStack - stack.length) + ")";
     1864                                }
     1865                                if ( type === "function" )  {
     1866                                        stack.push( obj );
     1867                                        res = parser.call( this, obj, stack );
     1868                                        stack.pop();
     1869                                        return res;
     1870                                }
     1871                                return ( type === "string" ) ? parser : this.parsers.error;
     1872                        },
     1873                        typeOf: function( obj ) {
     1874                                var type;
     1875                                if ( obj === null ) {
     1876                                        type = "null";
     1877                                } else if ( typeof obj === "undefined" ) {
     1878                                        type = "undefined";
     1879                                } else if ( QUnit.is( "regexp", obj) ) {
     1880                                        type = "regexp";
     1881                                } else if ( QUnit.is( "date", obj) ) {
     1882                                        type = "date";
     1883                                } else if ( QUnit.is( "function", obj) ) {
     1884                                        type = "function";
     1885                                } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
     1886                                        type = "window";
     1887                                } else if ( obj.nodeType === 9 ) {
     1888                                        type = "document";
     1889                                } else if ( obj.nodeType ) {
     1890                                        type = "node";
     1891                                } else if (
     1892                                        // native arrays
     1893                                        toString.call( obj ) === "[object Array]" ||
     1894                                        // NodeList objects
     1895                                        ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
     1896                                ) {
     1897                                        type = "array";
     1898                                } else if ( obj.constructor === Error.prototype.constructor ) {
     1899                                        type = "error";
     1900                                } else {
     1901                                        type = typeof obj;
     1902                                }
     1903                                return type;
     1904                        },
     1905                        separator: function() {
     1906                                return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? "&nbsp;" : " ";
     1907                        },
     1908                        // extra can be a number, shortcut for increasing-calling-decreasing
     1909                        indent: function( extra ) {
     1910                                if ( !this.multiline ) {
     1911                                        return "";
     1912                                }
     1913                                var chr = this.indentChar;
     1914                                if ( this.HTML ) {
     1915                                        chr = chr.replace( /\t/g, "   " ).replace( / /g, "&nbsp;" );
     1916                                }
     1917                                return new Array( this.depth + ( extra || 0 ) ).join(chr);
     1918                        },
     1919                        up: function( a ) {
     1920                                this.depth += a || 1;
     1921                        },
     1922                        down: function( a ) {
     1923                                this.depth -= a || 1;
     1924                        },
     1925                        setParser: function( name, parser ) {
     1926                                this.parsers[name] = parser;
     1927                        },
     1928                        // The next 3 are exposed so you can use them
     1929                        quote: quote,
     1930                        literal: literal,
     1931                        join: join,
     1932                        //
     1933                        depth: 1,
     1934                        // This is the list of parsers, to modify them, use jsDump.setParser
     1935                        parsers: {
     1936                                window: "[Window]",
     1937                                document: "[Document]",
     1938                                error: function(error) {
     1939                                        return "Error(\"" + error.message + "\")";
     1940                                },
     1941                                unknown: "[Unknown]",
     1942                                "null": "null",
     1943                                "undefined": "undefined",
     1944                                "function": function( fn ) {
     1945                                        var ret = "function",
     1946                                                // functions never have name in IE
     1947                                                name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
     1948
     1949                                        if ( name ) {
     1950                                                ret += " " + name;
     1951                                        }
     1952                                        ret += "( ";
     1953
     1954                                        ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
     1955                                        return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
     1956                                },
     1957                                array: array,
     1958                                nodelist: array,
     1959                                "arguments": array,
     1960                                object: function( map, stack ) {
     1961                                        /*jshint forin:false */
     1962                                        var ret = [ ], keys, key, val, i;
     1963                                        QUnit.jsDump.up();
     1964                                        keys = [];
     1965                                        for ( key in map ) {
     1966                                                keys.push( key );
     1967                                        }
     1968                                        keys.sort();
     1969                                        for ( i = 0; i < keys.length; i++ ) {
     1970                                                key = keys[ i ];
     1971                                                val = map[ key ];
     1972                                                ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
     1973                                        }
     1974                                        QUnit.jsDump.down();
     1975                                        return join( "{", ret, "}" );
     1976                                },
     1977                                node: function( node ) {
     1978                                        var len, i, val,
     1979                                                open = QUnit.jsDump.HTML ? "&lt;" : "<",
     1980                                                close = QUnit.jsDump.HTML ? "&gt;" : ">",
     1981                                                tag = node.nodeName.toLowerCase(),
     1982                                                ret = open + tag,
     1983                                                attrs = node.attributes;
     1984
     1985                                        if ( attrs ) {
     1986                                                for ( i = 0, len = attrs.length; i < len; i++ ) {
     1987                                                        val = attrs[i].nodeValue;
     1988                                                        // IE6 includes all attributes in .attributes, even ones not explicitly set.
     1989                                                        // Those have values like undefined, null, 0, false, "" or "inherit".
     1990                                                        if ( val && val !== "inherit" ) {
     1991                                                                ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
     1992                                                        }
     1993                                                }
     1994                                        }
     1995                                        ret += close;
     1996
     1997                                        // Show content of TextNode or CDATASection
     1998                                        if ( node.nodeType === 3 || node.nodeType === 4 ) {
     1999                                                ret += node.nodeValue;
     2000                                        }
     2001
     2002                                        return ret + open + "/" + tag + close;
     2003                                },
     2004                                // function calls it internally, it's the arguments part of the function
     2005                                functionArgs: function( fn ) {
     2006                                        var args,
     2007                                                l = fn.length;
     2008
     2009                                        if ( !l ) {
     2010                                                return "";
     2011                                        }
     2012
     2013                                        args = new Array(l);
     2014                                        while ( l-- ) {
     2015                                                // 97 is 'a'
     2016                                                args[l] = String.fromCharCode(97+l);
     2017                                        }
     2018                                        return " " + args.join( ", " ) + " ";
     2019                                },
     2020                                // object calls it internally, the key part of an item in a map
     2021                                key: quote,
     2022                                // function calls it internally, it's the content of the function
     2023                                functionCode: "[code]",
     2024                                // node calls it internally, it's an html attribute value
     2025                                attribute: quote,
     2026                                string: quote,
     2027                                date: quote,
     2028                                regexp: literal,
     2029                                number: literal,
     2030                                "boolean": literal
     2031                        },
     2032                        // if true, entities are escaped ( <, >, \t, space and \n )
     2033                        HTML: false,
     2034                        // indentation unit
     2035                        indentChar: "  ",
     2036                        // if true, items in a collection, are separated by a \n, else just a space.
     2037                        multiline: true
     2038                };
     2039
     2040        return jsDump;
     2041}());
     2042
     2043// from jquery.js
     2044function inArray( elem, array ) {
     2045        if ( array.indexOf ) {
     2046                return array.indexOf( elem );
     2047        }
     2048
     2049        for ( var i = 0, length = array.length; i < length; i++ ) {
     2050                if ( array[ i ] === elem ) {
     2051                        return i;
     2052                }
     2053        }
     2054
     2055        return -1;
     2056}
     2057
     2058/*
     2059 * Javascript Diff Algorithm
     2060 *  By John Resig (http://ejohn.org/)
     2061 *  Modified by Chu Alan "sprite"
     2062 *
     2063 * Released under the MIT license.
     2064 *
     2065 * More Info:
     2066 *  http://ejohn.org/projects/javascript-diff-algorithm/
     2067 *
     2068 * Usage: QUnit.diff(expected, actual)
     2069 *
     2070 * 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"
     2071 */
     2072QUnit.diff = (function() {
     2073        /*jshint eqeqeq:false, eqnull:true */
     2074        function diff( o, n ) {
     2075                var i,
     2076                        ns = {},
     2077                        os = {};
     2078
     2079                for ( i = 0; i < n.length; i++ ) {
     2080                        if ( !hasOwn.call( ns, n[i] ) ) {
     2081                                ns[ n[i] ] = {
     2082                                        rows: [],
     2083                                        o: null
     2084                                };
     2085                        }
     2086                        ns[ n[i] ].rows.push( i );
     2087                }
     2088
     2089                for ( i = 0; i < o.length; i++ ) {
     2090                        if ( !hasOwn.call( os, o[i] ) ) {
     2091                                os[ o[i] ] = {
     2092                                        rows: [],
     2093                                        n: null
     2094                                };
     2095                        }
     2096                        os[ o[i] ].rows.push( i );
     2097                }
     2098
     2099                for ( i in ns ) {
     2100                        if ( hasOwn.call( ns, i ) ) {
     2101                                if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
     2102                                        n[ ns[i].rows[0] ] = {
     2103                                                text: n[ ns[i].rows[0] ],
     2104                                                row: os[i].rows[0]
     2105                                        };
     2106                                        o[ os[i].rows[0] ] = {
     2107                                                text: o[ os[i].rows[0] ],
     2108                                                row: ns[i].rows[0]
     2109                                        };
     2110                                }
     2111                        }
     2112                }
     2113
     2114                for ( i = 0; i < n.length - 1; i++ ) {
     2115                        if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
     2116                                                n[ i + 1 ] == o[ n[i].row + 1 ] ) {
     2117
     2118                                n[ i + 1 ] = {
     2119                                        text: n[ i + 1 ],
     2120                                        row: n[i].row + 1
     2121                                };
     2122                                o[ n[i].row + 1 ] = {
     2123                                        text: o[ n[i].row + 1 ],
     2124                                        row: i + 1
     2125                                };
     2126                        }
     2127                }
     2128
     2129                for ( i = n.length - 1; i > 0; i-- ) {
     2130                        if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
     2131                                                n[ i - 1 ] == o[ n[i].row - 1 ]) {
     2132
     2133                                n[ i - 1 ] = {
     2134                                        text: n[ i - 1 ],
     2135                                        row: n[i].row - 1
     2136                                };
     2137                                o[ n[i].row - 1 ] = {
     2138                                        text: o[ n[i].row - 1 ],
     2139                                        row: i - 1
     2140                                };
     2141                        }
     2142                }
     2143
     2144                return {
     2145                        o: o,
     2146                        n: n
     2147                };
     2148        }
     2149
     2150        return function( o, n ) {
     2151                o = o.replace( /\s+$/, "" );
     2152                n = n.replace( /\s+$/, "" );
     2153
     2154                var i, pre,
     2155                        str = "",
     2156                        out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
     2157                        oSpace = o.match(/\s+/g),
     2158                        nSpace = n.match(/\s+/g);
     2159
     2160                if ( oSpace == null ) {
     2161                        oSpace = [ " " ];
     2162                }
     2163                else {
     2164                        oSpace.push( " " );
     2165                }
     2166
     2167                if ( nSpace == null ) {
     2168                        nSpace = [ " " ];
     2169                }
     2170                else {
     2171                        nSpace.push( " " );
     2172                }
     2173
     2174                if ( out.n.length === 0 ) {
     2175                        for ( i = 0; i < out.o.length; i++ ) {
     2176                                str += "<del>" + out.o[i] + oSpace[i] + "</del>";
     2177                        }
     2178                }
     2179                else {
     2180                        if ( out.n[0].text == null ) {
     2181                                for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
     2182                                        str += "<del>" + out.o[n] + oSpace[n] + "</del>";
     2183                                }
     2184                        }
     2185
     2186                        for ( i = 0; i < out.n.length; i++ ) {
     2187                                if (out.n[i].text == null) {
     2188                                        str += "<ins>" + out.n[i] + nSpace[i] + "</ins>";
     2189                                }
     2190                                else {
     2191                                        // `pre` initialized at top of scope
     2192                                        pre = "";
     2193
     2194                                        for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
     2195                                                pre += "<del>" + out.o[n] + oSpace[n] + "</del>";
     2196                                        }
     2197                                        str += " " + out.n[i].text + nSpace[i] + pre;
     2198                                }
     2199                        }
     2200                }
     2201
     2202                return str;
     2203        };
     2204}());
     2205
     2206// for CommonJS environments, export everything
     2207if ( typeof exports !== "undefined" ) {
     2208        extend( exports, QUnit.constructor.prototype );
     2209}
     2210
     2211// get at whatever the global object is, like window in browsers
     2212}( (function() {return this;}.call()) ));
  • tests/qunit/wp-admin/js/password-strength-meter.js

    Property changes on: tests/qunit/vendor/qunit.js
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1jQuery(function() {
     2        module('password-strength-meter');
     3
     4        test('missmached passwords should return 5', function(){
     5                equal( passwordStrength( 'password1',  'username', 'password2' ) , 5, 'miss matched passwords return 5');
     6        });
     7
     8        test('passwords shorter than 4 charachters should return 1', function(){
     9                equal( passwordStrength( 'abc',  'username', 'abc' ) , 1, 'short passwords return 1');
     10        });
     11
     12        test('long complicated passwords should return 4', function(){
     13                var password = function( length ){
     14                        var possability = 'abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
     15                                retVal = "";
     16                        for( var i = 0, n = possability.length; i < length; ++i) {
     17                                retVal += possability.charAt( Math.floor( Math.random() * n ) );
     18                        }
     19                        return retVal + 'aB2'; // add a lower case, uppercase and number just to make sure we always have one of each
     20                },
     21                twofifty = password( 250 );
     22
     23                equal( passwordStrength( twofifty , 'username', twofifty ), 4, '250 charachter complicated password returns 4');
     24        });
     25
     26        test('short uncomplicated passwords should return 2', function(){
     27                var letters = 'aaaa',
     28                        numbers = '1111',
     29                        uppercase = 'AAAA';
     30                equal( passwordStrength( letters, 'username', letters ), 2, 'password of `' + letters + '` returns 2' );
     31                equal( passwordStrength( numbers, 'username', numbers ), 2, 'password of `' + numbers + '` returns 2' );
     32                equal( passwordStrength( uppercase, 'username', uppercase ), 2, 'password of `' + uppercase + '` returns 2' );
     33        });     
     34});