diff --git a/Gruntfile.js b/Gruntfile.js index f1fbe1dd1..77f04b44a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -75,9 +75,6 @@ module.exports = function( grunt ) { "test/reorder.html", "test/reorderError1.html", "test/reorderError2.html", - "test/callbacks.html", - "test/callbacks-promises.html", - "test/events.html", "test/events-filters.html", "test/events-in-test.html", "test/logs.html", @@ -128,7 +125,6 @@ module.exports = function( grunt ) { "test/main/deepEqual.js", "test/main/stack.js", "test/main/utilities.js", - "test/events.js", "test/events-in-test.js", "test/onerror/inside-test.js", "test/onerror/outside-test.js", diff --git a/test/callbacks-promises.html b/test/callbacks-promises.html deleted file mode 100644 index d4bfcdd92..000000000 --- a/test/callbacks-promises.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - QUnit Callbacks Test Suite - - - - - -
-
- - diff --git a/test/callbacks-promises.js b/test/callbacks-promises.js deleted file mode 100644 index f69058d1c..000000000 --- a/test/callbacks-promises.js +++ /dev/null @@ -1,129 +0,0 @@ -var done = false; -var invokedHooks = []; - -function timeoutPromiseCallback( callback, timeout ) { - return new Promise( function( resolve ) { - setTimeout( function() { - callback(); - resolve(); - }, timeout ); - } ); -} - -QUnit.begin( function() { - return timeoutPromiseCallback( function() { - invokedHooks.push( "begin" ); - }, 100 ); -} ); -QUnit.begin( function() { - return timeoutPromiseCallback( function() { - - // This is the second begin callback, which should - // be executed only after the first one - if ( invokedHooks.indexOf( "begin" ) !== 0 ) { - return; - } - invokedHooks.push( "begin2" ); - }, 10 ); -} ); -QUnit.moduleStart( function() { - return timeoutPromiseCallback( function() { - invokedHooks.push( "moduleStart" ); - }, 100 ); -} ); -QUnit.testStart( function( cb ) { - return timeoutPromiseCallback( function() { - invokedHooks.push( "testStart - " + cb.name ); - }, 100 ); -} ); - -QUnit.testDone( function( cb ) { - return timeoutPromiseCallback( function() { - invokedHooks.push( "testDone - " + cb.name ); - }, 100 ); -} ); -QUnit.moduleDone( function( cb ) { - return timeoutPromiseCallback( function() { - invokedHooks.push( "moduleDone - " + cb.name ); - }, 100 ); -} ); -QUnit.done( function() { - return timeoutPromiseCallback( function() { - invokedHooks.push( "done" ); - }, 100 ); -} ); - -QUnit.done( function() { - if ( done ) { - return; - } - - done = true; - - QUnit.test( "verify callback order", function( assert ) { - assert.deepEqual( invokedHooks, [ - "begin", - "begin2", - "moduleStart", - "moduleStart", - "testStart - test1", - "testDone - test1", - "moduleDone - module1 > nestedModule1", - "testStart - test2", - "testDone - test2", - "moduleStart", - "testStart - test3", - "testDone - test3", - "moduleDone - module1 > nestedModule2", - "moduleDone - module1", - "done", - "moduleStart", - "testStart - verify callback order" - ] ); - } ); -} ); - -QUnit.module( "module1", function() { - QUnit.module( "nestedModule1", function() { - QUnit.test( "test1", function( assert ) { - assert.deepEqual( invokedHooks, [ - "begin", - "begin2", - "moduleStart", - "moduleStart", - "testStart - test1" - ] ); - } ); - } ); - - QUnit.test( "test2", function( assert ) { - assert.deepEqual( invokedHooks, [ - "begin", - "begin2", - "moduleStart", - "moduleStart", - "testStart - test1", - "testDone - test1", - "moduleDone - module1 > nestedModule1", - "testStart - test2" - ] ); - } ); - - QUnit.module( "nestedModule2", function() { - QUnit.test( "test3", function( assert ) { - assert.deepEqual( invokedHooks, [ - "begin", - "begin2", - "moduleStart", - "moduleStart", - "testStart - test1", - "testDone - test1", - "moduleDone - module1 > nestedModule1", - "testStart - test2", - "testDone - test2", - "moduleStart", - "testStart - test3" - ] ); - } ); - } ); -} ); diff --git a/test/callbacks.html b/test/callbacks.html deleted file mode 100644 index 187df4f4b..000000000 --- a/test/callbacks.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - QUnit Callbacks Test Suite - - - - - -
-
- - diff --git a/test/callbacks.js b/test/callbacks.js deleted file mode 100644 index 22f13b4be..000000000 --- a/test/callbacks.js +++ /dev/null @@ -1,174 +0,0 @@ -var invokedHooks = []; -var done = false; - -function callback( name ) { - return function() { - if ( done ) { - return; - } - - invokedHooks.push( name ); - }; -} - -QUnit.begin( callback( "begin1" ) ); -QUnit.begin( callback( "begin2" ) ); -QUnit.moduleStart( callback( "moduleStart1" ) ); -QUnit.moduleStart( callback( "moduleStart2" ) ); -QUnit.testStart( callback( "testStart1" ) ); -QUnit.testStart( callback( "testStart2" ) ); - -QUnit.log( callback( "log1" ) ); -QUnit.log( callback( "log2" ) ); - -QUnit.testDone( callback( "testDone1" ) ); -QUnit.testDone( callback( "testDone2" ) ); -QUnit.moduleDone( callback( "moduleDone1" ) ); -QUnit.moduleDone( callback( "moduleDone2" ) ); -QUnit.done( callback( "done1" ) ); -QUnit.done( callback( "done2" ) ); - -QUnit.done( function() { - if ( done ) { - return; - } - - done = true; - - QUnit.test( "verify callback order", function( assert ) { - assert.deepEqual( invokedHooks, [ - "begin1", - "begin2", - "moduleStart1", - "moduleStart2", - "testStart1", - "testStart2", - "module1 > before", - "module1 > beforeEach", - "module1 > test1", - "log1", - "log2", - "module1 > afterEach", - "testDone1", - "testDone2", - "moduleStart1", - "moduleStart2", - "testStart1", - "testStart2", - "module2 > before", - "module1 > beforeEach", - "module2 > beforeEach", - "module2 > test1", - "log1", - "log2", - "module2 > afterEach", - "module1 > afterEach", - "module2 > after", - "testDone1", - "testDone2", - "moduleDone1", - "moduleDone2", - "moduleStart1", - "moduleStart2", - "testStart1", - "testStart2", - "module3 > before", - "module1 > beforeEach", - "module3 > beforeEach", - "module3 > test1", - "log1", - "log2", - "module3 > afterEach", - "module1 > afterEach", - "module3 > after", - "testDone1", - "testDone2", - "moduleDone1", - "moduleDone2", - "testStart1", - "testStart2", - "module1 > beforeEach", - "module1 > test2", - "log1", - "log2", - "module1 > afterEach", - "testDone1", - "testDone2", - "moduleStart1", - "moduleStart2", - "testStart1", - "testStart2", - "module4 > before", - "module1 > beforeEach", - "module4 > beforeEach", - "module4 > test1", - "log1", - "log2", - "module4 > afterEach", - "module1 > afterEach", - "module4 > after", - "module1 > after", - "testDone1", - "testDone2", - "moduleDone1", - "moduleDone2", - "moduleDone1", - "moduleDone2", - "done1", - "done2" - ] ); - } ); -} ); - -QUnit.module( "module1", { - before: callback( "module1 > before" ), - beforeEach: callback( "module1 > beforeEach" ), - afterEach: callback( "module1 > afterEach" ), - after: callback( "module1 > after" ) -}, function() { - QUnit.test( "test1", function( assert ) { - invokedHooks.push( "module1 > test1" ); - assert.true( true ); - } ); - - QUnit.module( "module2", { - before: callback( "module2 > before" ), - beforeEach: callback( "module2 > beforeEach" ), - afterEach: callback( "module2 > afterEach" ), - after: callback( "module2 > after" ) - }, function() { - QUnit.test( "test1", function( assert ) { - invokedHooks.push( "module2 > test1" ); - assert.true( true ); - } ); - } ); - - QUnit.module( "module3", { - before: callback( "module3 > before" ), - beforeEach: callback( "module3 > beforeEach" ), - afterEach: callback( "module3 > afterEach" ), - after: callback( "module3 > after" ) - }, function() { - QUnit.test( "test1", function( assert ) { - invokedHooks.push( "module3 > test1" ); - assert.true( true ); - } ); - } ); - - QUnit.test( "test2", function( assert ) { - invokedHooks.push( "module1 > test2" ); - assert.true( true ); - } ); - - QUnit.module( "module4", { - before: callback( "module4 > before" ), - beforeEach: callback( "module4 > beforeEach" ), - afterEach: callback( "module4 > afterEach" ), - after: callback( "module4 > after" ) - }, function() { - QUnit.test( "test1", function( assert ) { - invokedHooks.push( "module4 > test1" ); - assert.true( true ); - } ); - } ); -} ); diff --git a/test/events.js b/test/cli/events.js similarity index 83% rename from test/events.js rename to test/cli/events.js index 14c459876..1957e82a2 100644 --- a/test/events.js +++ b/test/cli/events.js @@ -3,32 +3,47 @@ * by QUnit after the test run finishes. They are expected to adhere to the * js-reporters standard. */ - -var invokedHooks = [], - invokedHookDetails = {}, - done = false; +const invokedHooks = []; +const invokedHookDetails = {}; +const requireQUnit = require( "../../src/cli/require-qunit" ); +const myQUnit = requireQUnit(); function callback( name ) { invokedHookDetails[ name ] = []; return function( details ) { - if ( done ) { - return; - } - invokedHooks.push( name ); invokedHookDetails[ name ].push( details ); }; } -QUnit.on( "runStart", callback( "runStart" ) ); -QUnit.on( "suiteStart", callback( "suiteStart" ) ); -QUnit.on( "testStart", callback( "testStart" ) ); -QUnit.on( "assertion", callback( "assertion1" ) ); -QUnit.on( "assertion", callback( "assertion2" ) ); -QUnit.on( "testEnd", callback( "testEnd" ) ); -QUnit.on( "suiteEnd", callback( "suiteEnd" ) ); -QUnit.on( "runEnd", callback( "runEnd" ) ); +myQUnit.on( "runStart", callback( "runStart" ) ); +myQUnit.on( "suiteStart", callback( "suiteStart" ) ); +myQUnit.on( "testStart", callback( "testStart" ) ); +myQUnit.on( "assertion", callback( "assertion1" ) ); +myQUnit.on( "assertion", callback( "assertion2" ) ); +myQUnit.on( "testEnd", callback( "testEnd" ) ); +myQUnit.on( "suiteEnd", callback( "suiteEnd" ) ); +myQUnit.on( "runEnd", callback( "runEnd" ) ); + +myQUnit.module( "Events", function() { + myQUnit.module( "Nested", function() { + myQUnit.todo( "test1", function( assert ) { + assert.true( false, "failing assertion" ); + } ); + } ); + + myQUnit.test( "test2", function( assert ) { + assert.true( true, "passing assertion" ); + } ); + + myQUnit.skip( "test3" ); +} ); + +const myQunitRun = new Promise( resolve => { + myQUnit.on( "runEnd", resolve ); +} ); +myQUnit.start(); var test1Start = { name: "test1", @@ -178,15 +193,12 @@ function removeUnstableProperties( obj ) { // After all the tests run, we verify the events were fired in the correct order // with the correct data -QUnit.done( function() { - if ( done ) { - return; - } +QUnit.module( "Events", function() { - done = true; + QUnit.test( "verify callback order and data at end of test", async assert => { + + await myQunitRun; - QUnit.module( "Events-postdone" ); - QUnit.test( "verify callback order and data at end of test", function( assert ) { assert.deepEqual( invokedHooks, [ "runStart", "suiteStart", @@ -273,17 +285,3 @@ QUnit.done( function() { ); } ); } ); - -QUnit.module( "Events", function() { - QUnit.module( "Nested", function() { - QUnit.todo( "test1", function( assert ) { - assert.true( false, "failing assertion" ); - } ); - } ); - - QUnit.test( "test2", function( assert ) { - assert.true( true, "passing assertion" ); - } ); - - QUnit.skip( "test3" ); -} ); diff --git a/test/cli/fixtures/callbacks-promises.js b/test/cli/fixtures/callbacks-promises.js new file mode 100644 index 000000000..bebed7e84 --- /dev/null +++ b/test/cli/fixtures/callbacks-promises.js @@ -0,0 +1,63 @@ +function timeoutPromiseCallback( callback, timeout ) { + return new Promise( function( resolve ) { + setTimeout( function() { + callback(); + resolve(); + }, timeout ); + } ); +} + +QUnit.begin( function() { + return timeoutPromiseCallback( function() { + console.warn( "CALLBACK: begin" ); + }, 100 ); +} ); +QUnit.begin( function() { + return timeoutPromiseCallback( function() { + console.warn( "CALLBACK: begin2" ); + }, 10 ); +} ); +QUnit.moduleStart( function() { + return timeoutPromiseCallback( function() { + console.warn( "CALLBACK: moduleStart" ); + }, 100 ); +} ); +QUnit.testStart( function( cb ) { + return timeoutPromiseCallback( function() { + console.warn( "CALLBACK: testStart - " + cb.name ); + }, 100 ); +} ); + +QUnit.testDone( function( cb ) { + return timeoutPromiseCallback( function() { + console.warn( "CALLBACK: testDone - " + cb.name ); + }, 100 ); +} ); +QUnit.moduleDone( function( cb ) { + return timeoutPromiseCallback( function() { + console.warn( "CALLBACK: moduleDone - " + cb.name ); + }, 100 ); +} ); +QUnit.done( function() { + return timeoutPromiseCallback( function() { + console.warn( "CALLBACK: done" ); + }, 100 ); +} ); + +QUnit.module( "module1", function() { + QUnit.module( "nestedModule1", function() { + QUnit.test( "test1", function( assert ) { + assert.true( true ); + } ); + } ); + + QUnit.test( "test2", function( assert ) { + assert.true( true ); + } ); + + QUnit.module( "nestedModule2", function() { + QUnit.test( "test3", function( assert ) { + assert.true( true ); + } ); + } ); +} ); diff --git a/test/cli/fixtures/callbacks.js b/test/cli/fixtures/callbacks.js new file mode 100644 index 000000000..a543cf462 --- /dev/null +++ b/test/cli/fixtures/callbacks.js @@ -0,0 +1,75 @@ +function callback( name ) { + return function() { + console.warn( "CALLBACK: " + name ); + }; +} + +QUnit.begin( callback( "begin1" ) ); +QUnit.begin( callback( "begin2" ) ); +QUnit.moduleStart( callback( "moduleStart1" ) ); +QUnit.moduleStart( callback( "moduleStart2" ) ); +QUnit.testStart( callback( "testStart1" ) ); +QUnit.testStart( callback( "testStart2" ) ); + +QUnit.log( callback( "log1" ) ); +QUnit.log( callback( "log2" ) ); + +QUnit.testDone( callback( "testDone1" ) ); +QUnit.testDone( callback( "testDone2" ) ); +QUnit.moduleDone( callback( "moduleDone1" ) ); +QUnit.moduleDone( callback( "moduleDone2" ) ); +QUnit.done( callback( "done1" ) ); +QUnit.done( callback( "done2" ) ); + +QUnit.module( "module1", { + before: callback( "module1 > before" ), + beforeEach: callback( "module1 > beforeEach" ), + afterEach: callback( "module1 > afterEach" ), + after: callback( "module1 > after" ) +}, function() { + QUnit.test( "test1", function( assert ) { + console.warn( "TEST: module1 > test1" ); + assert.true( true ); + } ); + + QUnit.module( "module2", { + before: callback( "module2 > before" ), + beforeEach: callback( "module2 > beforeEach" ), + afterEach: callback( "module2 > afterEach" ), + after: callback( "module2 > after" ) + }, function() { + QUnit.test( "test1", function( assert ) { + console.warn( "TEST: module2 > test1" ); + assert.true( true ); + } ); + } ); + + QUnit.module( "module3", { + before: callback( "module3 > before" ), + beforeEach: callback( "module3 > beforeEach" ), + afterEach: callback( "module3 > afterEach" ), + after: callback( "module3 > after" ) + }, function() { + QUnit.test( "test1", function( assert ) { + console.warn( "TEST: module3 > test1" ); + assert.true( true ); + } ); + } ); + + QUnit.test( "test2", function( assert ) { + console.warn( "TEST: module1 > test2" ); + assert.true( true ); + } ); + + QUnit.module( "module4", { + before: callback( "module4 > before" ), + beforeEach: callback( "module4 > beforeEach" ), + afterEach: callback( "module4 > afterEach" ), + after: callback( "module4 > after" ) + }, function() { + QUnit.test( "test1", function( assert ) { + console.warn( "TEST: module4 > test1" ); + assert.true( true ); + } ); + } ); +} ); diff --git a/test/cli/main.js b/test/cli/main.js index f144c19d3..aa43051d5 100644 --- a/test/cli/main.js +++ b/test/cli/main.js @@ -71,8 +71,8 @@ QUnit.module( "CLI Main", () => { try { await execute( "qunit syntax-error/test.js" ); } catch ( e ) { - assert.notEqual( e.stdout.indexOf( "not ok 1 syntax-error/test.js > Failed to load the test file with error:" ), -1 ); - assert.notEqual( e.stdout.indexOf( "ReferenceError: varIsNotDefined is not defined" ), -1 ); + assert.true( e.stdout.includes( "not ok 1 syntax-error/test.js > Failed to load the test file with error:" ) ); + assert.true( e.stdout.includes( "ReferenceError: varIsNotDefined is not defined" ) ); assert.equal( e.code, 1 ); } } ); @@ -176,6 +176,118 @@ QUnit.module( "CLI Main", () => { } } ); + QUnit.test( "callbacks", async assert => { + const expected = `CALLBACK: begin1 +CALLBACK: begin2 +CALLBACK: moduleStart1 +CALLBACK: moduleStart2 +CALLBACK: testStart1 +CALLBACK: testStart2 +CALLBACK: module1 > before +CALLBACK: module1 > beforeEach +TEST: module1 > test1 +CALLBACK: log1 +CALLBACK: log2 +CALLBACK: module1 > afterEach +CALLBACK: testDone1 +CALLBACK: testDone2 +CALLBACK: moduleStart1 +CALLBACK: moduleStart2 +CALLBACK: testStart1 +CALLBACK: testStart2 +CALLBACK: module2 > before +CALLBACK: module1 > beforeEach +CALLBACK: module2 > beforeEach +TEST: module2 > test1 +CALLBACK: log1 +CALLBACK: log2 +CALLBACK: module2 > afterEach +CALLBACK: module1 > afterEach +CALLBACK: module2 > after +CALLBACK: testDone1 +CALLBACK: testDone2 +CALLBACK: moduleDone1 +CALLBACK: moduleDone2 +CALLBACK: moduleStart1 +CALLBACK: moduleStart2 +CALLBACK: testStart1 +CALLBACK: testStart2 +CALLBACK: module3 > before +CALLBACK: module1 > beforeEach +CALLBACK: module3 > beforeEach +TEST: module3 > test1 +CALLBACK: log1 +CALLBACK: log2 +CALLBACK: module3 > afterEach +CALLBACK: module1 > afterEach +CALLBACK: module3 > after +CALLBACK: testDone1 +CALLBACK: testDone2 +CALLBACK: moduleDone1 +CALLBACK: moduleDone2 +CALLBACK: testStart1 +CALLBACK: testStart2 +CALLBACK: module1 > beforeEach +TEST: module1 > test2 +CALLBACK: log1 +CALLBACK: log2 +CALLBACK: module1 > afterEach +CALLBACK: testDone1 +CALLBACK: testDone2 +CALLBACK: moduleStart1 +CALLBACK: moduleStart2 +CALLBACK: testStart1 +CALLBACK: testStart2 +CALLBACK: module4 > before +CALLBACK: module1 > beforeEach +CALLBACK: module4 > beforeEach +TEST: module4 > test1 +CALLBACK: log1 +CALLBACK: log2 +CALLBACK: module4 > afterEach +CALLBACK: module1 > afterEach +CALLBACK: module4 > after +CALLBACK: module1 > after +CALLBACK: testDone1 +CALLBACK: testDone2 +CALLBACK: moduleDone1 +CALLBACK: moduleDone2 +CALLBACK: moduleDone1 +CALLBACK: moduleDone2 +CALLBACK: done1 +CALLBACK: done2`; + + const command = "qunit callbacks.js"; + const execution = await execute( command ); + + assert.equal( execution.stderr, expected ); + assert.equal( execution.code, 0 ); + } ); + + QUnit.test( "callbacks with promises", async assert => { + const expected = `CALLBACK: begin +CALLBACK: begin2 +CALLBACK: moduleStart +CALLBACK: moduleStart +CALLBACK: testStart - test1 +CALLBACK: testDone - test1 +CALLBACK: moduleDone - module1 > nestedModule1 +CALLBACK: testStart - test2 +CALLBACK: testDone - test2 +CALLBACK: moduleStart +CALLBACK: testStart - test3 +CALLBACK: testDone - test3 +CALLBACK: moduleDone - module1 > nestedModule2 +CALLBACK: moduleDone - module1 +CALLBACK: done`; + + const command = "qunit callbacks-promises.js"; + const execution = await execute( command ); + + assert.equal( execution.stderr, expected ); + assert.equal( execution.code, 0 ); + } ); + if ( semver.gte( process.versions.node, "12.0.0" ) ) { QUnit.test( "run ESM test suite with import statement", async assert => { const command = "qunit ../../es2018/esm.mjs"; @@ -395,7 +507,7 @@ QUnit.module( "CLI Main", () => { await execute( "qunit semaphore/nan.js" ); } catch ( e ) { assert.pushResult( { - result: e.stdout.indexOf( "message: Invalid value on test.semaphore" ) > -1, + result: e.stdout.includes( "message: Invalid value on test.semaphore" ), actual: e.stdout + "\n" + e.stderr } ); } diff --git a/test/events.html b/test/events.html deleted file mode 100644 index 479820d0f..000000000 --- a/test/events.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - QUnit Events Test Suite - - - - - -
-
- - diff --git a/test/module-skip.js b/test/module-skip.js index a1bdac489..48954d9d5 100644 --- a/test/module-skip.js +++ b/test/module-skip.js @@ -1,28 +1,16 @@ -var tests = {}; +QUnit.config.reorder = false; -var done = false; +var tests = {}; QUnit.testDone( function( details ) { - if ( done ) { - return; - } - tests[ details.testId ] = { skipped: details.skipped, todo: details.todo }; } ); -QUnit.done( function() { - if ( done ) { - return; - } - - done = true; - - QUnit.test( "Compare stats", function( assert ) { - assert.expect( 1 ); - +QUnit.module( "Parent module", function( hooks ) { + hooks.after( function( assert ) { assert.deepEqual( tests, { "1d56e5b5": { skipped: false, @@ -42,9 +30,7 @@ QUnit.done( function() { } } ); } ); -} ); -QUnit.module( "Parent module", function() { QUnit.module( "A normal module", function() { QUnit.test( "normal test", function( assert ) { assert.true( true, "this test should run" ); @@ -64,4 +50,10 @@ QUnit.module( "Parent module", function() { assert.true( false, "this test should not run" ); } ); } ); + + // We need a test after the above skip, since hooks.after() runs after the + // last non-skipped test, and we want to include events from the skipped test. + QUnit.test( "another test", function( assert ) { + assert.true( true, "this test should run" ); + } ); } ); diff --git a/test/module-todo.js b/test/module-todo.js index 952bfd98a..4c3cad94d 100644 --- a/test/module-todo.js +++ b/test/module-todo.js @@ -1,28 +1,16 @@ -var tests = {}; +QUnit.config.reorder = false; -var done = false; +var tests = {}; QUnit.testDone( function( details ) { - if ( done ) { - return; - } - tests[ details.testId ] = { skipped: details.skipped, todo: details.todo }; } ); -QUnit.done( function() { - if ( done ) { - return; - } - - done = true; - - QUnit.test( "Compare stats", function( assert ) { - assert.expect( 1 ); - +QUnit.module( "parent module", function( hooks ) { + hooks.after( function( assert ) { assert.deepEqual( tests, { "efa6d5f5": { skipped: false, @@ -42,9 +30,7 @@ QUnit.done( function() { } } ); } ); -} ); -QUnit.module( "parent module", function() { QUnit.module( "a normal module", function() { QUnit.test( "normal test", function( assert ) { assert.true( true, "this test should run" ); @@ -64,4 +50,9 @@ QUnit.module( "parent module", function() { assert.true( false, "not implemented yet" ); } ); } ); + + // We need one more test to ensure hooks.after() runs after the above has finished. + QUnit.test( "another test", function( assert ) { + assert.true( true, "this test should run" ); + } ); } );