Add way to detect and log exceptions in request handlers.
See original GitHub issueIs your feature request related to a problem? Please describe.
I’m currently using msw
for mocking network requests in jest
tests. I haven’t found an easy way to detect when exceptions are thrown in my request handlers. For example, the code below will produce an exception due to bug and msw
will silently convert the error to a 500 response.
rest.post("/authorize", (req, res, ctx) => {
// ... some authorization logic ...
// getCurrentUser throws because there is a bug in it
const user = getCurrentUser();
// ... more authorization logic ...
return res(
ctx.status(200),
ctx.json({
redirectUri,
}),
);
});
Describe the solution you’d like
None of the lifecycle events are emitted when the exception is thrown. A new lifecycle event like response:error
would allow me to write something like
worker.on('response:error', (res, reqId, error) => {
console.error("Request handler threw error.", error);
});
This would help developers quickly ascertain the source of some test failures without having to follow a chain of symptoms back to a failed msw
request handler.
Describe alternatives you’ve considered
Alternative 1
I could use a higher order function wrapper like
rest.post("/authorize", logAndRethrowErrors((req, res, ctx) => {
// ...
}));
function logAndRethrowErrors(fn) {
return (...args) => {
try {
return fn(...args);
} catch (e) {
console.error(e);
throw e;
}
};
}
Pros: This code logs an error which likely includes helpful stack trace.
Cons:
This requires all developers on my project to add logAndRethrowErrors
which may be easy to forget. I’d instead prefer to fail loudly globally.
Alternative 2
I could do something like this during setup
// Setup
const server = setupServer(...handlers);
const requestsWithoutResponses = new Map();
server.on("request:start", (req) => {
requestsWithoutResponses.set(req.id, req);
});
server.on("request:end", (req) => {
requestsWithoutResponses.delete(req.id);
});
and this during teardown
// Teardown
server.close();
for (const [, req] of requestsWithoutResponses) {
console.error(
"Request received no response. This likely means the request handler threw an error, the error was swallowed by msw, and silently converted to a 500 response.\nRequest:",
req,
);
}
and assuming any request that did not emit "request:end"
resulted in an exception.
Pros: This gives me the global ability fail loudly.
Cons: Does not have the error message to emit.
Alternative 3
Combine alternative 1 and 2 above.
Pros:
Allows us to emit error trace with logAndRethrowErrors
and use the fallback teardown code to hint that a developer forgot logAndRethrowErrors
.
Cons:
This is quite a few lines of non-standard tooling for something that could be done succinctly if msw
offered a simple API for it.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:3
- Comments:8 (8 by maintainers)
Top GitHub Comments
What about
request:handlerError
instead ofrequest:unhandledException
(because it is not unhandled)handleRequest.tsx
const result = await handler.run(request, resolutionContext)
inuntil
and emitting the error + handler thereUsers are only interested in errors occurring inside their handlers, but not all errors that could occur in
getResponse
Hey, @MartinJaskulla! We’d love to have you involved with this. The issues don’t necessarily have to have a “help wanted” label for anybody to join in! We usually use “help wanted” meaning “we can’t do this on our own”.
It means that this particular issue needs automated tests to be written to verify it. It also means that we don’t have such tests, or the tests we have are insufficient in covering it.
In this particular case, we don’t have any tests because the solution to the issue is to extend an existing life-cycle events API with a new
request:unhandledException
event. Tests should be added for that event.What this task is about
First, we need to extend an existing interface of lifecycle events:
https://github.com/mswjs/msw/blob/6fc89f762681aa7f6f697ea78fa5f7c736b35c5d/src/sharedOptions.ts#L17-L24
I propose to add a new
request:unhandledException
event.Then we need to go to the common ground between
setupWorker
andsetupServer
that handles request and emit the new event whenever exception occurs during request handler:https://github.com/mswjs/msw/blob/6fc89f762681aa7f6f697ea78fa5f7c736b35c5d/src/utils/handleRequest.ts#L67-L72
We can wrap
getResponse
inuntil
and handle the exception like so:And then cover this scenario with tests. We can use existing tests for reference. I can also help you with tests.