Error thrown from assertion function is being swallowed?
colincollerlever opened this issue · comments
I'm trying to write an assertion function per the documentation but the Error
that I'm throwing from the assertion function is being swallowed.
Here's an extremely simple repo:
import * as supertest from 'supertest';
describe('An extremely simple test case', () => {
const request: supertest.SuperTest<supertest.Test> = global.__REQUEST__;
it("should fail", async () => {
await request.get('/some/path').expect(() => {
console.log(
"This function gets called...",
);
throw new Error("...but it doesn't fail the test!"); // <- This Error gets swallowed!
});
});
});
When I run the test, the assertion function is called, but the Error
is swallowed, and the test passes:
PASS test/e2e/specs/test.spec.ts
● Console
console.log
This function gets called...
at specs/test.spec.ts:8:15
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
This is with Node 14.20.0, Typescript 4.7.4 (targeting ES2017), Jest 28.1.3, and Supertest 6.1.3.
The only difference that I can see between what I'm doing and what it shows in the documentation is that the documentation is explicitly calling .end(cb)
, while I'm using async/await and so don't have a callback.
Walking through the code in the debugger, it looks like the err
caught by wrapAssertFn()
's inner function isn't an instanceof Error
:
function wrapAssertFn(assertFn) {
const savedStack = new Error().stack.split('\n').slice(3);
return function(res) {
let badStack;
let err;
try {
err = assertFn(res);
} catch (e) {
err = e;
}
if (err instanceof Error && err.stack) { <-- `err instanceof Error` evaluates to false here
and so the return value in _assertFunction()
isn't an Error
_assertFunction(fn, res) {
let err;
try {
err = fn(res);
} catch (e) {
err = e;
}
if (err instanceof Error) return err; <-- `err instanceof Error` evaluates to false here as well
}
and so errorObj
never gets set in assert()
...
// asserts
for (let i = 0; i < this._asserts.length && !errorObj; i += 1) {
errorObj = this._assertFunction(this._asserts[i], res);
}
// set unexpected superagent error if no other error has occurred.
if (!errorObj && resError instanceof Error && (!res || resError.status !== res.status)) {
errorObj = resError;
}
fn.call(this, errorObj || null, res);
}
but at the moment I have no idea why it wouldn't be instanceof Error
. 😞
I figured it out.
I'm setting up the SuperTest request via Jest's globalSetup
. Jest runs the global setup in a different context than the tests. This means the SuperTest request is set up in a different context than the tests. When the test code throws an Error
, and the SuperTest request catches it and checks whether it's instanceof Error
, SuperTest is comparing 2 different Error
types from the 2 different contexts. The comparison evaluates to false
, which causes the error to be swallowed, and the test not to fail.