From a92676edcebf7afaf223f9461f920f47c41ef26e Mon Sep 17 00:00:00 2001 From: David Majda Date: Tue, 13 Sep 2011 11:37:22 +0200 Subject: [PATCH] Upgrade QUnit to the current master Exact commit ID: 96e42601cadcba989f80bd4c294b7e0ee4ff1d29 --- test/vendor/qunit/qunit.css | 51 ++- test/vendor/qunit/qunit.js | 838 +++++++++++++++++++++--------------- 2 files changed, 527 insertions(+), 362 deletions(-) diff --git a/test/vendor/qunit/qunit.css b/test/vendor/qunit/qunit.css index a6a831c..c85f36a 100644 --- a/test/vendor/qunit/qunit.css +++ b/test/vendor/qunit/qunit.css @@ -1,7 +1,17 @@ +/** + * QUnit - A JavaScript Unit Testing Framework + * + * http://docs.jquery.com/QUnit + * + * Copyright (c) 2011 John Resig, Jörn Zaefferer + * Dual licensed under the MIT (MIT-LICENSE.txt) + * or GPL (GPL-LICENSE.txt) licenses. + */ + /** Font Family and Sizes */ #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { - font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; + font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; } #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } @@ -27,7 +37,7 @@ font-size: 1.5em; line-height: 1em; font-weight: normal; - + border-radius: 15px 15px 0 0; -moz-border-radius: 15px 15px 0 0; -webkit-border-top-right-radius: 15px; @@ -74,20 +84,34 @@ list-style-position: inside; } +#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { + display: none; +} + #qunit-tests li strong { cursor: pointer; } +#qunit-tests li a { + padding: 0.5em; + color: #c2ccd1; + text-decoration: none; +} +#qunit-tests li a:hover, +#qunit-tests li a:focus { + color: #000; +} + #qunit-tests ol { margin-top: 0.5em; padding: 0.5em; - + background-color: #fff; - + border-radius: 15px; -moz-border-radius: 15px; -webkit-border-radius: 15px; - + box-shadow: inset 0px 2px 13px #999; -moz-box-shadow: inset 0px 2px 13px #999; -webkit-box-shadow: inset 0px 2px 13px #999; @@ -150,7 +174,7 @@ #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } #qunit-tests .pass .test-name { color: #366097; } - + #qunit-tests .pass .test-actual, #qunit-tests .pass .test-expected { color: #999999; } @@ -162,6 +186,14 @@ color: #710909; background-color: #fff; border-left: 26px solid #EE5757; + white-space: pre; +} + +#qunit-tests > li:last-child { + border-radius: 0 0 15px 15px; + -moz-border-radius: 0 0 15px 15px; + -webkit-border-bottom-right-radius: 15px; + -webkit-border-bottom-left-radius: 15px; } #qunit-tests .fail { color: #000000; background-color: #EE5757; } @@ -174,7 +206,7 @@ #qunit-banner.qunit-fail { background-color: #EE5757; } -/** Footer */ +/** Result */ #qunit-testresult { padding: 0.5em 0.5em 0.5em 2.5em; @@ -182,10 +214,7 @@ color: #2b81af; background-color: #D2E0E6; - border-radius: 0 0 15px 15px; - -moz-border-radius: 0 0 15px 15px; - -webkit-border-bottom-right-radius: 15px; - -webkit-border-bottom-left-radius: 15px; + border-bottom: 1px solid white; } /** Fixture */ diff --git a/test/vendor/qunit/qunit.js b/test/vendor/qunit/qunit.js index 30e0395..09eb1a5 100644 --- a/test/vendor/qunit/qunit.js +++ b/test/vendor/qunit/qunit.js @@ -1,6 +1,6 @@ -/* +/** * QUnit - A JavaScript Unit Testing Framework - * + * * http://docs.jquery.com/QUnit * * Copyright (c) 2011 John Resig, Jörn Zaefferer @@ -15,11 +15,11 @@ var defined = { sessionStorage: (function() { try { return !!sessionStorage.getItem; - } catch(e){ + } catch(e) { return false; } - })() -} + })() +}; var testId = 0; @@ -40,6 +40,7 @@ Test.prototype = { b.innerHTML = "Running " + this.name; var li = document.createElement("li"); li.appendChild( b ); + li.className = "running"; li.id = this.id = "test-output" + testId++; tests.appendChild( li ); } @@ -47,7 +48,7 @@ Test.prototype = { setup: function() { if (this.module != config.previousModule) { if ( config.previousModule ) { - QUnit.moduleDone( { + runLoggingCallbacks('moduleDone', QUnit, { name: config.previousModule, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, @@ -56,7 +57,7 @@ Test.prototype = { } config.previousModule = this.module; config.moduleStats = { all: 0, bad: 0 }; - QUnit.moduleStart( { + runLoggingCallbacks( 'moduleStart', QUnit, { name: this.module } ); } @@ -70,14 +71,14 @@ Test.prototype = { extend(this.testEnvironment, this.testEnvironmentArg); } - QUnit.testStart( { + runLoggingCallbacks( 'testStart', QUnit, { name: this.testName } ); // allow utility functions to access the current test environment // TODO why?? QUnit.current_testEnvironment = this.testEnvironment; - + try { if ( !config.pollution ) { saveGlobal(); @@ -113,8 +114,8 @@ Test.prototype = { }, teardown: function() { try { - checkPollution(); this.testEnvironment.teardown.call(this.testEnvironment); + checkPollution(); } catch(e) { QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message ); } @@ -123,7 +124,7 @@ Test.prototype = { if ( this.expected && this.expected != this.assertions.length ) { QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); } - + var good = 0, bad = 0, tests = id("qunit-tests"); @@ -131,7 +132,7 @@ Test.prototype = { config.moduleStats.all += this.assertions.length; if ( tests ) { - var ol = document.createElement("ol"); + var ol = document.createElement("ol"); for ( var i = 0; i < this.assertions.length; i++ ) { var assertion = this.assertions[i]; @@ -151,7 +152,13 @@ Test.prototype = { } // store result when possible - defined.sessionStorage && sessionStorage.setItem("qunit-" + this.testName, bad); + if ( QUnit.config.reorder && defined.sessionStorage ) { + if (bad) { + sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad); + } else { + sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName); + } + } if (bad == 0) { ol.style.display = "none"; @@ -159,27 +166,32 @@ Test.prototype = { var b = document.createElement("strong"); b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; - + + var a = document.createElement("a"); + a.innerHTML = "Rerun"; + a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); + addEvent(b, "click", function() { - var next = b.nextSibling, display = next.style.display; + var next = b.nextSibling.nextSibling, + display = next.style.display; next.style.display = display === "none" ? "block" : "none"; }); - + addEvent(b, "dblclick", function(e) { var target = e && e.target ? e.target : window.event.srcElement; if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { target = target.parentNode; } if ( window.location && target.nodeName.toLowerCase() === "strong" ) { - window.location.search = "?" + encodeURIComponent(getText([target]).replace(/\(.+\)$/, "").replace(/(^\s*|\s*$)/g, "")); + window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); } }); var li = id(this.id); li.className = bad ? "fail" : "pass"; - li.style.display = resultDisplayStyle(!bad); li.removeChild( li.firstChild ); li.appendChild( b ); + li.appendChild( a ); li.appendChild( ol ); } else { @@ -198,14 +210,14 @@ Test.prototype = { fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset); } - QUnit.testDone( { + runLoggingCallbacks( 'testDone', QUnit, { name: this.testName, failed: bad, passed: this.assertions.length - bad, total: this.assertions.length } ); }, - + queue: function() { var test = this; synchronize(function() { @@ -227,15 +239,15 @@ Test.prototype = { }); } // defer when previous test run passed, if storage is available - var bad = defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.testName); + var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName); if (bad) { run(); } else { synchronize(run); }; } - -} + +}; var QUnit = { @@ -253,7 +265,7 @@ var QUnit = { QUnit.test(testName, expected, callback, true); }, - + test: function(testName, expected, callback, async) { var name = '' + testName + '', testEnvironmentArg; @@ -263,7 +275,7 @@ var QUnit = { } // is 2nd argument a testEnvironment? if ( expected && typeof expected === 'object') { - testEnvironmentArg = expected; + testEnvironmentArg = expected; expected = null; } @@ -274,13 +286,13 @@ var QUnit = { if ( !validTest(config.currentModule + ": " + testName) ) { return; } - + var test = new Test(name, testName, expected, testEnvironmentArg, async, callback); test.module = config.currentModule; test.moduleTestEnvironment = config.currentModuleTestEnviroment; test.queue(); }, - + /** * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. */ @@ -299,7 +311,7 @@ var QUnit = { message: msg }; msg = escapeHtml(msg); - QUnit.log(details); + runLoggingCallbacks( 'log', QUnit, details ); config.current.assertions.push({ result: a, message: msg @@ -325,7 +337,7 @@ var QUnit = { notEqual: function(actual, expected, message) { QUnit.push(expected != actual, actual, expected, message); }, - + deepEqual: function(actual, expected, message) { QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); }, @@ -344,34 +356,34 @@ var QUnit = { raises: function(block, expected, message) { var actual, ok = false; - + if (typeof expected === 'string') { message = expected; expected = null; } - + try { block(); } catch (e) { actual = e; } - + if (actual) { // we don't want to validate thrown error if (!expected) { ok = true; - // expected is a regexp + // expected is a regexp } else if (QUnit.objectType(expected) === "regexp") { ok = expected.test(actual); - // expected is a constructor + // expected is a constructor } else if (actual instanceof expected) { ok = true; - // expected is a validation function which returns true is validation passed + // expected is a validation function which returns true is validation passed } else if (expected.call({}, actual) === true) { ok = true; } } - + QUnit.ok(ok, message); }, @@ -388,6 +400,9 @@ var QUnit = { // A slight delay, to avoid any current callbacks if ( defined.setTimeout ) { window.setTimeout(function() { + if (config.semaphore > 0) { + return; + } if ( config.timeout ) { clearTimeout(config.timeout); } @@ -400,7 +415,7 @@ var QUnit = { process(); } }, - + stop: function(timeout) { config.semaphore++; config.blocking = true; @@ -413,9 +428,17 @@ var QUnit = { }, timeout); } } - }; +//We want access to the constructor's prototype +(function() { + function F(){}; + F.prototype = QUnit; + QUnit = new F(); + //Make F QUnit's constructor so that we can add to the prototype later + QUnit.constructor = F; +})(); + // Backwards compatibility, deprecated QUnit.equals = QUnit.equal; QUnit.same = QUnit.deepEqual; @@ -426,33 +449,52 @@ var config = { queue: [], // block until document ready - blocking: true + blocking: true, + + // when enabled, show only failing tests + // gets persisted through sessionStorage and can be changed in UI via checkbox + hidepassed: false, + + // by default, run previously failed tests first + // very useful in combination with "Hide passed tests" checked + reorder: true, + + // by default, modify document.title when suite is done + altertitle: true, + + urlConfig: ['noglobals', 'notrycatch'], + + //logging callback queues + begin: [], + done: [], + log: [], + testStart: [], + testDone: [], + moduleStart: [], + moduleDone: [] }; // Load paramaters (function() { var location = window.location || { search: "", protocol: "file:" }, - GETParams = location.search.slice(1).split('&'); - - for ( var i = 0; i < GETParams.length; i++ ) { - GETParams[i] = decodeURIComponent( GETParams[i] ); - if ( GETParams[i] === "noglobals" ) { - GETParams.splice( i, 1 ); - i--; - config.noglobals = true; - } else if ( GETParams[i] === "notrycatch" ) { - GETParams.splice( i, 1 ); - i--; - config.notrycatch = true; - } else if ( GETParams[i].search('=') > -1 ) { - GETParams.splice( i, 1 ); - i--; + params = location.search.slice( 1 ).split( "&" ), + length = params.length, + urlParams = {}, + current; + + if ( params[ 0 ] ) { + for ( var i = 0; i < length; i++ ) { + current = params[ i ].split( "=" ); + current[ 0 ] = decodeURIComponent( current[ 0 ] ); + // allow just a key to turn on a flag, e.g., test.html?noglobals + current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; + urlParams[ current[ 0 ] ] = current[ 1 ]; } } - - // restrict modules/tests by get parameters - config.filters = GETParams; - + + QUnit.urlParams = urlParams; + config.filter = urlParams.filter; + // Figure out if we're running the tests from a server or not QUnit.isLocal = !!(location.protocol === 'file:'); })(); @@ -481,14 +523,14 @@ extend(QUnit, { blocking: false, autostart: true, autorun: false, - filters: [], + filter: "", queue: [], semaphore: 0 }); - var tests = id("qunit-tests"), - banner = id("qunit-banner"), - result = id("qunit-testresult"); + var tests = id( "qunit-tests" ), + banner = id( "qunit-banner" ), + result = id( "qunit-testresult" ); if ( tests ) { tests.innerHTML = ""; @@ -501,24 +543,32 @@ extend(QUnit, { if ( result ) { result.parentNode.removeChild( result ); } + + if ( tests ) { + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = 'Running...
 '; + } }, - + /** * Resets the test setup. Useful for tests that modify the DOM. - * + * * If jQuery is available, uses jQuery's html(), otherwise just innerHTML. */ reset: function() { if ( window.jQuery ) { - jQuery( "#main, #qunit-fixture" ).html( config.fixture ); + jQuery( "#qunit-fixture" ).html( config.fixture ); } else { - var main = id( 'main' ) || id( 'qunit-fixture' ); + var main = id( 'qunit-fixture' ); if ( main ) { main.innerHTML = config.fixture; } } }, - + /** * Trigger an event on an element. * @@ -538,12 +588,12 @@ extend(QUnit, { elem.fireEvent("on"+type); } }, - + // Safe object type checking is: function( type, obj ) { return QUnit.objectType( obj ) == type; }, - + objectType: function( obj ) { if (typeof obj === "undefined") { return "undefined"; @@ -577,7 +627,7 @@ extend(QUnit, { } return undefined; }, - + push: function(result, actual, expected, message) { var details = { result: result, @@ -585,7 +635,7 @@ extend(QUnit, { actual: actual, expected: expected }; - + message = escapeHtml(message) || (result ? "okay" : "failed"); message = '' + message + ""; expected = escapeHtml(QUnit.jsDump.parse(expected)); @@ -599,43 +649,63 @@ extend(QUnit, { var source = sourceFromStacktrace(); if (source) { details.source = source; - output += 'Source:
' + source +'
'; + output += 'Source:
' + escapeHtml(source) + '
'; } } output += ""; - - QUnit.log(details); - + + runLoggingCallbacks( 'log', QUnit, details ); + config.current.assertions.push({ result: !!result, message: output }); }, - + + url: function( params ) { + params = extend( extend( {}, QUnit.urlParams ), params ); + var querystring = "?", + key; + for ( key in params ) { + querystring += encodeURIComponent( key ) + "=" + + encodeURIComponent( params[ key ] ) + "&"; + } + return window.location.pathname + querystring.slice( 0, -1 ); + }, + + extend: extend, + id: id, + addEvent: addEvent, +}); + +//QUnit.constructor is set to the empty F() above so that we can add to it's prototype later +//Doing this allows us to tell if the following methods have been overwritten on the actual +//QUnit object, which is a deprecated way of using the callbacks. +extend(QUnit.constructor.prototype, { // Logging callbacks; all receive a single argument with the listed properties // run test/logs.html for any related changes - begin: function() {}, + begin: registerLoggingCallback('begin'), // done: { failed, passed, total, runtime } - done: function() {}, + done: registerLoggingCallback('done'), // log: { result, actual, expected, message } - log: function() {}, + log: registerLoggingCallback('log'), // testStart: { name } - testStart: function() {}, + testStart: registerLoggingCallback('testStart'), // testDone: { name, failed, passed, total } - testDone: function() {}, + testDone: registerLoggingCallback('testDone'), // moduleStart: { name } - moduleStart: function() {}, + moduleStart: registerLoggingCallback('moduleStart'), // moduleDone: { name, failed, passed, total } - moduleDone: function() {} + moduleDone: registerLoggingCallback('moduleDone'), }); if ( typeof document === "undefined" || document.readyState === "complete" ) { config.autorun = true; } -addEvent(window, "load", function() { - QUnit.begin({}); - +QUnit.load = function() { + runLoggingCallbacks( 'begin', QUnit, {} ); + // Initialize the config, saving the execution queue var oldconfig = extend({}, config); QUnit.init(); @@ -643,42 +713,51 @@ addEvent(window, "load", function() { config.blocking = false; + var urlConfigHtml = '', len = config.urlConfig.length; + for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) { + config[val] = QUnit.urlParams[val]; + urlConfigHtml += ''; + } + var userAgent = id("qunit-userAgent"); if ( userAgent ) { userAgent.innerHTML = navigator.userAgent; } var banner = id("qunit-header"); if ( banner ) { - var paramsIndex = location.href.lastIndexOf(location.search); - if ( paramsIndex > -1 ) { - var mainPageLocation = location.href.slice(0, paramsIndex); - if ( mainPageLocation == location.href ) { - banner.innerHTML = ' ' + banner.innerHTML + ' '; - } else { - var testName = decodeURIComponent(location.search.slice(1)); - banner.innerHTML = '' + banner.innerHTML + '' + testName + ''; - } - } + banner.innerHTML = ' ' + banner.innerHTML + ' ' + urlConfigHtml; + addEvent( banner, "change", function( event ) { + var params = {}; + params[ event.target.name ] = event.target.checked ? true : undefined; + window.location = QUnit.url( params ); + }); } - + var toolbar = id("qunit-testrunner-toolbar"); if ( toolbar ) { var filter = document.createElement("input"); filter.type = "checkbox"; filter.id = "qunit-filter-pass"; addEvent( filter, "click", function() { - var li = document.getElementsByTagName("li"); - for ( var i = 0; i < li.length; i++ ) { - if ( li[i].className.indexOf("pass") > -1 ) { - li[i].style.display = filter.checked ? "none" : ""; - } + var ol = document.getElementById("qunit-tests"); + if ( filter.checked ) { + ol.className = ol.className + " hidepass"; + } else { + var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; + ol.className = tmp.replace(/ hidepass /, " "); } if ( defined.sessionStorage ) { - sessionStorage.setItem("qunit-filter-passed-tests", filter.checked ? "true" : ""); + if (filter.checked) { + sessionStorage.setItem("qunit-filter-passed-tests", "true"); + } else { + sessionStorage.removeItem("qunit-filter-passed-tests"); + } } }); - if ( defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { + if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { filter.checked = true; + var ol = document.getElementById("qunit-tests"); + ol.className = ol.className + " hidepass"; } toolbar.appendChild( filter ); @@ -688,7 +767,7 @@ addEvent(window, "load", function() { toolbar.appendChild( label ); } - var main = id('main') || id('qunit-fixture'); + var main = id('qunit-fixture'); if ( main ) { config.fixture = main.innerHTML; } @@ -696,14 +775,16 @@ addEvent(window, "load", function() { if (config.autostart) { QUnit.start(); } -}); +}; + +addEvent(window, "load", QUnit.load); function done() { config.autorun = true; // Log the last module results if ( config.currentModule ) { - QUnit.moduleDone( { + runLoggingCallbacks( 'moduleDone', QUnit, { name: config.currentModule, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, @@ -732,50 +813,46 @@ function done() { banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); } - if ( tests ) { - var result = id("qunit-testresult"); - - if ( !result ) { - result = document.createElement("p"); - result.id = "qunit-testresult"; - result.className = "result"; - tests.parentNode.insertBefore( result, tests.nextSibling ); - } + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } - result.innerHTML = html; + if ( config.altertitle && typeof document !== "undefined" && document.title ) { + // show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = [ + (config.stats.bad ? "\u2716" : "\u2714"), + document.title.replace(/^[\u2714\u2716] /i, "") + ].join(" "); } - QUnit.done( { + runLoggingCallbacks( 'done', QUnit, { failed: config.stats.bad, - passed: passed, + passed: passed, total: config.stats.all, runtime: runtime } ); } function validTest( name ) { - var i = config.filters.length, + var filter = config.filter, run = false; - if ( !i ) { + if ( !filter ) { return true; } - - while ( i-- ) { - var filter = config.filters[i], - not = filter.charAt(0) == '!'; - if ( not ) { - filter = filter.slice(1); - } + var not = filter.charAt( 0 ) === "!"; + if ( not ) { + filter = filter.slice( 1 ); + } - if ( name.indexOf(filter) !== -1 ) { - return !not; - } + if ( name.indexOf( filter ) !== -1 ) { + return !not; + } - if ( not ) { - run = true; - } + if ( not ) { + run = true; } return run; @@ -793,14 +870,14 @@ function sourceFromStacktrace() { } else if (e.stack) { // Firefox, Chrome return e.stack.split("\n")[4]; + } else if (e.sourceURL) { + // Safari, PhantomJS + // TODO sourceURL points at the 'throw new Error' line above, useless + //return e.sourceURL + ":" + e.line; } } } -function resultDisplayStyle(passed) { - return passed && id("qunit-filter-pass") && id("qunit-filter-pass").checked ? 'none' : ''; -} - function escapeHtml(s) { if (!s) { return ""; @@ -837,14 +914,14 @@ function process() { break; } } - if (!config.blocking && !config.queue.length) { - done(); - } + if (!config.blocking && !config.queue.length) { + done(); + } } function saveGlobal() { config.pollution = []; - + if ( config.noglobals ) { for ( var key in window ) { config.pollution.push( key ); @@ -855,17 +932,15 @@ function saveGlobal() { function checkPollution( name ) { var old = config.pollution; saveGlobal(); - - var newGlobals = diff( old, config.pollution ); + + var newGlobals = diff( config.pollution, old ); if ( newGlobals.length > 0 ) { ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); - config.current.expected++; } - var deletedGlobals = diff( config.pollution, old ); + var deletedGlobals = diff( old, config.pollution ); if ( deletedGlobals.length > 0 ) { ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); - config.current.expected++; } } @@ -897,7 +972,11 @@ function fail(message, exception, callback) { function extend(a, b) { for ( var prop in b ) { - a[prop] = b[prop]; + if ( b[prop] === undefined ) { + delete a[prop]; + } else { + a[prop] = b[prop]; + } } return a; @@ -918,176 +997,206 @@ function id(name) { document.getElementById( name ); } +function registerLoggingCallback(key){ + return function(callback){ + config[key].push( callback ); + }; +} + +// Supports deprecated method of completely overwriting logging callbacks +function runLoggingCallbacks(key, scope, args) { + //debugger; + var callbacks; + if ( QUnit.hasOwnProperty(key) ) { + QUnit[key].call(scope, args); + } else { + callbacks = config[key]; + for( var i = 0; i < callbacks.length; i++ ) { + callbacks[i].call( scope, args ); + } + } +} + // Test for equality any JavaScript type. -// Discussions and reference: http://philrathe.com/articles/equiv -// Test suites: http://philrathe.com/tests/equiv // Author: Philippe Rathé QUnit.equiv = function () { - var innerEquiv; // the real equiv function - var callers = []; // stack to decide between skip/abort functions - var parents = []; // stack to avoiding loops from circular referencing - - // Call the o related callback with the given arguments. - function bindCallbacks(o, callbacks, args) { - var prop = QUnit.objectType(o); - if (prop) { - if (QUnit.objectType(callbacks[prop]) === "function") { - return callbacks[prop].apply(callbacks, args); - } else { - return callbacks[prop]; // or undefined - } - } - } - - var callbacks = function () { - - // for string, boolean, number and null - function useStrictEquality(b, a) { - if (b instanceof a.constructor || a instanceof b.constructor) { - // to catch short annotaion VS 'new' annotation of a declaration - // e.g. var i = 1; - // var j = new Number(1); - return a == b; - } else { - return a === b; - } - } - - return { - "string": useStrictEquality, - "boolean": useStrictEquality, - "number": useStrictEquality, - "null": useStrictEquality, - "undefined": useStrictEquality, - - "nan": function (b) { - return isNaN(b); - }, - - "date": function (b, a) { - return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf(); - }, - - "regexp": function (b, a) { - return QUnit.objectType(b) === "regexp" && - a.source === b.source && // the regex itself - a.global === b.global && // and its modifers (gmi) ... - a.ignoreCase === b.ignoreCase && - a.multiline === b.multiline; - }, - - // - skip when the property is a method of an instance (OOP) - // - abort otherwise, - // initial === would have catch identical references anyway - "function": function () { - var caller = callers[callers.length - 1]; - return caller !== Object && - typeof caller !== "undefined"; - }, - - "array": function (b, a) { - var i, j, loop; - var len; - - // b could be an object literal here - if ( ! (QUnit.objectType(b) === "array")) { - return false; - } - - len = a.length; - if (len !== b.length) { // safe and faster - return false; - } - - //track reference to avoid circular references - parents.push(a); - for (i = 0; i < len; i++) { - loop = false; - for(j=0;j'; - + var tag = node.nodeName.toLowerCase(), ret = open + tag; - + for ( var a in QUnit.jsDump.DOMAttrs ) { var val = node[QUnit.jsDump.DOMAttrs[a]]; if ( val ) @@ -1226,8 +1347,8 @@ QUnit.jsDump = (function() { }, functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function var l = fn.length; - if ( !l ) return ''; - + if ( !l ) return ''; + var args = Array(l); while ( l-- ) args[l] = String.fromCharCode(97+l);//97 is 'a' @@ -1275,6 +1396,21 @@ function getText( elems ) { return ret; }; +//from jquery.js +function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; +} + /* * Javascript Diff Algorithm * By John Resig (http://ejohn.org/) @@ -1284,34 +1420,34 @@ function getText( elems ) { * * More Info: * http://ejohn.org/projects/javascript-diff-algorithm/ - * + * * Usage: QUnit.diff(expected, actual) - * + * * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" */ QUnit.diff = (function() { - function diff(o, n){ - var ns = new Object(); - var os = new Object(); - + function diff(o, n) { + var ns = {}; + var os = {}; + for (var i = 0; i < n.length; i++) { - if (ns[n[i]] == null) + if (ns[n[i]] == null) ns[n[i]] = { - rows: new Array(), + rows: [], o: null }; ns[n[i]].rows.push(i); } - + for (var i = 0; i < o.length; i++) { - if (os[o[i]] == null) + if (os[o[i]] == null) os[o[i]] = { - rows: new Array(), + rows: [], n: null }; os[o[i]].rows.push(i); } - + for (var i in ns) { if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { n[ns[i].rows[0]] = { @@ -1324,7 +1460,7 @@ QUnit.diff = (function() { }; } } - + for (var i = 0; i < n.length - 1; i++) { if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && n[i + 1] == o[n[i].row + 1]) { @@ -1338,7 +1474,7 @@ QUnit.diff = (function() { }; } } - + for (var i = n.length - 1; i > 0; i--) { if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && n[i - 1] == o[n[i].row - 1]) { @@ -1352,20 +1488,20 @@ QUnit.diff = (function() { }; } } - + return { o: o, n: n }; } - - return function(o, n){ + + return function(o, n) { o = o.replace(/\s+$/, ''); n = n.replace(/\s+$/, ''); var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/)); var str = ""; - + var oSpace = o.match(/\s+/g); if (oSpace == null) { oSpace = [" "]; @@ -1380,7 +1516,7 @@ QUnit.diff = (function() { else { nSpace.push(" "); } - + if (out.n.length == 0) { for (var i = 0; i < out.o.length; i++) { str += '' + out.o[i] + oSpace[i] + ""; @@ -1392,14 +1528,14 @@ QUnit.diff = (function() { str += '' + out.o[n] + oSpace[n] + ""; } } - + for (var i = 0; i < out.n.length; i++) { if (out.n[i].text == null) { str += '' + out.n[i] + nSpace[i] + ""; } else { var pre = ""; - + for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { pre += '' + out.o[n] + oSpace[n] + ""; } @@ -1407,7 +1543,7 @@ QUnit.diff = (function() { } } } - + return str; }; })();