r113529 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r113528‎ | r113529 | r113530 >
Date:21:50, 9 March 2012
Author:tparscal
Status:deferred
Tags:
Comment:
Updated QUnit
Modified paths:
  • /trunk/extensions/VisualEditor/modules/qunit/qunit.css (modified) (history)
  • /trunk/extensions/VisualEditor/modules/qunit/qunit.js (modified) (history)

Diff [purge]

Index: trunk/extensions/VisualEditor/modules/qunit/qunit.css
@@ -1,9 +1,9 @@
22 /**
3 - * QUnit 1.2.0pre - A JavaScript Unit Testing Framework
 3+ * QUnit v1.4.0pre - A JavaScript Unit Testing Framework
44 *
55 * http://docs.jquery.com/QUnit
66 *
7 - * Copyright (c) 2011 John Resig, Jörn Zaefferer
 7+ * Copyright (c) 2012 John Resig, Jörn Zaefferer
88 * Dual licensed under the MIT (MIT-LICENSE.txt)
99 * or GPL (GPL-LICENSE.txt) licenses.
1010 */
@@ -54,6 +54,10 @@
5555 color: #fff;
5656 }
5757
 58+#qunit-header label {
 59+ display: inline-block;
 60+}
 61+
5862 #qunit-banner {
5963 height: 5px;
6064 }
@@ -223,4 +227,6 @@
224228 position: absolute;
225229 top: -10000px;
226230 left: -10000px;
 231+ width: 1000px;
 232+ height: 1000px;
227233 }
Index: trunk/extensions/VisualEditor/modules/qunit/qunit.js
@@ -1,9 +1,9 @@
22 /**
3 - * QUnit 1.2.0pre - A JavaScript Unit Testing Framework
 3+ * QUnit v1.4.0pre - A JavaScript Unit Testing Framework
44 *
55 * http://docs.jquery.com/QUnit
66 *
7 - * Copyright (c) 2011 John Resig, Jörn Zaefferer
 7+ * Copyright (c) 2012 John Resig, Jörn Zaefferer
88 * Dual licensed under the MIT (MIT-LICENSE.txt)
99 * or GPL (GPL-LICENSE.txt) licenses.
1010 */
@@ -13,23 +13,25 @@
1414 var defined = {
1515 setTimeout: typeof window.setTimeout !== "undefined",
1616 sessionStorage: (function() {
 17+ var x = "qunit-test-string";
1718 try {
18 - return !!sessionStorage.getItem;
 19+ sessionStorage.setItem(x, x);
 20+ sessionStorage.removeItem(x);
 21+ return true;
1922 } catch(e) {
2023 return false;
2124 }
22 - })()
 25+ }())
2326 };
2427
2528 var testId = 0,
2629 toString = Object.prototype.toString,
2730 hasOwn = Object.prototype.hasOwnProperty;
2831
29 -var Test = function(name, testName, expected, testEnvironmentArg, async, callback) {
 32+var Test = function(name, testName, expected, async, callback) {
3033 this.name = name;
3134 this.testName = testName;
3235 this.expected = expected;
33 - this.testEnvironmentArg = testEnvironmentArg;
3436 this.async = async;
3537 this.callback = callback;
3638 this.assertions = [];
@@ -62,6 +64,10 @@
6365 runLoggingCallbacks( 'moduleStart', QUnit, {
6466 name: this.module
6567 } );
 68+ } else if (config.autorun) {
 69+ runLoggingCallbacks( 'moduleStart', QUnit, {
 70+ name: this.module
 71+ } );
6672 }
6773
6874 config.current = this;
@@ -69,9 +75,6 @@
7076 setup: function() {},
7177 teardown: function() {}
7278 }, this.moduleTestEnvironment);
73 - if (this.testEnvironmentArg) {
74 - extend(this.testEnvironment, this.testEnvironmentArg);
75 - }
7679
7780 runLoggingCallbacks( 'testStart', QUnit, {
7881 name: this.testName,
@@ -82,14 +85,17 @@
8386 // TODO why??
8487 QUnit.current_testEnvironment = this.testEnvironment;
8588
 89+ if ( !config.pollution ) {
 90+ saveGlobal();
 91+ }
 92+ if ( config.notrycatch ) {
 93+ this.testEnvironment.setup.call(this.testEnvironment);
 94+ return;
 95+ }
8696 try {
87 - if ( !config.pollution ) {
88 - saveGlobal();
89 - }
90 -
9197 this.testEnvironment.setup.call(this.testEnvironment);
9298 } catch(e) {
93 - QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message );
 99+ QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
94100 }
95101 },
96102 run: function() {
@@ -105,8 +111,7 @@
106112 try {
107113 this.callback.call(this.testEnvironment);
108114 } catch(e) {
109 - fail("Test " + this.testName + " died, exception and test follows", e, this.callback);
110 - QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) );
 115+ QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + ": " + e.message, extractStacktrace( e, 1 ) );
