mocha: 🐛 Bug: afterEach halts suite and/or causes simultaneous failure and pass

This is a common pattern with tools like sinon or nock - to have afterEach do some standard verification at the end of each test.

I’m fairly sure this used to work - not sure what’s changed.

var assert = require('assert');

describe("afterEach", function() {
    var verificationFlag;
    beforeEach(function() {
        verificationFlag = 0;
    });
    afterEach(function() {
        assert.equal(verificationFlag, 1);
    });

    it("0", function() { })
    it("1", function() { verificationFlag = 1 })
    it("2", function() { verificationFlag = 2 })
});

Expected output: 3 tests, 3 failures Actual output: 1 test, 1 pass, 1 fail (from hook)

About this issue

  • Original URL
  • State: open
  • Created 9 years ago
  • Reactions: 6
  • Comments: 45 (21 by maintainers)

Most upvoted comments

This is not stale and should be fixed.

@glebec that behaviour (or ‘ugly workaround’) is currently broken, I’m trying to get it fixed in #1944.

I think the right solution should be the one mentioned by @glebec

Currently the whole test suite shutdowns thinking that throwing an error within a hook is a “setup -infrastructure” problem and not a test problem. Otherwise a coding error within a hook would trigger lots of false test errors when actually the test tear -down / -up is broken.

IMHO the solution I would like to see is solving #3345, probably with the pull provided by @jjoos in #1944 and also adding some documentation to the error explaining that this.test.error() should be used if the intention is failing the test, not a test setup exception.

Actually I improved that solution and published it in an npm package: https://github.com/Rush/mocha-finalize-each

Below supports all types of tests: sync, async and promises. It unifies them to use promises so that finalizeEach can have a uniform interface.

var finalizeEach = require('mocha-finalize-each');

describe('some tests', function() {
  var sinonSandbox = sinon.sandbox.create();

  finalizeEach(this, promise => {
    return promise.then(() => {
      // will fail tests if sinon assertions are not satisfied
      sinonSandbox.verifyAndRestore();
    }).finally(() => {
      // clean in all cases
      sinonSandbox.restore();
    });
  });

  it('some test', function() {
     /* ...  some code using sinonSandbox */
  });
});