Skip to content

Commit

Permalink
Docs: Designate E0002 to "Cannot add hook" and add examples
Browse files Browse the repository at this point in the history
Ref #1576.
  • Loading branch information
Krinkle committed Jun 8, 2024
1 parent 99a8768 commit fd17b66
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 26 deletions.
80 changes: 56 additions & 24 deletions docs/api/QUnit/module.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,23 +123,21 @@ QUnit.test('basic test example 4', function (assert) {
Using modern syntax:

```js
const { test } = QUnit;

QUnit.module('Group A');

test('basic test example', assert => {
QUnit.test('basic test example', assert => {
assert.true(true, 'this is fine');
});
test('basic test example 2', assert => {
QUnit.test('basic test example 2', assert => {
assert.true(true, 'this is also fine');
});

QUnit.module('Group B');

test('basic test example 3', assert => {
QUnit.test('basic test example 3', assert => {
assert.true(true, 'this is fine');
});
test('basic test example 4', assert => {
QUnit.test('basic test example 4', assert => {
assert.true(true, 'this is also fine');
});
```
Expand All @@ -166,24 +164,22 @@ QUnit.module('module A', {
### Nested module scope

```js
const { test } = QUnit;

QUnit.module('Group A', hooks => {
test('basic test example', assert => {
QUnit.test('basic test example', assert => {
assert.true(true, 'this is fine');
});

test('basic test example 2', assert => {
QUnit.test('basic test example 2', assert => {
assert.true(true, 'this is also fine');
});
});

QUnit.module('Group B', hooks => {
test('basic test example 3', assert => {
QUnit.test('basic test example 3', assert => {
assert.true(true, 'this is fine');
});

test('basic test example 4', assert => {
QUnit.test('basic test example 4', assert => {
assert.true(true, 'this is also fine');
});
});
Expand All @@ -194,8 +190,6 @@ QUnit.module('Group B', hooks => {
Use `before`/`beforeEach` hooks are queued for nested modules. `after`/`afterEach` hooks are stacked on nested modules.

```js
const { test } = QUnit;

QUnit.module('My Group', hooks => {
// It is valid to call the same hook methods more than once.
hooks.beforeEach(assert => {
Expand All @@ -206,7 +200,7 @@ QUnit.module('My Group', hooks => {
assert.ok(true, 'afterEach called');
});

test('with hooks', assert => {
QUnit.test('with hooks', assert => {
// 1 x beforeEach
// 1 x afterEach
assert.expect(2);
Expand All @@ -223,7 +217,7 @@ QUnit.module('My Group', hooks => {
assert.ok(true, 'nested afterEach called');
});

test('with nested hooks', assert => {
QUnit.test('with nested hooks', assert => {
// 2 x beforeEach (parent, current)
// 2 x afterEach (current, parent)
assert.expect(4);
Expand Down Expand Up @@ -261,21 +255,19 @@ The test context is also available when using the nested scope. Beware that use
in arrow functions.

```js
const { test } = QUnit;

QUnit.module('Machine Maker', hooks => {
hooks.beforeEach(function () {
this.maker = new Maker();
this.parts = ['wheels', 'motor', 'chassis'];
});

test('makes a robot', function (assert) {
QUnit.test('makes a robot', function (assert) {
this.parts.push('arduino');
assert.equal(this.maker.build(this.parts), 'robot');
assert.deepEqual(this.maker.log, ['robot']);
});

test('makes a car', function (assert) {
QUnit.test('makes a car', function (assert) {
assert.equal(this.maker.build(this.parts), 'car');
this.maker.duplicate();
assert.deepEqual(this.maker.log, ['car', 'car']);
Expand All @@ -286,8 +278,6 @@ QUnit.module('Machine Maker', hooks => {
It might be more convenient to use JavaScript's own lexical scope instead:

```js
const { test } = QUnit;

QUnit.module('Machine Maker', hooks => {
let maker;
let parts;
Expand All @@ -296,13 +286,13 @@ QUnit.module('Machine Maker', hooks => {
parts = ['wheels', 'motor', 'chassis'];
});

test('makes a robot', assert => {
QUnit.test('makes a robot', assert => {
parts.push('arduino');
assert.equal(maker.build(parts), 'robot');
assert.deepEqual(maker.log, ['robot']);
});

test('makes a car', assert => {
QUnit.test('makes a car', assert => {
assert.equal(maker.build(parts), 'car');
maker.duplicate();
assert.deepEqual(maker.log, ['car', 'car']);
Expand Down Expand Up @@ -436,3 +426,45 @@ QUnit.module.todo('Robot', hooks => {
// ...
});
```

### Error: Cannot add hook outside the containing module {#E0002}

If you encounter this error, it means you have called `hooks.beforeEach()` or `hooks.afterEach()` on the "hooks" parameter of a module outside the current module scope. Detection of this issue was [introduced](https://github.com/qunitjs/qunit/issues/1576) in QUnit 3.0.

```
Error: Cannot add beforeEach hook outside the containing module.
```
```
Error: Cannot add afterEach hook outside the containing module.
Called on "X", instead of expected "Y".
```

This can happen if you create a nested module and forget to specify the `hooks` parameter on the inner scope:

```js
QUnit.module('MyGroup', (hooks) => {
QUnit.module('Child', () => {
// ^ Oops, forgot "hooks" here!

hooks.beforeEach(() => {
// ...
});

QUnit.test('example');
});
});
```

Another way that this might happen is if you have named them differently, or perhaps mispelled one, and are referring to the outer parameter from the inner module. Is is recommended to name hooks parameters the same, as this will naturally refer to the correct and closest one always, thus avoiding any mistake.

```js
QUnit.module('MyGroup', (hooksOuter) => {
QUnit.module('Child', (hooksInner) => {
hooksOuter.beforeEach(() => {
// Oops, used "hooksOuter" instead of "hooksInner"!
});

QUnit.test('example');
});
});
```
2 changes: 1 addition & 1 deletion src/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function setHookFromEnvironment (hooks, environment, name) {
function makeSetHook (module, hookName) {
return function setHook (callback) {
if (config.currentModule !== module) {
throw new Error(`Cannot add ${hookName} hook outside the containing module. Called on "${module.name}", instead of expected "${config.currentModule.name}"`);
throw new Error(`Cannot add ${hookName} hook outside the containing module. Called on "${module.name}", instead of expected "${config.currentModule.name}". https://qunitjs.com/api/QUnit/module/#E0002`);
}
module.hooks[hookName].push(callback);
};
Expand Down
2 changes: 1 addition & 1 deletion test/main/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ QUnit.module('QUnit.module', function () {

QUnit.test('create hook on parent module', function (assert) {
assert.strictEqual(beforeEachErrorMessage,
'Cannot add beforeEach hook outside the containing module. Called on "QUnit.module > improper hook creation", instead of expected "QUnit.module > improper hook creation > child"',
'Cannot add beforeEach hook outside the containing module. Called on "QUnit.module > improper hook creation", instead of expected "QUnit.module > improper hook creation > child". https://qunitjs.com/api/QUnit/module/#E0002',
'beforeEachErrorMessage'
);
assert.false(outerHookRan, 'outerHookRan');
Expand Down

0 comments on commit fd17b66

Please sign in to comment.