111116 // else next test will carry the responsibility
112117 saveGlobal();
113118
@@ -118,20 +123,28 @@
119124 },
120125 teardown: function() {
121126 config.current = this;
122 - try {
 127+ if ( config.notrycatch ) {
123128 this.testEnvironment.teardown.call(this.testEnvironment);
124 - checkPollution();
125 - } catch(e) {
126 - QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message );
 129+ return;
 130+ } else {
 131+ try {
 132+ this.testEnvironment.teardown.call(this.testEnvironment);
 133+ } catch(e) {
 134+ QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
 135+ }
127136 }
 137+ checkPollution();
128138 },
129139 finish: function() {
130140 config.current = this;
131141 if ( this.expected != null && this.expected != this.assertions.length ) {
132 - QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
 142+ QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
 143+ } else if ( this.expected == null && !this.assertions.length ) {
 144+ QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions." );
133145 }
134146
135147 var good = 0, bad = 0,
 148+ li, i,
136149 tests = id("qunit-tests");
137150
138151 config.stats.all += this.assertions.length;
@@ -140,10 +153,10 @@
141154 if ( tests ) {
142155 var ol = document.createElement("ol");
143156
144 - for ( var i = 0; i < this.assertions.length; i++ ) {
 157+ for ( i = 0; i < this.assertions.length; i++ ) {
145158 var assertion = this.assertions[i];
146159
147 - var li = document.createElement("li");
 160+ li = document.createElement("li");
148161 li.className = assertion.result ? "pass" : "fail";
149162 li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed");
150163 ol.appendChild( li );
@@ -166,7 +179,7 @@
167180 }
168181 }
169182
170 - if (bad == 0) {
 183+ if (bad === 0) {
171184 ol.style.display = "none";
172185 }
173186
@@ -193,7 +206,7 @@
194207 }
195208 });
196209
197 - var li = id(this.id);
 210+ li = id(this.id);
198211 li.className = bad ? "fail" : "pass";
199212 li.removeChild( li.firstChild );
200213 li.appendChild( b );
@@ -201,7 +214,7 @@
202215 li.appendChild( ol );
203216
204217 } else {
205 - for ( var i = 0; i < this.assertions.length; i++ ) {
 218+ for ( i = 0; i < this.assertions.length; i++ ) {
206219 if ( !this.assertions[i].result ) {
207220 bad++;
208221 config.stats.bad++;
@@ -210,11 +223,7 @@
211224 }
212225 }
213226
214 - try {
215 - QUnit.reset();
216 - } catch(e) {
217 - fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset);
218 - }
 227+ QUnit.reset();
219228
220229 runLoggingCallbacks( 'testDone', QUnit, {
221230 name: this.testName,
@@ -251,7 +260,7 @@
252261 run();
253262 } else {
254263 synchronize(run, true);
255 - };
 264+ }
256265 }
257266
258267 };
@@ -274,17 +283,12 @@
275284 },
276285
277286 test: function(testName, expected, callback, async) {
278 - var name = '<span class="test-name">' + testName + '</span>', testEnvironmentArg;
 287+ var name = '<span class="test-name">' + escapeInnerText(testName) + '</span>';
279288
280289 if ( arguments.length === 2 ) {
281290 callback = expected;
282291 expected = null;
283292 }
284 - // is 2nd argument a testEnvironment?
285 - if ( expected && typeof expected === 'object') {
286 - testEnvironmentArg = expected;
287 - expected = null;
288 - }
289293
290294 if ( config.currentModule ) {
291295 name = '<span class="module-name">' + config.currentModule + "</span>: " + name;
@@ -294,49 +298,45 @@
295299 return;
296300 }
297301
298 - var test = new Test(name, testName, expected, testEnvironmentArg, async, callback);
 302+ var test = new Test(name, testName, expected, async, callback);
299303 test.module = config.currentModule;
300304 test.moduleTestEnvironment = config.currentModuleTestEnviroment;
301305 test.queue();
302306 },
303307
304 - /**
305 - * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
306 - */
 308+ // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
