diff --git a/src/module.js b/src/module.js index daef48131..c7d747534 100644 --- a/src/module.js +++ b/src/module.js @@ -83,7 +83,14 @@ function processModule( name, options, executeNow, modifiers = {} ) { if ( objectType( executeNow ) === "function" ) { moduleStack.push( module ); config.currentModule = module; - executeNow.call( module.testEnvironment, moduleFns ); + + const cbReturnValue = executeNow.call( module.testEnvironment, moduleFns ); + if ( cbReturnValue != null && objectType( cbReturnValue.then ) === "function" ) { + Logger.warn( "Returning a promise from a module callback is not supported. " + + "Instead, use hooks for async behavior. " + + "This will become an error in QUnit 3.0." ); + } + moduleStack.pop(); module = module.parentModule || currentModule; } diff --git a/test/cli/fixtures/async-module-warning/promise-test.js b/test/cli/fixtures/async-module-warning/promise-test.js new file mode 100644 index 000000000..9474de11b --- /dev/null +++ b/test/cli/fixtures/async-module-warning/promise-test.js @@ -0,0 +1,6 @@ +QUnit.module( "module manually returning a promise", function() { + QUnit.test( "has a test", function( assert ) { + assert.true( true ); + } ); + return Promise.resolve( 1 ); +} ); diff --git a/test/cli/fixtures/async-module-warning/test.js b/test/cli/fixtures/async-module-warning/test.js new file mode 100644 index 000000000..e28ae64d3 --- /dev/null +++ b/test/cli/fixtures/async-module-warning/test.js @@ -0,0 +1,10 @@ +// eslint-disable-next-line qunit/no-async-module-callbacks +QUnit.module( "module with async callback", async function() { + await Promise.resolve( 1 ); + + QUnit.test( "has a test", function( assert ) { + assert.true( true ); + } ); +} ); + +QUnit.module( "resulting parent module" ); diff --git a/test/cli/fixtures/expected/tap-outputs.js b/test/cli/fixtures/expected/tap-outputs.js index a019afbc0..97a4024d7 100644 --- a/test/cli/fixtures/expected/tap-outputs.js +++ b/test/cli/fixtures/expected/tap-outputs.js @@ -339,6 +339,24 @@ ok 1 module providing hooks > module not providing hooks > has a test # pass 1 # skip 0 # todo 0 +# fail 0`, + + "qunit async-module-warning/test.js": +`TAP version 13 +ok 1 resulting parent module > has a test +1..1 +# pass 1 +# skip 0 +# todo 0 +# fail 0`, + + "qunit async-module-warning/promise-test.js": +`TAP version 13 +ok 1 module manually returning a promise > has a test +1..1 +# pass 1 +# skip 0 +# todo 0 # fail 0`, "qunit config-module.js": diff --git a/test/cli/main.js b/test/cli/main.js index 47ece5c3b..2c5be859c 100644 --- a/test/cli/main.js +++ b/test/cli/main.js @@ -498,6 +498,24 @@ QUnit.module( "CLI Main", () => { assert.equal( execution.stdout, expectedOutput[ command ] ); } ); + QUnit.test( "warns about unsupported async module callback", async assert => { + const command = "qunit async-module-warning/test.js"; + const execution = await execute( command ); + + assert.equal( execution.code, 0 ); + assert.equal( execution.stderr, "Returning a promise from a module callback is not supported. Instead, use hooks for async behavior. This will become an error in QUnit 3.0.", "The warning shows" ); + assert.equal( execution.stdout, expectedOutput[ command ] ); + } ); + + QUnit.test( "warns about unsupported promise return value from module", async assert => { + const command = "qunit async-module-warning/promise-test.js"; + const execution = await execute( command ); + + assert.equal( execution.code, 0 ); + assert.equal( execution.stderr, "Returning a promise from a module callback is not supported. Instead, use hooks for async behavior. This will become an error in QUnit 3.0.", "The warning shows" ); + assert.equal( execution.stdout, expectedOutput[ command ] ); + } ); + QUnit.module( "assert.expect failing conditions", () => { QUnit.test( "mismatched expected assertions", async assert => { const command = "qunit assert-expect/failing-expect.js";