Skip to content

Commit

Permalink
Behavior of after/afterEach hooks with --bail flag (#3617)
Browse files Browse the repository at this point in the history
* runner.js: delete second end emit

* tests

* documentation

* runner.js

* tests: corrections

closes #3398, closes #3598, closes #3457, closes #3617
  • Loading branch information
juergba authored and boneskull committed Dec 19, 2018
1 parent dac4e92 commit a9f3526
Show file tree
Hide file tree
Showing 11 changed files with 351 additions and 31 deletions.
2 changes: 1 addition & 1 deletion docs/index.md
Expand Up @@ -909,7 +909,7 @@ Enforce a rule that tests must be written in "async" style, meaning each test pr

### `--bail, -b`

Causes Mocha to stop running tests after the first test failure it encounters.
Causes Mocha to stop running tests after the first test failure it encounters. Corresponding `after()` and `afterEach()` hooks are executed for potential cleanup.

`--bail` does *not* imply `--exit`.

Expand Down
8 changes: 3 additions & 5 deletions lib/runner.js
Expand Up @@ -241,16 +241,14 @@ Runner.prototype.fail = function(test, err) {
}

this.emit('fail', test, err);
if (this.suite.bail()) {
this.emit('end');
}
};

/**
* Fail the given `hook` with `err`.
*
* Hook failures work in the following pattern:
* - If bail, then exit
* - If bail, run corresponding `after each` and `after` hooks,
* then exit
* - Failed `before` hook skips all tests in a suite and subsuites,
* but jumps to corresponding `after` hook
* - Failed `before each` hook skips remaining tests in a
Expand Down Expand Up @@ -494,7 +492,7 @@ Runner.prototype.runTests = function(suite, fn) {
function next(err, errSuite) {
// if we bail after first err
if (self.failures && suite._bail) {
return fn();
tests = [];
}

if (self._abort) {
Expand Down
23 changes: 23 additions & 0 deletions test/integration/fixtures/options/bail-async.fixture.js
@@ -0,0 +1,23 @@
'use strict';

describe('suite1', function () {
it('should display this spec', function () {});

it('should only display this error', function (done) {
throw new Error('this should be displayed');
});

it('should not display this error', function (done) {
throw new Error('this should not be displayed');
});
});

describe('suite2', function () {
before(function (done) {
throw new Error('this hook should not be displayed');
});

it('should not display this error', function (done) {
throw new Error('this should not be displayed');
});
});
54 changes: 50 additions & 4 deletions test/integration/fixtures/options/bail-with-after.fixture.js
@@ -1,11 +1,57 @@
'use strict';
var assert = require('assert');

describe('suite1', function () {
it('should only display this error', function () {
throw new Error('this should be displayed');
var runOrder = [];
before('before suite1', function () {
runOrder.push('before suite1');
});
beforeEach('beforeEach suite1', function () {
runOrder.push('beforeEach suite1');
});
it('test suite1', function () {
runOrder.push('test suite1');
});

describe('suite1A', function () {
before('before suite1A', function () {
runOrder.push('before suite1A');
});
beforeEach('beforeEach suite1A', function () {
runOrder.push('beforeEach suite1A');
});
it('test suite1A', function () {
runOrder.push('test suite1A');
});
afterEach('afterEach suite1A', function () {
runOrder.push('afterEach suite1A');
});
after('after suite1A', function () {
runOrder.push('after suite1A');
throw new Error('after suite1A error');
});
});

afterEach('afterEach suite1', function () {
runOrder.push('afterEach suite1');
});
after('after suite1', function () {
runOrder.push('after suite1');
assert.deepStrictEqual(runOrder, [
'before suite1', 'beforeEach suite1', 'test suite1',
'afterEach suite1', 'before suite1A', 'beforeEach suite1',
'beforeEach suite1A', 'test suite1A', 'afterEach suite1A',
'afterEach suite1', 'after suite1A', 'after suite1'
]);
});
});

after(function () {
throw new Error('this hook should not be displayed');
describe('suite2', function () {
before('before suite2', function () {});
beforeEach('beforeEach suite2', function () {});
it('test suite2', function () {
runOrder.push('test suite2 - should not run');
});
afterEach('afterEach suite2', function () {});
after('after suite2', function () {});
});
57 changes: 57 additions & 0 deletions test/integration/fixtures/options/bail-with-afterEach.fixture.js
@@ -0,0 +1,57 @@
'use strict';
var assert = require('assert');

describe('suite1', function () {
var runOrder = [];
before('before suite1', function () {
runOrder.push('before suite1');
});
beforeEach('beforeEach suite1', function () {
runOrder.push('beforeEach suite1');
});
it('test suite1', function () {
runOrder.push('test suite1');
});

describe('suite1A', function () {
before('before suite1A', function () {
runOrder.push('before suite1A');
});
beforeEach('beforeEach suite1A', function () {
runOrder.push('beforeEach suite1A');
});
it('test suite1A', function () {
runOrder.push('test suite1A');
});
afterEach('afterEach suite1A', function () {
runOrder.push('afterEach suite1A');
throw new Error('afterEach suite1A error');
});
after('after suite1A', function () {
runOrder.push('after suite1A');
});
});

afterEach('afterEach suite1', function () {
runOrder.push('afterEach suite1');
});
after('after suite1', function () {
runOrder.push('after suite1');
assert.deepStrictEqual(runOrder, [
'before suite1', 'beforeEach suite1', 'test suite1',
'afterEach suite1', 'before suite1A', 'beforeEach suite1',
'beforeEach suite1A', 'test suite1A', 'afterEach suite1A',
'afterEach suite1', 'after suite1A', 'after suite1'
]);
});
});

describe('suite2', function () {
before('before suite2', function () {});
beforeEach('beforeEach suite2', function () {});
it('test suite2', function () {
runOrder.push('test suite2 - should not run');
});
afterEach('afterEach suite2', function () {});
after('after suite2', function () {});
});
41 changes: 37 additions & 4 deletions test/integration/fixtures/options/bail-with-before.fixture.js
@@ -1,11 +1,44 @@
'use strict';
var assert = require('assert');

describe('suite1', function () {
before(function () {
throw new Error('this hook should be only displayed');
var runOrder = [];
before('before suite1', function () {
runOrder.push('before suite1');
throw new Error('before suite1 error');
});
beforeEach('beforeEach suite1', function () {
runOrder.push('beforeEach suite1 - should not run');
});
it('test suite1', function () {
runOrder.push('test suite1 - should not run');
});

describe('suite1A', function () {
before('before suite1A', function () {});
beforeEach('beforeEach suite1A', function () {});
it('test suite1A', function () {
runOrder.push('test suite1A - should not run');
});
afterEach('afterEach suite1A', function () {});
after('after suite1A', function () {});
});

afterEach('afterEach suite1', function () {
runOrder.push('afterEach suite1 - should not run');
});
after('after suite1', function () {
runOrder.push('after suite1');
assert.deepStrictEqual(runOrder, ['before suite1', 'after suite1']);
});
});

it('should not display this error', function () {
throw new Error('this should not be displayed');
describe('suite2', function () {
before('before suite2', function () {});
beforeEach('beforeEach suite2', function () {});
it('test suite2', function () {
runOrder.push('test suite2 - should not run');
});
afterEach('afterEach suite2', function () {});
after('after suite2', function () {});
});
46 changes: 46 additions & 0 deletions test/integration/fixtures/options/bail-with-beforeEach.fixture.js
@@ -0,0 +1,46 @@
'use strict';
var assert = require('assert');

describe('suite1', function () {
var runOrder = [];
before('before suite1', function () {
runOrder.push('before suite1');
});
beforeEach('beforeEach suite1', function () {
runOrder.push('beforeEach suite1');
throw new Error('beforeEach suite1 error');
});
it('test suite1', function () {
runOrder.push('test suite1 - should not run');
});

describe('suite1A', function () {
before('before suite1A', function () {});
beforeEach('beforeEach suite1A', function () {});
it('test suite1A', function () {
runOrder.push('test suite1A - should not run');
});
afterEach('afterEach suite1A', function () {});
after('after suite1A', function () {});
});

afterEach('afterEach suite1', function () {
runOrder.push('afterEach suite1');
});
after('after suite1', function () {
runOrder.push('after suite1');
assert.deepStrictEqual(runOrder, [
'before suite1', 'beforeEach suite1', 'afterEach suite1', 'after suite1'
]);
});
});

describe('suite2', function () {
before('before suite2', function () {});
beforeEach('beforeEach suite2', function () {});
it('test suite2', function () {
runOrder.push('test suite2 - should not run');
});
afterEach('afterEach suite2', function () {});
after('after suite2', function () {});
});
47 changes: 47 additions & 0 deletions test/integration/fixtures/options/bail-with-test.fixture.js
@@ -0,0 +1,47 @@
'use strict';
var assert = require('assert');

describe('suite1', function () {
var runOrder = [];
before('before suite1', function () {
runOrder.push('before suite1');
});
beforeEach('beforeEach suite1', function () {
runOrder.push('beforeEach suite1');
});
it('test suite1', function () {
runOrder.push('test suite1');
throw new Error('test suite1 error');
});

describe('suite1A', function () {
before('before suite1A', function () {});
beforeEach('beforeEach suite1A', function () {});
it('test suite1A', function () {
runOrder.push('test suite1A - should not run');
});
afterEach('afterEach suite1A', function () {});
after('after suite1A', function () {});
});

afterEach('afterEach suite1', function () {
runOrder.push('afterEach suite1');
});
after('after suite1', function () {
runOrder.push('after suite1');
assert.deepStrictEqual(runOrder, [
'before suite1', 'beforeEach suite1', 'test suite1',
'afterEach suite1', 'after suite1'
]);
});
});

describe('suite2', function () {
before('before suite2', function () {});
beforeEach('beforeEach suite2', function () {});
it('test suite2', function () {
runOrder.push('test suite2 - should not run');
});
afterEach('afterEach suite2', function () {});
after('after suite2', function () {});
});
8 changes: 4 additions & 4 deletions test/integration/fixtures/options/bail.fixture.js
Expand Up @@ -3,21 +3,21 @@
describe('suite1', function () {
it('should display this spec', function () {});

it('should only display this error', function (done) {
it('should only display this error', function () {
throw new Error('this should be displayed');
});

it('should not display this error', function (done) {
it('should not display this error', function () {
throw new Error('this should not be displayed');
});
});

describe('suite2', function () {
before(function (done) {
before(function () {
throw new Error('this hook should not be displayed');
});

it('should not display this error', function (done) {
it('should not display this error', function () {
throw new Error('this should not be displayed');
});
});

0 comments on commit a9f3526

Please sign in to comment.