307309 expect: function(asserts) {
308310 config.current.expected = asserts;
309311 },
310312
311 - /**
312 - * Asserts true.
313 - * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
314 - */
315 - ok: function(a, msg) {
316 - a = !!a;
 313+ // Asserts true.
 314+ // @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
 315+ ok: function(result, msg) {
 316+ if (!config.current) {
 317+ throw new Error("ok() assertion outside test context, was " + sourceFromStacktrace(2));
 318+ }
 319+ result = !!result;
317320 var details = {
318 - result: a,
 321+ result: result,
319322 message: msg
320323 };
321 - msg = escapeInnerText(msg);
 324+ msg = escapeInnerText(msg || (result ? "okay" : "failed"));
 325+ if ( !result ) {
 326+ var source = sourceFromStacktrace(2);
 327+ if (source) {
 328+ details.source = source;
 329+ msg += '<table><tr class="test-source"><th>Source: </th><td><pre>' + escapeInnerText(source) + '</pre></td></tr></table>';
 330+ }
 331+ }
322332 runLoggingCallbacks( 'log', QUnit, details );
323333 config.current.assertions.push({
324 - result: a,
 334+ result: result,
325335 message: msg
326336 });
327337 },
328338
329 - /**
330 - * Checks that the first two arguments are equal, with an optional message.
331 - * Prints out both actual and expected values.
332 - *
333 - * Prefered to ok( actual == expected, message )
334 - *
335 - * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
336 - *
337 - * @param Object actual
338 - * @param Object expected
339 - * @param String message (optional)
340 - */
 339+ // Checks that the first two arguments are equal, with an optional message. Prints out both actual and expected values.
 340+ // @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
341341 equal: function(actual, expected, message) {
342342 QUnit.push(expected == actual, actual, expected, message);
343343 },
@@ -440,16 +440,21 @@
441441
442442 //We want access to the constructor's prototype
443443 (function() {
444 - function F(){};
 444+ function F(){}
445445 F.prototype = QUnit;
446446 QUnit = new F();
447447 //Make F QUnit's constructor so that we can add to the prototype later
448448 QUnit.constructor = F;
449 -})();
 449+}());
450450
451 -// Backwards compatibility, deprecated
452 -QUnit.equals = QUnit.equal;
453 -QUnit.same = QUnit.deepEqual;
 451+// deprecated; still export them to window to provide clear error messages
 452+// next step: remove entirely
 453+QUnit.equals = function() {
 454+ QUnit.push(false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead");
 455+};
 456+QUnit.same = function() {
 457+ QUnit.push(false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead");
 458+};
454459
455460 // Maintain internal state
456461 var config = {
@@ -504,17 +509,14 @@
505510 config.filter = urlParams.filter;
506511
507512 // Figure out if we're running the tests from a server or not
508 - QUnit.isLocal = !!(location.protocol === 'file:');
509 -})();
 513+ QUnit.isLocal = location.protocol === 'file:';
 514+}());
510515
511516 // Expose the API as global variables, unless an 'exports'
512 -// object exists, in that case we assume we're in CommonJS
 517+// object exists, in that case we assume we're in CommonJS - export everything at the end
513518 if ( typeof exports === "undefined" || typeof require === "undefined" ) {
514519 extend(window, QUnit);
515520 window.QUnit = QUnit;
516 -} else {
517 - extend(exports, QUnit);
518 - exports.QUnit = QUnit;
519521 }
520522
521523 // define these after exposing globals to keep them in these QUnit namespace only
@@ -526,7 +528,7 @@
527529 extend(config, {
528530 stats: { all: 0, bad: 0 },
529531 moduleStats: { all: 0, bad: 0 },
530 - started: +new Date,
 532+ started: +new Date(),
531533 updateRate: 1000,
532534 blocking: false,
533535 autostart: true,
@@ -536,6 +538,16 @@
537539 semaphore: 0
538540 });
539541
 542+ var qunit = id( "qunit" );
 543+ if ( qunit ) {
 544+ qunit.innerHTML =
 545+ '<h1 id="qunit-header">' + escapeInnerText( document.title ) + '</h1>' +
 546+ '<h2 id="qunit-banner"></h2>' +
 547+ '<div id="qunit-testrunner-toolbar"></div>' +
 548+ '<h2 id="qunit-userAgent"></h2>' +
 549+ '<ol id="qunit-tests"></ol>';
 550+ }
 551+
540552 var tests = id( "qunit-tests" ),
541553 banner = id( "qunit-banner" ),
542554 result = id( "qunit-testresult" );
@@ -561,11 +573,8 @@
562574 }
563575 },
564576
565 - /**
566 - * Resets the test setup. Useful for tests that modify the DOM.
567 - *
568 - * If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
569 - */
 577+ // Resets the test setup. Useful for tests that modify the DOM.
 578+ // If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
570579 reset: function() {
571580 if ( window.jQuery ) {
572581 jQuery( "#qunit-fixture" ).html( config.fixture );
@@ -577,14 +586,8 @@
578587 }
579588 },
580589
581 - /**
582 - * Trigger an event on an element.
583 - *
584 - * @example triggerEvent( document.body, "click" );
585 - *
586 - * @param DOMElement elem
587 - * @param String type
588 - */
 590+ // Trigger an event on an element.
 591+ // @example triggerEvent( document.body, "click" );
