In my tests using Supertest and MSW I've noticed that, although they still pass successfully, MSW has started showing warnings for the requests that Supertest is making. For example (see files to reproduce at the end of the post):
$ npm t
> [email protected] test
> jest
PASS ./app.test.js
password API
✓ exposes a number of words (76 ms)
console.warn
[MSW] Warning: captured a request without a matching request handler:
• GET http://127.0.0.1:55984/api
If you still wish to intercept this unhandled request, please create a request handler for it.
Read more: https://mswjs.io/docs/getting-started/mocks
at onUnhandledRequest (node_modules/msw/node/lib/index.js:7599:21)
at node_modules/msw/node/lib/index.js:7630:13
at fulfilled (node_modules/msw/node/lib/index.js:50:58)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.005 s
Ran all test suites.
The request GET http://127.0.0.1:55984/api
is one that Supertest is making to the app, which is the whole point of the test, not one that MSW needs to be handling. These warnings weren't shown when I first wrote the tests, either.
The linked page shows how to create a handler, but I don't want MSW to handle these requests. Why did this start happening, and how can I stop it showing warnings for the "/api"
calls?
package.json
:
{
"name": "msw-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jest"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.21.1",
"express": "^4.17.1"
},
"devDependencies": {
"jest": "^27.0.4",
"msw": "^0.29.0",
"supertest": "^6.1.3"
}
}
app.js
:
const axios = require("axios");
const express = require("express");
const app = express();
app.get("/api", (_, res) => {
axios.get("https://api.pwnedpasswords.com/range/ABC12")
.then(() => res.json({ words: 3 }))
.catch((err) => res.sendStatus(500));
});
module.exports = app;
app.test.js
:
const { rest } = require("msw");
const { setupServer } = require("msw/node");
const request = require("supertest");
const app = require("./app");
const server = setupServer(
rest.get("https://api.pwnedpasswords.com/range/:range", (req, res, ctx) => {
return res(ctx.status(200), ctx.text(""));
}),
);
describe("password API", () => {
beforeAll(() => server.listen());
beforeEach(() => server.resetHandlers());
afterAll(() => server.close());
it("exposes a number of words", () => {
return request(app).get("/api").expect(200).then((res) => {
expect(res.body.words).toBe(3);
});
});
});
This feature was introduced in MSW v0.20.0, but in v0.29.0 the default setting for unhandled requests changed from "bypass"
to "warn"
, hence the warnings suddenly appearing in the console. You can reset it to "bypass"
as shown in the docs for setupWorker#start
or setupServer#listen
, in my case:
beforeAll(() => server.listen({ onUnhandledRequest: "bypass" }));
However, this might mean missing warnings for requests you should be handling, so another option is to pass a function that receives the request object. This could e.g. log a warning or throw an error (which will cause the test to fail). In my case, as all of my Supertest requests were to /api
endpoints, that looked like:
beforeAll(() => server.listen({
onUnhandledRequest: ({ method, url }) => {
if (!url.pathname.startsWith("/api")) {
throw new Error(`Unhandled ${method} request to ${url}`);
}
},
}));
As suggested by kettanaito in the comments, I looked into whether you could identify Supertest calls by their headers. Unfortunately it seems like Supertest no longer sets a default User-Agent
, so you'd have to do this test-by-test:
describe("password API", () => {
beforeAll(() => server.listen({
onUnhandledRequest: ({ headers, method, url }) => {
if (headers.get("User-Agent") !== "supertest") {
throw new Error(`Unhandled ${method} request to ${url}`);
}
},
}));
beforeEach(() => server.resetHandlers());
afterAll(() => server.close());
it("exposes a number of words", () => {
return request(app)
.get("/api")
.set("User-Agent", "supertest")
.expect(200)
.then((res) => {
expect(res.body.words).toBe(3);
});
});
});
From v0.38.0 you can use the second parameter to onUnhandledRequest
, conventionally named print
, to hand control back to MSW in cases you don't want to handle, e.g.:
beforeAll(() => server.listen({
onUnhandledRequest: ({ headers }, print) => {
if (headers.get("User-Agent") === "supertest") {
return;
}
print.error();
},
}));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With