foobar8675
foobar8675

Reputation: 1315

Throwing mocha exception can make a test pass when it should not

In our mocha tests, sometimes we have bugs and throw exceptions, and when those exceptions are thrown, the subsequent asserts are not called and our tests might pass even though there was something wrong.

  // this would pass
  it('adsf', async () => {
    assert.equal(1,1)
    var foo = undefined;
    foo.hi(); // throw exception
    assert.equal(1,2) // assert not called
  });

We tried wrapping this in a try catch, like the following

  // this would fail, but not say why
  it('adsf', async () => {
    try {
      assert.equal(1,1)
      // var foo = undefined;
      // foo.hi();
      assert.equal(1,2)
    } catch (err) {
      assert.fail(err) // if fail, such as the 1,2 case above, the line number of the error is not shown
    }
  });

but the catch case hides some of the failed assert info. If anyone has any suggestions, it would be appreciated.

Upvotes: 0

Views: 811

Answers (1)

afenster
afenster

Reputation: 3608

The test in your example will not pass. In mocha, the test would fail if the function that is called in a test throws an exception. Example:

const assert = require('assert');

function foo() {
  throw new Error('err');
}

describe('test', () => {
  it('works', async () => {
    foo();
    console.log('came here');
  });
});
$ npx mocha test.js

  test
    1) works

  0 passing (6ms)
  1 failing

  1) test
       works:
     Error: err
      at foo (test.js:8:9)
      at Context.<anonymous> (test.js:13:11)
      at processImmediate (internal/timers.js:439:21)

So, in your example, since foo.hi throws TypeError, it would be caught by mocha and shown as a test failure (the execution won't reach asserts indeed but the test will be shown as failed anyway).

What I suspect happens in your case is throwing in a promise or rejecting a promise, like in one of these examples:

function throwing() {
  return new Promise((resolve, reject) => { throw new Error('err'); });
}

function rejecting() {
  return new Promise((resolve, reject) => { reject(new Error('err')); });
}

describe('test', () => {
  it('works', async () => {
    throwing();
    rejecting();
    console.log('came here');
  });
});
$ npx mocha test.js

  test
came here
    ✓ works

[some UnhandledPromiseRejectionWarnings here]

  1 passing (6ms)

Both will not be caught by a test because the function executes successfully returning a promise and the test block completes, but the failure occurs later. If your function returns a promise, just await for it in your test to make sure you get the promise result:

describe('test', () => {
  it('works', async () => {
    await throwing();
    await rejecting();
    console.log('came here');
  });
});
$ npx mocha test.js 

  test
    1) works

  0 passing (6ms)
  1 failing

  1) test
       works:
     Error: err
      at test.js:4:51
      at new Promise (<anonymous>)
      at throwing (test.js:4:10)
      at Context.<anonymous> (test.js:13:11)
      at processImmediate (internal/timers.js:439:21)

Upvotes: 1

Related Questions