If I get a wrong status code back from a controller, it'd be nice if supertest had an optional 'print response body on failure' mode so I can see the content of the message associated with that wrong status code. Currently you have to go in and manually add additional debugging into like: .expect(200, function() { console.log(arguments); done(); }) every time a test starts failing.
Another option might be to be smarter about generating the Error response in supertest, e.g. parsing the res.body and (optionally) jamming that into the error message. It could even somehow do some specialcase handling of the default connect error handler to populate the stack trace (if that's even possible).
hmm touch call it's already reasonably long with expected 404 "Not Found", got 200 "OK" tacking on the potentially huge response body might suck
It would be opt-in. Basically, when debugging an error I want a clean way to see the associated error information without having to mess around adding console.logs in the test callback. Another idea would be to optionally pop open a web browser at the current url. These features would be useful to me, perhaps I need to start simply making addons to your modules instead of diluting the core.
meh. just console.log.
I like this idea. How can I console.log when an .expect(200) fails?
+1
+1. Some default option to enable failed requests logging would be very helpful
+1 please!!
+1. Or can someone show us how to console.log when .expect(statusCode) fails?
+1
I need this constantly. It's especially bad when a test seems to only fail sometimes. And the fact that there are no stack traces; what do you do when you test two endpoints that both should respond with 200 and your test fails? Which one is it?
If anyone stumbles upon this and wonders how to log at all. Appending this to your test case logs if an error occurs and rethrows the error via done.
.end((err, res) => {
if (err) {
console.error(res.error);
}
done(err);
});
What if I'm using promises? Putting something like this in the catch block only gives me the generic error that isn't helpful. I can't call .end when using promises.
If anyone is still looking for a way to do this with Promises here's how I did it. According to the readme, "Expectations are run in the order of definition.", so I just created an expection before the expect(statusCode) that checks if the res is the correct statusCode, and if not prints out the body.
For example:
request(server)
.get(endpoint)
.query(query)
.set('Accept', 'application/json; charsaet=utf-8')
.expect(function(res) {
if(res.status != statusCode){
console.log(JSON.stringify(res.body, null, 2));
}
})
.expect(statusCode);
I was looking for a solution to the same problem, and ended up making a VS Code snippet that would insert the following one-liner in my chain, for status code 204, as an example:
.expect((res) => (res.status != 204 ? console.log(res.body) : 0))
Similar to @strujillojr's suggestion. My response body is already a JSON payload.
If you want something reusable and are using typescript, this what I did which is inspired by C# extension methods:
import supertest from 'supertest';
(supertest as any).Test.prototype.expectOrPrint = function (
this: supertest.Test,
statusCode: number
) {
this.expect((res) => {
if (res.status !== statusCode) {
console.error(JSON.stringify(res.body, null, 2));
}
});
this.expect(statusCode);
return this;
};
declare module 'supertest' {
interface Test {
expectOrPrint: (statusCode: number) => Test;
}
}
and then you can use it like this:
await request
.post('/api/v1/graphql')
.send({
query: `{
contacts(
first: 1
) {
id, firstName
}
}`,
})
.expectOrPrint(401);
Actually, one problem with that solution (and previous solutions mentioned) is that the response body is not printed along-side the expect failure. Depending on how many tests there are and/or how many of those are failing, it's quite difficult to find the corresponding response body. I made the following modification which essentially replaces expect:
import supertest from 'supertest';
import status from 'statuses';
(supertest as any).Test.prototype.expect = function (
this: supertest.Test,
statusCode: number
) {
this.then((res) => {
if (res.status !== statusCode) {
let message = `expected ${statusCode} "${status(statusCode)}", got ${res.status} "${status(res.status)}"
response: ${JSON.stringify(res.body, null, 2)}`;
throw message;
}
});
return this;
};
With this, doing a normal .expect(402) would print out something like the following:

Solution by @rhyek doesn't seem to work for me. All tests will pass even if status codes do not match, it will cause some unhandled promise rejection errors though. Modified to following:
import supertest from 'supertest';
import status from 'statuses';
(supertest as any).Test.prototype.expect = function (
this: supertest.Test,
statusCode: number
) {
return this.then((res) => {
if (res.status !== statusCode) {
const message = `expected ${statusCode} "${status(statusCode)}", got ${res.status} "${status(res.status)}"
response: ${JSON.stringify(res.body, null, 2)}`;
throw message;
}
return this;
});
};
I found the above solutions limiting in terms of allowing chained expect calls, so I found an alternative that alters the assert method on the prototype instead.
import supertest from 'supertest';
declare module 'supertest' {
interface Test {
_assert(this: supertest.Test, resError: Error, res: supertest.Response, fn: Function)
}
}
Object.defineProperties((supertest as any).Test.prototype, {
'_assert': {
value: (supertest as any).Test.prototype.assert,
},
'assert': {
value: function (this: supertest.Test, resError, res, fn) {
this._assert(resError, res, (err, res) => {
if (err) {
err.message = `${err.message}\nstatus: ${res.status}\nresponse: ${JSON.stringify(res.body, null, 2)}`;
}
fn.call(this, err, res);
});
}
}
});
This approach has the advantages of:
expect calls).expect assertion logic.This results in error messages such as the following, which is output from a test that failed a response body checker.
Error: expect(received).toInclude(expected)
Expected string to include:
"GraphQL is stopping"
Received:
"GraphQL is running development server."
status: 200
response: {
"data": {
"hello": "GraphQL is running development server."
}
}
All-in-all, I'd still love some ability to configure supertest to allow for automatic response printing on error.
Most helpful comment
If anyone stumbles upon this and wonders how to log at all. Appending this to your test case logs if an error occurs and rethrows the error via done.