diff options
Diffstat (limited to 'external')
-rw-r--r-- | external/jquery.mousewheel.js (renamed from external/jquery.mousewheel-3.0.4.js) | 34 | ||||
-rw-r--r-- | external/qunit.css | 41 | ||||
-rw-r--r-- | external/qunit.js | 437 |
3 files changed, 343 insertions, 169 deletions
diff --git a/external/jquery.mousewheel-3.0.4.js b/external/jquery.mousewheel.js index dbf8f4b0f..808e12b89 100644 --- a/external/jquery.mousewheel-3.0.4.js +++ b/external/jquery.mousewheel.js @@ -1,12 +1,12 @@ -/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
+/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
* Licensed under the MIT License (LICENSE.txt).
*
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
* Thanks to: Seamus Leahy for adding deltaX and deltaY
*
- * Version: 3.0.4
- *
+ * Version: 3.0.6
+ *
* Requires: 1.2.2+
*/
@@ -14,6 +14,12 @@ var types = ['DOMMouseScroll', 'mousewheel'];
+if ($.event.fixHooks) {
+ for ( var i=types.length; i; ) {
+ $.event.fixHooks[ types[--i] ] = $.event.mouseHooks;
+ }
+}
+
$.event.special.mousewheel = {
setup: function() {
if ( this.addEventListener ) {
@@ -24,7 +30,7 @@ $.event.special.mousewheel = { this.onmousewheel = handler;
}
},
-
+
teardown: function() {
if ( this.removeEventListener ) {
for ( var i=types.length; i; ) {
@@ -40,7 +46,7 @@ $.fn.extend({ mousewheel: function(fn) {
return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
},
-
+
unmousewheel: function(fn) {
return this.unbind("mousewheel", fn);
}
@@ -51,28 +57,28 @@ function handler(event) { var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
event = $.event.fix(orgEvent);
event.type = "mousewheel";
-
+
// Old school scrollwheel delta
- if ( event.wheelDelta ) { delta = event.wheelDelta/120; }
- if ( event.detail ) { delta = -event.detail/3; }
-
+ if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; }
+ if ( orgEvent.detail ) { delta = -orgEvent.detail/3; }
+
// New school multidimensional scroll (touchpads) deltas
deltaY = delta;
-
+
// Gecko
if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
deltaY = 0;
deltaX = -1*delta;
}
-
+
// Webkit
if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
-
+
// Add event and delta to the front of the arguments
args.unshift(event, delta, deltaX, deltaY);
-
- return $.event.handle.apply(this, args);
+
+ return ($.event.dispatch || $.event.handle).apply(this, args);
}
})(jQuery);
\ No newline at end of file diff --git a/external/qunit.css b/external/qunit.css index 23235ec84..257b224ff 100644 --- a/external/qunit.css +++ b/external/qunit.css @@ -1,5 +1,5 @@ /** - * QUnit v1.6.0 - A JavaScript Unit Testing Framework + * QUnit v1.9.0 - A JavaScript Unit Testing Framework * * http://docs.jquery.com/QUnit * @@ -38,10 +38,10 @@ 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; - -webkit-border-top-left-radius: 15px; + border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-top-right-radius: 5px; + -webkit-border-top-left-radius: 5px; } #qunit-header a { @@ -54,9 +54,9 @@ color: #fff; } -#qunit-header label { +#qunit-testrunner-toolbar label { display: inline-block; - padding-left: 0.5em; + padding: 0 .5em 0 .1em; } #qunit-banner { @@ -113,13 +113,9 @@ 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; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; } #qunit-tests table { @@ -162,8 +158,7 @@ #qunit-tests b.failed { color: #710909; } #qunit-tests li li { - margin: 0.5em; - padding: 0.4em 0.5em 0.4em 0.5em; + padding: 5px; background-color: #fff; border-bottom: none; list-style-position: inside; @@ -172,9 +167,9 @@ /*** Passing Styles */ #qunit-tests li li.pass { - color: #5E740B; + color: #3c510c; background-color: #fff; - border-left: 26px solid #C6E746; + border-left: 10px solid #C6E746; } #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } @@ -190,15 +185,15 @@ #qunit-tests li li.fail { color: #710909; background-color: #fff; - border-left: 26px solid #EE5757; + border-left: 10px 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; + border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + -webkit-border-bottom-right-radius: 5px; + -webkit-border-bottom-left-radius: 5px; } #qunit-tests .fail { color: #000000; background-color: #EE5757; } diff --git a/external/qunit.js b/external/qunit.js index 2c277fab5..9efedcb44 100644 --- a/external/qunit.js +++ b/external/qunit.js @@ -1,5 +1,5 @@ /** - * QUnit v1.6.0 - A JavaScript Unit Testing Framework + * QUnit v1.9.0 - A JavaScript Unit Testing Framework * * http://docs.jquery.com/QUnit * @@ -12,7 +12,9 @@ var QUnit, config, + onErrorFnPrev, testId = 0, + fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty, defined = { @@ -29,26 +31,31 @@ var QUnit, }()) }; -function Test( name, testName, expected, async, callback ) { - this.name = name; - this.testName = testName; - this.expected = expected; - this.async = async; - this.callback = callback; +function Test( settings ) { + extend( this, settings ); this.assertions = []; + this.testNumber = ++Test.count; } +Test.count = 0; + Test.prototype = { init: function() { - var b, li, + var a, b, li, tests = id( "qunit-tests" ); if ( tests ) { b = document.createElement( "strong" ); - b.innerHTML = "Running " + this.name; + b.innerHTML = this.name; + + // `a` initialized at top of scope + a = document.createElement( "a" ); + a.innerHTML = "Rerun"; + a.href = QUnit.url({ testNumber: this.testNumber }); li = document.createElement( "li" ); li.appendChild( b ); + li.appendChild( a ); li.className = "running"; li.id = this.id = "qunit-test-output" + testId++; @@ -119,14 +126,14 @@ Test.prototype = { } if ( config.notrycatch ) { - this.callback.call( this.testEnvironment ); + this.callback.call( this.testEnvironment, QUnit.assert ); return; } try { - this.callback.call( this.testEnvironment ); + this.callback.call( this.testEnvironment, QUnit.assert ); } catch( e ) { - QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + ": " + e.message, extractStacktrace( e, 1 ) ); + QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + e.message, extractStacktrace( e, 0 ) ); // else next test will carry the responsibility saveGlobal(); @@ -152,13 +159,16 @@ Test.prototype = { }, finish: function() { config.current = this; - if ( this.expected != null && this.expected != this.assertions.length ) { + if ( config.requireExpects && this.expected == null ) { + QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); + } else if ( this.expected != null && this.expected != this.assertions.length ) { QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); } else if ( this.expected == null && !this.assertions.length ) { QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); } var assertion, a, b, i, li, ol, + test = this, good = 0, bad = 0, tests = id( "qunit-tests" ); @@ -203,11 +213,6 @@ Test.prototype = { b = document.createElement( "strong" ); b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>"; - // `a` initialized at top of scope - 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.nextSibling, display = next.style.display; @@ -220,9 +225,7 @@ Test.prototype = { target = target.parentNode; } if ( window.location && target.nodeName.toLowerCase() === "strong" ) { - window.location = QUnit.url({ - filter: getText([target]).replace( /\([^)]+\)$/, "" ).replace( /(^\s*|\s*$)/g, "" ) - }); + window.location = QUnit.url({ testNumber: test.testNumber }); } }); @@ -230,8 +233,9 @@ Test.prototype = { li = id( this.id ); li.className = bad ? "fail" : "pass"; li.removeChild( li.firstChild ); + a = li.firstChild; li.appendChild( b ); - li.appendChild( a ); + li.appendChild ( a ); li.appendChild( ol ); } else { @@ -253,6 +257,8 @@ Test.prototype = { }); QUnit.reset(); + + config.current = undefined; }, queue: function() { @@ -291,6 +297,7 @@ Test.prototype = { } }; +// Root QUnit object. // `QUnit` initialized at top of scope QUnit = { @@ -322,14 +329,21 @@ QUnit = { name = "<span class='module-name'>" + config.currentModule + "</span>: " + name; } - if ( !validTest(config.currentModule + ": " + testName) ) { + test = new Test({ + name: name, + testName: testName, + expected: expected, + async: async, + callback: callback, + module: config.currentModule, + moduleTestEnvironment: config.currentModuleTestEnviroment, + stack: sourceFromStacktrace( 2 ) + }); + + if ( !validTest( test ) ) { return; } - test = new Test( name, testName, expected, async, callback ); - test.module = config.currentModule; - test.moduleTestEnvironment = config.currentModuleTestEnviroment; - test.stack = sourceFromStacktrace( 2 ); test.queue(); }, @@ -338,8 +352,61 @@ QUnit = { config.current.expected = asserts; }, - // Asserts true. - // @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + start: function( count ) { + config.semaphore -= count || 1; + // don't start until equal number of stop-calls + if ( config.semaphore > 0 ) { + return; + } + // ignore if start is called more often then stop + if ( config.semaphore < 0 ) { + config.semaphore = 0; + } + // 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 ); + } + + config.blocking = false; + process( true ); + }, 13); + } else { + config.blocking = false; + process( true ); + } + }, + + stop: function( count ) { + config.semaphore += count || 1; + config.blocking = true; + + if ( config.testTimeout && defined.setTimeout ) { + clearTimeout( config.timeout ); + config.timeout = window.setTimeout(function() { + QUnit.ok( false, "Test timed out" ); + config.semaphore = 1; + QUnit.start(); + }, config.testTimeout ); + } + } +}; + +// Asssert helpers +// All of these must call either QUnit.push() or manually do: +// - runLoggingCallbacks( "log", .. ); +// - config.current.assertions.push({ .. }); +QUnit.assert = { + /** + * Asserts rough true-ish result. + * @name ok + * @function + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ ok: function( result, msg ) { if ( !config.current ) { throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); @@ -369,46 +436,74 @@ QUnit = { }); }, - // Checks that the first two arguments are equal, with an optional message. Prints out both actual and expected values. - // @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes." ); + /** + * Assert that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * @name equal + * @function + * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); + */ equal: function( actual, expected, message ) { QUnit.push( expected == actual, actual, expected, message ); }, + /** + * @name notEqual + * @function + */ notEqual: function( actual, expected, message ) { QUnit.push( expected != actual, actual, expected, message ); }, + /** + * @name deepEqual + * @function + */ deepEqual: function( actual, expected, message ) { QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); }, + /** + * @name notDeepEqual + * @function + */ notDeepEqual: function( actual, expected, message ) { QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); }, + /** + * @name strictEqual + * @function + */ strictEqual: function( actual, expected, message ) { QUnit.push( expected === actual, actual, expected, message ); }, + /** + * @name notStrictEqual + * @function + */ notStrictEqual: function( actual, expected, message ) { QUnit.push( expected !== actual, actual, expected, message ); }, - raises: function( block, expected, message ) { + throws: function( block, expected, message ) { var actual, ok = false; + // 'expected' is optional if ( typeof expected === "string" ) { message = expected; expected = null; } + config.current.ignoreGlobalErrors = true; try { block.call( config.current.testEnvironment ); } catch (e) { actual = e; } + config.current.ignoreGlobalErrors = false; if ( actual ) { // we don't want to validate thrown error @@ -424,53 +519,35 @@ QUnit = { } else if ( expected.call( {}, actual ) === true ) { ok = true; } - } - - QUnit.ok( ok, message ); - }, - - start: function( count ) { - config.semaphore -= count || 1; - // don't start until equal number of stop-calls - if ( config.semaphore > 0 ) { - return; - } - // ignore if start is called more often then stop - if ( config.semaphore < 0 ) { - config.semaphore = 0; - } - // 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 ); - } - config.blocking = false; - process( true ); - }, 13); + QUnit.push( ok, actual, null, message ); } else { - config.blocking = false; - process( true ); + QUnit.pushFailure( message, null, 'No exception was thrown.' ); } - }, + } +}; - stop: function( count ) { - config.semaphore += count || 1; - config.blocking = true; +/** + * @deprecate since 1.8.0 + * Kept assertion helpers in root for backwards compatibility + */ +extend( QUnit, QUnit.assert ); - if ( config.testTimeout && defined.setTimeout ) { - clearTimeout( config.timeout ); - config.timeout = window.setTimeout(function() { - QUnit.ok( false, "Test timed out" ); - config.semaphore = 1; - QUnit.start(); - }, config.testTimeout ); - } - } +/** + * @deprecated since 1.9.0 + * Kept global "raises()" for backwards compatibility + */ +QUnit.raises = QUnit.assert.throws; + +/** + * @deprecated since 1.0.0, replaced with error pushes since 1.3.0 + * Kept to avoid TypeErrors for undefined methods. + */ +QUnit.equals = function() { + QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); +}; +QUnit.same = function() { + QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); }; // We want access to the constructor's prototype @@ -482,17 +559,11 @@ QUnit = { QUnit.constructor = F; }()); -// deprecated; still export them to window to provide clear error messages -// next step: remove entirely -QUnit.equals = function() { - QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); -}; -QUnit.same = function() { - QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); -}; - -// Maintain internal state -// `config` initialized at top of scope +/** + * Config object: Maintain internal state + * Later exposed as QUnit.config + * `config` initialized at top of scope + */ config = { // The queue of tests to run queue: [], @@ -511,7 +582,23 @@ config = { // by default, modify document.title when suite is done altertitle: true, - urlConfig: [ "noglobals", "notrycatch" ], + // when enabled, all tests must call expect() + requireExpects: false, + + // add checkboxes that are persisted in the query-string + // when enabled, the id is set to `true` as a `QUnit.config` property + urlConfig: [ + { + id: "noglobals", + label: "Check for Globals", + tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." + }, + { + id: "notrycatch", + label: "No try-catch", + tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." + } + ], // logging callback queues begin: [], @@ -523,7 +610,7 @@ config = { moduleDone: [] }; -// Load paramaters +// Initialize more QUnit.config and QUnit.urlParams (function() { var i, location = window.location || { search: "", protocol: "file:" }, @@ -543,20 +630,30 @@ config = { } QUnit.urlParams = urlParams; + + // String search anywhere in moduleName+testName config.filter = urlParams.filter; + // Exact match of the module name + config.module = urlParams.module; + + config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; + // Figure out if we're running the tests from a server or not QUnit.isLocal = location.protocol === "file:"; }()); -// Expose the API as global variables, unless an 'exports' object exists, -// in that case we assume we're in CommonJS - export everything at the end +// Export global variables, unless an 'exports' object exists, +// in that case we assume we're in CommonJS (dealt with on the bottom of the script) if ( typeof exports === "undefined" ) { extend( window, QUnit ); + + // Expose QUnit object window.QUnit = QUnit; } -// define these after exposing globals to keep them in these QUnit namespace only +// Extend QUnit object, +// these after set here because they should not be exposed as global functions extend( QUnit, { config: config, @@ -722,22 +819,34 @@ extend( QUnit, { }); }, - pushFailure: function( message, source ) { + pushFailure: function( message, source, actual ) { + if ( !config.current ) { + throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + var output, details = { result: false, message: message }; - message = escapeInnerText(message ) || "error"; + message = escapeInnerText( message ) || "error"; message = "<span class='test-message'>" + message + "</span>"; output = message; + output += "<table>"; + + if ( actual ) { + output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeInnerText( actual ) + "</pre></td></tr>"; + } + if ( source ) { details.source = source; - output += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>"; + output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>"; } + output += "</table>"; + runLoggingCallbacks( "log", QUnit, details ); config.current.assertions.push({ @@ -764,25 +873,37 @@ extend( QUnit, { extend: extend, id: id, addEvent: addEvent + // load, equiv, jsDump, diff: Attached later }); -// 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. +/** + * @deprecated: Created for backwards compatibility with test runner that set the hook function + * into QUnit.{hook}, instead of invoking it and passing the hook function. + * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. + * Doing this allows us to tell if the following methods have been overwritten on the actual + * QUnit object. + */ extend( QUnit.constructor.prototype, { + // Logging callbacks; all receive a single argument with the listed properties // run test/logs.html for any related changes begin: registerLoggingCallback( "begin" ), + // done: { failed, passed, total, runtime } done: registerLoggingCallback( "done" ), + // log: { result, actual, expected, message } log: registerLoggingCallback( "log" ), + // testStart: { name } testStart: registerLoggingCallback( "testStart" ), + // testDone: { name, failed, passed, total } testDone: registerLoggingCallback( "testDone" ), + // moduleStart: { name } moduleStart: registerLoggingCallback( "moduleStart" ), + // moduleDone: { name, failed, passed, total } moduleDone: registerLoggingCallback( "moduleDone" ) }); @@ -795,7 +916,7 @@ QUnit.load = function() { runLoggingCallbacks( "begin", QUnit, {} ); // Initialize the config, saving the execution queue - var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, + var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, urlConfigCheckboxes, urlConfigHtml = "", oldconfig = extend( {}, config ); @@ -808,8 +929,15 @@ QUnit.load = function() { for ( i = 0; i < len; i++ ) { val = config.urlConfig[i]; - config[val] = QUnit.urlParams[val]; - urlConfigHtml += "<label><input name='" + val + "' type='checkbox'" + ( config[val] ? " checked='checked'" : "" ) + ">" + val + "</label>"; + if ( typeof val === "string" ) { + val = { + id: val, + label: val, + tooltip: "[no tooltip available]" + }; + } + config[ val.id ] = QUnit.urlParams[ val.id ]; + urlConfigHtml += "<input id='qunit-urlconfig-" + val.id + "' name='" + val.id + "' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) + " title='" + val.tooltip + "'><label for='qunit-urlconfig-" + val.id + "' title='" + val.tooltip + "'>" + val.label + "</label>"; } // `userAgent` initialized at top of scope @@ -821,12 +949,7 @@ QUnit.load = function() { // `banner` initialized at top of scope banner = id( "qunit-header" ); if ( banner ) { - banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined }) + "'>" + banner.innerHTML + "</a> " + urlConfigHtml; - addEvent( banner, "change", function( event ) { - var params = {}; - params[ event.target.name ] = event.target.checked ? true : undefined; - window.location = QUnit.url( params ); - }); + banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) + "'>" + banner.innerHTML + "</a> "; } // `toolbar` initialized at top of scope @@ -867,8 +990,18 @@ QUnit.load = function() { // `label` initialized at top of scope label = document.createElement( "label" ); label.setAttribute( "for", "qunit-filter-pass" ); + label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." ); label.innerHTML = "Hide passed tests"; toolbar.appendChild( label ); + + urlConfigCheckboxes = document.createElement( 'span' ); + urlConfigCheckboxes.innerHTML = urlConfigHtml; + addEvent( urlConfigCheckboxes, "change", function( event ) { + var params = {}; + params[ event.target.name ] = event.target.checked ? true : undefined; + window.location = QUnit.url( params ); + }); + toolbar.appendChild( urlConfigCheckboxes ); } // `main` initialized at top of scope @@ -884,15 +1017,36 @@ QUnit.load = function() { addEvent( window, "load", QUnit.load ); -// addEvent(window, "error" ) gives us a useless event object -window.onerror = function( message, file, line ) { - if ( QUnit.config.current ) { - QUnit.pushFailure( message, file + ":" + line ); - } else { - QUnit.test( "global failure", function() { - QUnit.pushFailure( message, file + ":" + line ); - }); +// `onErrorFnPrev` initialized at top of scope +// Preserve other handlers +onErrorFnPrev = window.onerror; + +// Cover uncaught exceptions +// Returning true will surpress the default browser handler, +// returning false will let it run. +window.onerror = function ( error, filePath, linerNr ) { + var ret = false; + if ( onErrorFnPrev ) { + ret = onErrorFnPrev( error, filePath, linerNr ); } + + // Treat return value as window.onerror itself does, + // Only do our handling if not surpressed. + if ( ret !== true ) { + if ( QUnit.config.current ) { + if ( QUnit.config.current.ignoreGlobalErrors ) { + return true; + } + QUnit.pushFailure( error, filePath + ":" + linerNr ); + } else { + QUnit.test( "global failure", function() { + QUnit.pushFailure( error, filePath + ":" + linerNr ); + }); + } + return false; + } + + return ret; }; function done() { @@ -962,39 +1116,46 @@ function done() { }); } -function validTest( name ) { - var not, - filter = config.filter, - run = false; +/** @return Boolean: true if this test should be ran */ +function validTest( test ) { + var include, + filter = config.filter && config.filter.toLowerCase(), + module = config.module && config.module.toLowerCase(), + fullName = (test.module + ": " + test.testName).toLowerCase(); - if ( !filter ) { - return true; + if ( config.testNumber ) { + return test.testNumber === config.testNumber; } - not = filter.charAt( 0 ) === "!"; + if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { + return false; + } - if ( not ) { - filter = filter.slice( 1 ); + if ( !filter ) { + return true; } - if ( name.indexOf( filter ) !== -1 ) { - return !not; + include = filter.charAt( 0 ) !== "!"; + if ( !include ) { + filter = filter.slice( 1 ); } - if ( not ) { - run = true; + // If the filter matches, we need to honour include + if ( fullName.indexOf( filter ) !== -1 ) { + return include; } - return run; + // Otherwise, do the opposite + return !include; } // so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) // Later Safari and IE10 are supposed to support error.stack as well // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack function extractStacktrace( e, offset ) { - offset = offset || 3; + offset = offset === undefined ? 3 : offset; - var stack; + var stack, include, i, regex; if ( e.stacktrace ) { // Opera @@ -1005,6 +1166,18 @@ function extractStacktrace( e, offset ) { if (/^error$/i.test( stack[0] ) ) { stack.shift(); } + if ( fileName ) { + include = []; + for ( i = offset; i < stack.length; i++ ) { + if ( stack[ i ].indexOf( fileName ) != -1 ) { + break; + } + include.push( stack[ i ] ); + } + if ( include.length ) { + return include.join( "\n" ); + } + } return stack[ offset ]; } else if ( e.sourceURL ) { // Safari, PhantomJS @@ -1419,11 +1592,11 @@ QUnit.jsDump = (function() { type = "null"; } else if ( typeof obj === "undefined" ) { type = "undefined"; - } else if ( QUnit.is( "RegExp", obj) ) { + } else if ( QUnit.is( "regexp", obj) ) { type = "regexp"; - } else if ( QUnit.is( "Date", obj) ) { + } else if ( QUnit.is( "date", obj) ) { type = "date"; - } else if ( QUnit.is( "Function", obj) ) { + } else if ( QUnit.is( "function", obj) ) { type = "function"; } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { type = "window"; |