589592 triggerEvent: function( elem, type, event ) {
590593 if ( document.createEvent ) {
591594 event = document.createEvent("MouseEvents");
@@ -615,19 +618,18 @@
616619 var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || '';
617620
618621 switch (type) {
619 - case 'Number':
620 - if (isNaN(obj)) {
621 - return "nan";
622 - } else {
623 - return "number";
624 - }
625 - case 'String':
626 - case 'Boolean':
627 - case 'Array':
628 - case 'Date':
629 - case 'RegExp':
630 - case 'Function':
631 - return type.toLowerCase();
 622+ case 'Number':
 623+ if (isNaN(obj)) {
 624+ return "nan";
 625+ }
 626+ return "number";
 627+ case 'String':
 628+ case 'Boolean':
 629+ case 'Array':
 630+ case 'Date':
 631+ case 'RegExp':
 632+ case 'Function':
 633+ return type.toLowerCase();
632634 }
633635 if (typeof obj === "object") {
634636 return "object";
@@ -636,6 +638,9 @@
637639 },
638640
639641 push: function(result, actual, expected, message) {
 642+ if (!config.current) {
 643+ throw new Error("assertion outside test context, was " + sourceFromStacktrace());
 644+ }
640645 var details = {
641646 result: result,
642647 message: message,
@@ -645,21 +650,22 @@
646651
647652 message = escapeInnerText(message) || (result ? "okay" : "failed");
648653 message = '<span class="test-message">' + message + "</span>";
649 - expected = escapeInnerText(QUnit.jsDump.parse(expected));
650 - actual = escapeInnerText(QUnit.jsDump.parse(actual));
651 - var output = message + '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
652 - if (actual != expected) {
653 - output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
654 - output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) +'</pre></td></tr>';
655 - }
 654+ var output = message;
656655 if (!result) {
 656+ expected = escapeInnerText(QUnit.jsDump.parse(expected));
 657+ actual = escapeInnerText(QUnit.jsDump.parse(actual));
 658+ output += '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
 659+ if (actual != expected) {
 660+ output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
 661+ output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) +'</pre></td></tr>';
 662+ }
657663 var source = sourceFromStacktrace();
658664 if (source) {
659665 details.source = source;
660666 output += '<tr class="test-source"><th>Source: </th><td><pre>' + escapeInnerText(source) + '</pre></td></tr>';
661667 }
 668+ output += "</table>";
662669 }
663 - output += "</table>";
664670
665671 runLoggingCallbacks( 'log', QUnit, details );
666672
@@ -669,6 +675,23 @@
670676 });
671677 },
672678
 679+ pushFailure: function(message, source) {
 680+ var details = {
 681+ result: false,
 682+ message: message
 683+ };
 684+ var output = escapeInnerText(message);
 685+ if (source) {
 686+ details.source = source;
 687+ output += '<table><tr class="test-source"><th>Source: </th><td><pre>' + escapeInnerText(source) + '</pre></td></tr></table>';
 688+ }
 689+ runLoggingCallbacks( 'log', QUnit, details );
 690+ config.current.assertions.push({
 691+ result: false,
 692+ message: output
 693+ });
 694+ },
 695+
