Skip to content

Commit

Permalink
Ensure root level hooks are called when running in watch mode
Browse files Browse the repository at this point in the history
## Rationale
Tests with root level hooks are ignored when running in watch mode.
This occurs on initial & subsequent runs.

## Changes

- extended `suite.clone` to clone hooks

This change was necessary to ensure that when a suite is cloned during
the setup phase for watch that hooks are available on the newly cloned
suite.

Note the use of `suite.clone` appears to be only used in
`lib/cli/run-watch`. I did consider making the cloning of hooks
optional but opted not to as `suite.clone` is internal to `mocha` & not
publicly referenced in the API documentation.

Tests for `suite.clone` have been amended to reflect the above change.

- Extended integration tests for watch to take into consideration
  hooks

## Refs

- /issues/4347
  • Loading branch information
indieisaconcept committed Jul 26, 2020
1 parent 02bdb6b commit c4db914
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 8 deletions.
7 changes: 7 additions & 0 deletions lib/suite.js
Expand Up @@ -119,6 +119,13 @@ Suite.prototype.clone = function() {
debug('clone');
suite.ctx = this.ctx;
suite.root = this.root;

// Required to ensure hooks are available during watch
suite._beforeEach = this._beforeEach;
suite._afterEach = this._afterEach;
suite._beforeAll = this._beforeAll;
suite._afterAll = this._afterAll;

suite.timeout(this.timeout());
suite.retries(this.retries());
suite.slow(this.slow());
Expand Down
7 changes: 7 additions & 0 deletions test/integration/fixtures/options/watch/hook.fixture.js
@@ -0,0 +1,7 @@
module.exports = {
mochaHooks: {
["<hook>"]: function() {
throw new Error("<hook> Hook Error");
},
},
};
37 changes: 37 additions & 0 deletions test/integration/options/watch.spec.js
Expand Up @@ -275,6 +275,43 @@ describe('--watch', function() {
expect(results[1].tests, 'to have length', 2);
});
});

describe('with required hooks', function() {
/**
* Helper for setting up hook tests
*
* @param {string} hookName name of hook to test
* @return {function}
*/
function setupHookTest(hookName) {
return function() {
const testFile = path.join(tempDir, 'test.js');
const hookFile = path.join(tempDir, 'hook.js');

copyFixture('__default__', testFile);
copyFixture('options/watch/hook', hookFile);

replaceFileContents(hookFile, '<hook>', hookName);

return runMochaWatch(
[testFile, '--require', hookFile],
tempDir,
() => {
touchFile(testFile);
}
).then(results => {
expect(results.length, 'to equal', 2);
expect(results[0].failures, 'to have length', 1);
expect(results[1].failures, 'to have length', 1);
});
};
}

it('mochaHooks.beforeAll runs as expected', setupHookTest('beforeAll'));
it('mochaHooks.beforeEach runs as expected', setupHookTest('beforeEach'));
it('mochaHooks.afterAll runs as expected', setupHookTest('afterAll'));
it('mochaHooks.afterEaxch runs as expected', setupHookTest('afterEach'));
});
});
});

Expand Down
16 changes: 8 additions & 8 deletions test/unit/suite.spec.js
Expand Up @@ -54,20 +54,20 @@ describe('Suite', function() {
expect(this.suite.clone().tests, 'to be empty');
});

it('should not copy the values from the _beforeEach array', function() {
expect(this.suite.clone()._beforeEach, 'to be empty');
it('should copy the values from the _beforeEach array', function() {
expect(this.suite.clone()._beforeEach, 'to equal', [2]);
});

it('should not copy the values from the _beforeAll array', function() {
expect(this.suite.clone()._beforeAll, 'to be empty');
it('should copy the values from the _beforeAll array', function() {
expect(this.suite.clone()._beforeAll, 'to equal', [3]);
});

it('should not copy the values from the _afterEach array', function() {
expect(this.suite.clone()._afterEach, 'to be empty');
it('should copy the values from the _afterEach array', function() {
expect(this.suite.clone()._afterEach, 'to equal', [4]);
});

it('should not copy the values from the _afterAll array', function() {
expect(this.suite.clone()._afterAll, 'to be empty');
it('should copy the values from the _afterAll array', function() {
expect(this.suite.clone()._afterAll, 'to equal', [5]);
});

it('should copy the root property', function() {
Expand Down

0 comments on commit c4db914

Please sign in to comment.