diff --git a/reporter/html.js b/reporter/html.js index 94de44c42..3f3068aea 100644 --- a/reporter/html.js +++ b/reporter/html.js @@ -668,6 +668,9 @@ QUnit.testDone(function( details ) { time.innerHTML = details.runtime + " ms"; testItem.className = bad ? "fail" : "pass"; + if ( details.skipped ) { + addClass( testItem, "skipped" ); + } testItem.insertBefore( time, assertList ); }); diff --git a/src/core.js b/src/core.js index 3a9bf4fb5..166446660 100644 --- a/src/core.js +++ b/src/core.js @@ -117,15 +117,17 @@ QUnit = { testName: testName, expected: expected, async: async, - callback: callback, - module: config.currentModule, - moduleTestEnvironment: config.currentModuleTestEnvironment, - stack: sourceFromStacktrace( 2 ) + callback: callback }); - if ( !validTest( test ) ) { - return; - } + test.queue(); + }, + + skip: function( testName ) { + var test = new Test({ + testName: testName, + skip: true + }); test.queue(); }, @@ -447,7 +449,7 @@ window.onerror = function( error, filePath, linerNr ) { } else { QUnit.test( "global failure", extend(function() { QUnit.pushFailure( error, filePath + ":" + linerNr ); - }, { validTest: validTest } ) ); + }, { validTest: true } ) ); } return false; } @@ -481,47 +483,6 @@ function done() { }); } -/** @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(); - - // Internally-generated tests are always valid - if ( test.callback && test.callback.validTest === validTest ) { - delete test.callback.validTest; - return true; - } - - if ( config.testNumber.length > 0 ) { - if ( inArray( test.testNumber, config.testNumber ) < 0 ) { - return false; - } - } - - if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { - return false; - } - - if ( !filter ) { - return true; - } - - include = filter.charAt( 0 ) !== "!"; - if ( !include ) { - filter = filter.slice( 1 ); - } - - // If the filter matches, we need to honour include - if ( fullName.indexOf( filter ) !== -1 ) { - return include; - } - - // Otherwise, do the opposite - return !include; -} - // Doesn't support IE6 to IE9 // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack function extractStacktrace( e, offset ) { diff --git a/src/qunit.css b/src/qunit.css index ca8fe3893..ed53ef64c 100644 --- a/src/qunit.css +++ b/src/qunit.css @@ -211,6 +211,11 @@ #qunit-banner.qunit-fail { background-color: #EE5757; } +/*** Skipped tests */ + +#qunit-tests .skipped { + background-color: #EBECE9; +} /** Result */ diff --git a/src/test.js b/src/test.js index 92dd8bae0..01df7cc2e 100644 --- a/src/test.js +++ b/src/test.js @@ -1,8 +1,18 @@ function Test( settings ) { extend( this, settings ); - this.assert = new Assert( this ); this.assertions = []; this.testNumber = ++Test.count; + this.module = config.currentModule; + this.moduleTestEnvironment = config.currentModuleTestEnvironment; + this.stack = sourceFromStacktrace( 3 ); + + if ( settings.skip ) { + this.callback = function() {}; + this.async = false; + this.expected = 0; + } else { + this.assert = new Assert( this ); + } } Test.count = 0; @@ -102,6 +112,11 @@ Test.prototype = { hooks: function( handler ) { var hooks = []; + // hooks are also ignored on skipped tests + if ( this.skip ) { + return hooks; + } + if ( QUnit.objectType( config[ handler ] ) === "function" ) { hooks.push( this.queueHook( config[ handler ], handler ) ); } @@ -139,6 +154,7 @@ Test.prototype = { runLoggingCallbacks( "testDone", { name: this.testName, module: this.module, + skipped: !!this.skip, failed: bad, passed: this.assertions.length - bad, total: this.assertions.length, @@ -159,6 +175,10 @@ Test.prototype = { var bad, test = this; + if ( !this.valid() ) { + return; + } + function run() { // each of these can by async @@ -250,6 +270,47 @@ Test.prototype = { result: false, message: message }); + }, + + /** @return Boolean: true if this test should be ran */ + valid: function() { + var include, + filter = config.filter && config.filter.toLowerCase(), + module = config.module && config.module.toLowerCase(), + fullName = ( this.module + ": " + this.testName ).toLowerCase(); + + // Internally-generated tests are always valid + if ( this.callback && this.callback.validTest ) { + delete this.callback.validTest; + return true; + } + + if ( config.testNumber.length > 0 ) { + if ( inArray( this.testNumber, config.testNumber ) < 0 ) { + return false; + } + } + + if ( module && ( !this.module || this.module.toLowerCase() !== module ) ) { + return false; + } + + if ( !filter ) { + return true; + } + + include = filter.charAt( 0 ) !== "!"; + if ( !include ) { + filter = filter.slice( 1 ); + } + + // If the filter matches, we need to honour include + if ( fullName.indexOf( filter ) !== -1 ) { + return include; + } + + // Otherwise, do the opposite + return !include; } }; diff --git a/test/logs.js b/test/logs.js index 0739cc937..92b4e7e5b 100644 --- a/test/logs.js +++ b/test/logs.js @@ -150,7 +150,8 @@ QUnit.test( "test2", function( assert ) { failed: 0, passed: 17, total: 17, - testNumber: 1 + testNumber: 1, + skipped: false }, "testDone context" ); assert.deepEqual( testContext, { module: "logs1", diff --git a/test/test.js b/test/test.js index 627560669..02abbd1ca 100644 --- a/test/test.js +++ b/test/test.js @@ -438,3 +438,25 @@ QUnit.test( "mod2", function( assert ) { assert.mod2( 2, 0, "2 % 2 == 0" ); assert.mod2( 3, 1, "3 % 2 == 1" ); }); + +QUnit.module( "QUnit.skip", { + beforeEach: function( assert ) { + + // skip test hooks for skipped tests + assert.ok( false, "skipped function" ); + throw "Error"; + }, + afterEach: function( assert ) { + assert.ok( false, "skipped function" ); + throw "Error"; + } +}); + +QUnit.skip( "test blocks are skipped", function( assert ) { + + // this test callback won't run, even with broken code + assert.expect( 1000 ); + throw "Error"; +}); + +QUnit.skip( "no function" );