0

I'm testing a function using Chai's expect ... not.to.throw pattern (v4.3.4):

describe('parseInt', () => {
  it('does not throw TypeError', () => {
    // foo is not defined, so a ReferenceError is thrown... somewhere?
    expect(() => parseInt(foo)).not.to.throw(TypeError);
  });
});

The closure throws an error, but I don't see this error anywhere in the output (running mocha). The test passes without the slightest indication of the problem inside the closure.

I expect to at least see the error in the console, even if the tests pass.

This answer says that such errors must be run like so:

// wrapping describe/it are elided
try {
  expect(() => parseInt(foo)).not.to.throw(TypeError);
} catch (e) {
  expect(e).to.be.a(ReferenceError); // should PASS, and does
}

This passes, but doesn't appear to be testing the second condition. I can flip it and the test still passes:

// wrapping describe/it are elided
try {
  expect(() => parseInt(foo)).not.to.throw(TypeError);
} catch (e) {
  expect(e).not.to.be.a(ReferenceError); // should FAIL, but does not
}

What am I missing?

Rich Apodaca
  • 28,316
  • 16
  • 103
  • 129

1 Answers1

0

Edit

I think the behavior you are observing is actually expected. The original post you referenced may be misleading.

Consider the following test:

// describe/it wrappers have been redacted
expect(()=>parseInt(foo)).to.not.throw(TypeError)

Should this test pass or fail? Intuitively it should pass since the assertion is met: a TypeError was not thrown.

Again for the following test, should 'hello there' be logged to the console?

// describe/it wrappers have been redacted
try {
  expect(() => parseInt(foo)).to.not.throw(TypeError);
} catch (e) {
  console.log('hello there')
}
  • If yes, then the statement expect(() => parseInt(foo)).to.not.throw(TypeError), must throw.
  • And for it to throw, the assertion - not throw a TypeError - must not be met, but we have already established that the assertion is met, and so no exception is thrown.
  • Therefore, all code in the catch block is unreachable.

This is why the second assertion in your original example is never executed. It will only be reached if the code somehow threw a TypeError and caused the assertion to fail.

Possible solution

For the approach you are taking, I think it could work if there was a way to tell mocha/chai to still go ahead and propagate the error that is thrown by the target function even if the assertion is met. I am unsure of if there is a way to do this, though.

Alternative approach

Alternatively, I think you can get the same (or similar) outcome for the test you have in mind by doing this instead:

// describe/it wrappers have been redacted
const myFunc = () => parseInt(foo)
expect(myFunc).to.not.throw(TypeError)
expect(myFunc).to.throw(ReferenceError)

Here are the assumptions underlying the above test:

  • You are expecting an error
  • The error should under no circumstances be a TypeError
  • The error thrown should always be a ReferenceError.

In case these assumptions do not match what you are currently testing for, or if my alternate approach does not satisfy your needs, kindly let me know!

PS, I used mocha: "^9.1.0" and chai: "^4.3.4" for these tests.

rexess
  • 729
  • 4
  • 7
  • I wasn't being clear that these tests were run in the context of a Mocha/Chai setup, so there is wrapping context that wasn't shown. I updated the question to reflect this. – Rich Apodaca Aug 25 '21 at 22:23
  • Gotcha! I tested things out again within a mocha context and I think I see what the issue is. I will update my answer. – rexess Aug 25 '21 at 23:48