673696 url: function( params ) {
674697 params = extend( extend( {}, QUnit.urlParams ), params );
675698 var querystring = "?",
@@ -724,7 +747,8 @@
725748 config.blocking = false;
726749
727750 var urlConfigHtml = '', len = config.urlConfig.length;
728 - for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) {
 751+ for ( var i = 0, val; i < len; i++ ) {
 752+ val = config.urlConfig[i];
729753 config[val] = QUnit.urlParams[val];
730754 urlConfigHtml += '<label><input name="' + val + '" type="checkbox"' + ( config[val] ? ' checked="checked"' : '' ) + '>' + val + '</label>';
731755 }
@@ -792,10 +816,10 @@
793817 // addEvent(window, "error") gives us a useless event object
794818 window.onerror = function( message, file, line ) {
795819 if ( QUnit.config.current ) {
796 - ok( false, message + ", " + file + ":" + line );
 820+ QUnit.pushFailure( message, file + ":" + line );
797821 } else {
798 - test( "global failure", function() {
799 - ok( false, message + ", " + file + ":" + line );
 822+ QUnit.test( "global failure", function() {
 823+ QUnit.pushFailure( message, file + ":" + line );
800824 });
801825 }
802826 };
@@ -815,7 +839,7 @@
816840
817841 var banner = id("qunit-banner"),
818842 tests = id("qunit-tests"),
819 - runtime = +new Date - config.started,
 843+ runtime = +new Date() - config.started,
820844 passed = config.stats.all - config.stats.bad,
821845 html = [
822846 'Tests completed in ',
@@ -847,6 +871,15 @@
848872 ].join(" ");
849873 }
850874
 875+ // clear own sessionStorage items if all tests passed
 876+ if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
 877+ for (var key in sessionStorage) {
 878+ if (sessionStorage.hasOwnProperty(key) && key.indexOf("qunit-") === 0 ) {
 879+ sessionStorage.removeItem(key);
 880+ }
 881+ }
 882+ }
 883+
851884 runLoggingCallbacks( 'done', QUnit, {
852885 failed: config.stats.bad,
853886 passed: passed,
@@ -881,21 +914,34 @@
882915
883916 // so far supports only Firefox, Chrome and Opera (buggy)
884917 // could be extended in the future to use something like https://github.com/csnover/TraceKit
885 -function sourceFromStacktrace() {
 918+function extractStacktrace( e, offset ) {
 919+ offset = offset || 3;
 920+ if (e.stacktrace) {
 921+ // Opera
 922+ return e.stacktrace.split("\n")[offset + 3];
 923+ } else if (e.stack) {
 924+ // Firefox, Chrome
 925+ var stack = e.stack.split("\n");
 926+ if (/^error$/i.test(stack[0])) {
 927+ stack.shift();
 928+ }
 929+ return stack[offset];
 930+ } else if (e.sourceURL) {
 931+ // Safari, PhantomJS
 932+ // hopefully one day Safari provides actual stacktraces
 933+ // exclude useless self-reference for generated Error objects
 934+ if ( /qunit.js$/.test( e.sourceURL ) ) {
 935+ return;
 936+ }
 937+ // for actual exceptions, this is useful
 938+ return e.sourceURL + ":" + e.line;
 939+ }
 940+}
 941+function sourceFromStacktrace(offset) {
886942 try {
887943 throw new Error();
888944 } catch ( e ) {
889 - if (e.stacktrace) {
890 - // Opera
891 - return e.stacktrace.split("\n")[6];
892 - } else if (e.stack) {
893 - // Firefox, Chrome
894 - return e.stack.split("\n")[4];
895 - } else if (e.sourceURL) {
896 - // Safari, PhantomJS
897 - // TODO sourceURL points at the 'throw new Error' line above, useless
898 - //return e.sourceURL + ":" + e.line;
899 - }
 945+ return extractStacktrace( e, offset );
900946 }
901947 }
902948
@@ -923,6 +969,9 @@
924970 }
925971
926972 function process( last ) {
 973+ function next() {
 974+ process( last );
 975+ }
927976 var start = new Date().getTime();
928977 config.depth = config.depth ? config.depth + 1 : 1;
929978
@@ -930,9 +979,7 @@
931980 if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
932981 config.queue.shift()();
933982 } else {
934 - window.setTimeout( function(){
935 - process( last );
936 - }, 13 );
 983+ window.setTimeout( next, 13 );
937984 break;
938985 }
939986 }
@@ -961,12 +1008,12 @@
9621009
9631010 var newGlobals = diff( config.pollution, old );
9641011 if ( newGlobals.length > 0 ) {
965 - ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
 1012+ QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
9661013 }
9671014
9681015 var deletedGlobals = diff( old, config.pollution );
9691016 if ( deletedGlobals.length > 0 ) {
970 - ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
 1017+ QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
9711018 }
9721019 }
9731020
@@ -985,17 +1032,6 @@
9861033 return result;
9871034 }
9881035
989 -function fail(message, exception, callback) {
990 - if ( typeof console !== "undefined" && console.error && console.warn ) {
991 - console.error(message);
992 - console.error(exception);
993 - console.warn(callback.toString());
994 -
995 - } else if ( window.opera && opera.postError ) {
996 - opera.postError(message, exception, callback.toString);
997 - }
998 -}
999 -
10001036 function extend(a, b) {
10011037 for ( var prop in b ) {
10021038 if ( b[prop] === undefined ) {
@@ -1047,7 +1083,7 @@
10481084
10491085 // Test for equality any JavaScript type.
10501086 // Author: Philippe Rathé <prathe@gmail.com>
1051 -QUnit.equiv = function () {
 1087+QUnit.equiv = (function() {
10521088
10531089 var innerEquiv; // the real equiv function
10541090 var callers = []; // stack to decide between skip/abort functions
@@ -1065,8 +1101,12 @@
10661102 }
10671103 }
10681104
1069 - var callbacks = function () {
 1105+ var getProto = Object.getPrototypeOf || function (obj) {
 1106+ return obj.__proto__;
 1107+ };
10701108
 1109+ var callbacks = (function () {
 1110+
10711111 // for string, boolean, number and null
10721112 function useStrictEquality(b, a) {
10731113 if (b instanceof a.constructor || a instanceof b.constructor) {
@@ -1092,17 +1132,18 @@
10931133 },
10941134
10951135 "date" : function(b, a) {
1096 - return QUnit.objectType(b) === "date"
1097 - && a.valueOf() === b.valueOf();
 1136+ return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf();
10981137 },
10991138
11001139 "regexp" : function(b, a) {
1101 - return QUnit.objectType(b) === "regexp"
1102 - && a.source === b.source && // the regex itself
1103 - a.global === b.global && // and its modifers
1104 - // (gmi) ...
1105 - a.ignoreCase === b.ignoreCase
1106 - && a.multiline === b.multiline;
 1140+ return QUnit.objectType(b) === "regexp" &&
 1141+ // the regex itself
 1142+ a.source === b.source &&
 1143+ // and its modifers
 1144+ a.global === b.global &&
 1145+ // (gmi) ...
 1146+ a.ignoreCase === b.ignoreCase &&
 1147+ a.multiline === b.multiline;
11071148 },
11081149
11091150 // - skip when the property is a method of an instance (OOP)
@@ -1118,7 +1159,7 @@
11191160 var len;
11201161
11211162 // b could be an object literal here
1122 - if (!(QUnit.objectType(b) === "array")) {
 1163+ if (QUnit.objectType(b) !== "array") {
11231164 return false;
11241165 }
11251166
@@ -1154,7 +1195,13 @@
11551196 // comparing constructors is more strict than using
11561197 // instanceof
11571198 if (a.constructor !== b.constructor) {
1158 - return false;
 1199+ // Allow objects with no prototype to be equivalent to
 1200+ // objects with Object as their constructor.
 1201+ if (!((getProto(a) === null && getProto(b) === Object.prototype) ||
 1202+ (getProto(b) === null && getProto(a) === Object.prototype)))
 1203+ {
 1204+ return false;
 1205+ }
11591206 }
11601207
11611208 // stack constructor before traversing properties
@@ -1166,9 +1213,10 @@
11671214 // and go deep
11681215 loop = false;
11691216 for (j = 0; j < parents.length; j++) {
1170 - if (parents[j] === a[i])
1171 - loop = true; // don't go down the same path
1172 - // twice
 1217+ if (parents[j] === a[i]) {
 1218+ // don't go down the same path twice
 1219+ loop = true;
 1220+ }
11731221 }
11741222 aProperties.push(i); // collect a's properties
11751223
@@ -1186,12 +1234,10 @@
11871235 }
11881236
11891237 // Ensures identical properties name
1190 - return eq
1191 - && innerEquiv(aProperties.sort(), bProperties
1192 - .sort());
 1238+ return eq && innerEquiv(aProperties.sort(), bProperties.sort());
11931239 }
11941240 };
1195 - }();
 1241+ }());
11961242
11971243 innerEquiv = function() { // can take multiple arguments
11981244 var args = Array.prototype.slice.apply(arguments);
@@ -1202,23 +1248,21 @@
12031249 return (function(a, b) {
12041250 if (a === b) {
12051251 return true; // catch the most you can
1206 - } else if (a === null || b === null || typeof a === "undefined"
1207 - || typeof b === "undefined"
1208 - || QUnit.objectType(a) !== QUnit.objectType(b)) {
 1252+ } else if (a === null || b === null || typeof a === "undefined" ||
 1253+ typeof b === "undefined" ||
 1254+ QUnit.objectType(a) !== QUnit.objectType(b)) {
12091255 return false; // don't lose time with error prone cases
12101256 } else {
12111257 return bindCallbacks(a, callbacks, [ b, a ]);
12121258 }
12131259
12141260 // apply transition with (1..n) arguments
1215 - })(args[0], args[1])
1216 - && arguments.callee.apply(this, args.splice(1,
1217 - args.length - 1));
 1261+ }(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length - 1)));
12181262 };
12191263
12201264 return innerEquiv;
12211265
1222 -}();
 1266+}());
12231267
12241268 /**
12251269 * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
@@ -1233,33 +1277,36 @@
12341278 QUnit.jsDump = (function() {
12351279 function quote( str ) {
12361280 return '"' + str.toString().replace(/"/g, '\\"') + '"';
1237 - };
 1281+ }
12381282 function literal( o ) {
12391283 return o + '';
1240 - };
 1284+ }
12411285 function join( pre, arr, post ) {
12421286 var s = jsDump.separator(),
12431287 base = jsDump.indent(),
12441288 inner = jsDump.indent(1);
1245 - if ( arr.join )
 1289+ if ( arr.join ) {
12461290 arr = arr.join( ',' + s + inner );
1247 - if ( !arr )
 1291+ }
 1292+ if ( !arr ) {
12481293 return pre + post;
 1294+ }
12491295 return [ pre, inner + arr, base + post ].join(s);
1250 - };
 1296+ }
12511297 function array( arr, stack ) {
1252 - var i = arr.length, ret = Array(i);
 1298+ var i = arr.length, ret = new Array(i);
12531299 this.up();
1254 - while ( i-- )
 1300+ while ( i-- ) {
12551301 ret[i] = this.parse( arr[i] , undefined , stack);
 1302+ }
12561303 this.down();
12571304 return join( '[', ret, ']' );
1258 - };
 1305+ }
12591306
12601307 var reName = /^function (\w+)/;
12611308
12621309 var jsDump = {
1263 - parse:function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance
 1310+ parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance
12641311 stack = stack || [ ];
12651312 var parser = this.parsers[ type || this.typeOf(obj) ];
12661313 type = typeof parser;
@@ -1277,7 +1324,7 @@
12781325 // else
12791326 return (type == 'string') ? parser : this.parsers.error;
12801327 },
1281 - typeOf:function( obj ) {
 1328+ typeOf: function( obj ) {
12821329 var type;
12831330 if ( obj === null ) {
12841331 type = "null";
@@ -1307,45 +1354,48 @@
13081355 }
13091356 return type;
13101357 },
1311 - separator:function() {
 1358+ separator: function() {
13121359 return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
13131360 },
1314 - indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
1315 - if ( !this.multiline )
 1361+ indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
 1362+ if ( !this.multiline ) {
13161363 return '';
 1364+ }
13171365 var chr = this.indentChar;
1318 - if ( this.HTML )
 1366+ if ( this.HTML ) {
13191367 chr = chr.replace(/\t/g,' ').replace(/ /g,'&nbsp;');
1320 - return Array( this._depth_ + (extra||0) ).join(chr);
 1368+ }
 1369+ return new Array( this._depth_ + (extra||0) ).join(chr);
13211370 },
1322 - up:function( a ) {
 1371+ up: function( a ) {
13231372 this._depth_ += a || 1;
13241373 },
1325 - down:function( a ) {
 1374+ down: function( a ) {
13261375 this._depth_ -= a || 1;
13271376 },
1328 - setParser:function( name, parser ) {
 1377+ setParser: function( name, parser ) {
13291378 this.parsers[name] = parser;
13301379 },
13311380 // The next 3 are exposed so you can use them
1332 - quote:quote,
1333 - literal:literal,
1334 - join:join,
 1381+ quote: quote,
 1382+ literal: literal,
 1383+ join: join,
13351384 //
13361385 _depth_: 1,
13371386 // This is the list of parsers, to modify them, use jsDump.setParser
1338 - parsers:{
 1387+ parsers: {
13391388 window: '[Window]',
13401389 document: '[Document]',
1341 - error:'[ERROR]', //when no parser is found, shouldn't happen
 1390+ error: '[ERROR]', //when no parser is found, shouldn't happen
13421391 unknown: '[Unknown]',
1343 - 'null':'null',
1344 - 'undefined':'undefined',
1345 - 'function':function( fn ) {
 1392+ 'null': 'null',
 1393+ 'undefined': 'undefined',
 1394+ 'function': function( fn ) {
13461395 var ret = 'function',
13471396 name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
1348 - if ( name )
 1397+ if ( name ) {
13491398 ret += ' ' + name;
 1399+ }
13501400 ret += '(';
13511401
13521402 ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join('');
@@ -1353,18 +1403,26 @@
13541404 },
13551405 array: array,
13561406 nodelist: array,
1357 - arguments: array,
1358 - object:function( map, stack ) {
1359 - var ret = [ ];
 1407+ 'arguments': array,
 1408+ object: function( map, stack ) {
 1409+ var ret = [ ], keys, key, val, i;
13601410 QUnit.jsDump.up();
1361 - for ( var key in map ) {
1362 - var val = map[key];
1363 - ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(val, undefined, stack));
1364 - }
 1411+ if (Object.keys) {
 1412+ keys = Object.keys( map );
 1413+ } else {
 1414+ keys = [];
 1415+ for (key in map) { keys.push( key ); }
 1416+ }
 1417+ keys.sort();
 1418+ for (i = 0; i < keys.length; i++) {
 1419+ key = keys[ i ];
 1420+ val = map[ key ];
 1421+ ret.push( QUnit.jsDump.parse( key, 'key' ) + ': ' + QUnit.jsDump.parse( val, undefined, stack ) );
 1422+ }
13651423 QUnit.jsDump.down();
13661424 return join( '{', ret, '}' );
13671425 },
1368 - node:function( node ) {
 1426+ node: function( node ) {
13691427 var open = QUnit.jsDump.HTML ? '&lt;' : '<',
13701428 close = QUnit.jsDump.HTML ? '&gt;' : '>';
13711429
@@ -1373,28 +1431,32 @@
13741432
13751433 for ( var a in QUnit.jsDump.DOMAttrs ) {
13761434 var val = node[QUnit.jsDump.DOMAttrs[a]];
1377 - if ( val )
 1435+ if ( val ) {
13781436 ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' );
 1437+ }
13791438 }
13801439 return ret + close + open + '/' + tag + close;
13811440 },
1382 - functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
 1441+ functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function
13831442 var l = fn.length;
1384 - if ( !l ) return '';
 1443+ if ( !l ) {
 1444+ return '';
 1445+ }
13851446
1386 - var args = Array(l);
1387 - while ( l-- )
 1447+ var args = new Array(l);
 1448+ while ( l-- ) {
13881449 args[l] = String.fromCharCode(97+l);//97 is 'a'
 1450+ }
13891451 return ' ' + args.join(', ') + ' ';
13901452 },
1391 - key:quote, //object calls it internally, the key part of an item in a map
1392 - functionCode:'[code]', //function calls it internally, it's the content of the function
1393 - attribute:quote, //node calls it internally, it's an html attribute value
1394 - string:quote,
1395 - date:quote,
1396 - regexp:literal, //regex
1397 - number:literal,
1398 - 'boolean':literal
 1453+ key: quote, //object calls it internally, the key part of an item in a map
 1454+ functionCode: '[code]', //function calls it internally, it's the content of the function
 1455+ attribute: quote, //node calls it internally, it's an html attribute value
 1456+ string: quote,
 1457+ date: quote,
 1458+ regexp: literal, //regex
 1459+ number: literal,
 1460+ 'boolean': literal
13991461 },
14001462 DOMAttrs:{//attributes to dump from nodes, name=>realName
14011463 id:'id',
@@ -1407,7 +1469,7 @@
14081470 };
14091471
14101472 return jsDump;
1411 -})();
 1473+}());
14121474
14131475 // from Sizzle.js
14141476 function getText( elems ) {
@@ -1427,7 +1489,7 @@
14281490 }
14291491
14301492 return ret;
1431 -};
 1493+}
14321494
14331495 //from jquery.js
14341496 function inArray( elem, array ) {
@@ -1462,26 +1524,29 @@
14631525 function diff(o, n) {
14641526 var ns = {};
14651527 var os = {};
 1528+ var i;
14661529
1467 - for (var i = 0; i < n.length; i++) {
1468 - if (ns[n[i]] == null)
 1530+ for (i = 0; i < n.length; i++) {
 1531+ if (ns[n[i]] == null) {
14691532 ns[n[i]] = {
14701533 rows: [],
14711534 o: null
14721535 };
 1536+ }
14731537 ns[n[i]].rows.push(i);
14741538 }
14751539
1476 - for (var i = 0; i < o.length; i++) {
1477 - if (os[o[i]] == null)
 1540+ for (i = 0; i < o.length; i++) {
 1541+ if (os[o[i]] == null) {
14781542 os[o[i]] = {
14791543 rows: [],
14801544 n: null
14811545 };
 1546+ }
14821547 os[o[i]].rows.push(i);
14831548 }
14841549
1485 - for (var i in ns) {
 1550+ for (i in ns) {
14861551 if ( !hasOwn.call( ns, i ) ) {
14871552 continue;
14881553 }
@@ -1497,7 +1562,7 @@
14981563 }
14991564 }
15001565
1501 - for (var i = 0; i < n.length - 1; i++) {
 1566+ for (i = 0; i < n.length - 1; i++) {
15021567 if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
15031568 n[i + 1] == o[n[i].row + 1]) {
15041569 n[i + 1] = {
@@ -1511,7 +1576,7 @@
15121577 }
15131578 }
15141579
1515 - for (var i = n.length - 1; i > 0; i--) {
 1580+ for (i = n.length - 1; i > 0; i--) {
15161581 if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
15171582 n[i - 1] == o[n[i].row - 1]) {
15181583 n[i - 1] = {
@@ -1534,9 +1599,10 @@
15351600 return function(o, n) {
15361601 o = o.replace(/\s+$/, '');
15371602 n = n.replace(/\s+$/, '');
1538 - var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
 1603+ var out = diff(o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/));
15391604
15401605 var str = "";
 1606+ var i;
15411607
15421608 var oSpace = o.match(/\s+/g);
15431609 if (oSpace == null) {
@@ -1553,8 +1619,8 @@
15541620 nSpace.push(" ");
15551621 }
15561622
1557 - if (out.n.length == 0) {
1558 - for (var i = 0; i < out.o.length; i++) {
 1623+ if (out.n.length === 0) {
 1624+ for (i = 0; i < out.o.length; i++) {
15591625 str += '<del>' + out.o[i] + oSpace[i] + "</del>";
15601626 }
15611627 }
@@ -1565,7 +1631,7 @@
15661632 }
15671633 }
15681634
1569 - for (var i = 0; i < out.n.length; i++) {
 1635+ for (i = 0; i < out.n.length; i++) {
15701636 if (out.n[i].text == null) {
15711637 str += '<ins>' + out.n[i] + nSpace[i] + "</ins>";
15721638 }
@@ -1582,6 +1648,12 @@
15831649
15841650 return str;
15851651 };
1586 -})();
 1652+}());
15871653
1588 -})(this);
 1654+// for CommonJS enviroments, export everything
 1655+if ( typeof exports !== "undefined" || typeof require !== "undefined" ) {
 1656+ extend(exports, QUnit);
 1657+}
 1658+
 1659+// get at whatever the global object is, like window in browsers
 1660+}( (function() {return this;}.call()) ));

Status & tagging log