msw: Request stuck in pending state / promise never resolves
Environment
| Name | Version |
|---|---|
| msw | 0.35.0 |
| node | 14.17.6 |
| OS | codesandbox & ubuntu 20.04 |
Request handlers
// Example of declaration. Provide your code here.
import { setupServer } from 'msw/node'
import { rest } from 'msw'
const server = setupServer()
server.listen({
onUnhandledRequest: "bypass"
})
stripe.customers.update("customer_id", {
name: "stephan",
email: "stephan@example.com"
}).finally(() => {
// you'll never come here
});
Actual request
stripe.customers.update("customer_id", {
name: "stephan",
email: "stephan@example.com"
}).finally(() => {
// you'll never come here
});
Current behavior
Request is made, Stripe shows that there was a successful response, but the promise never resolves.
Expected behavior
Request should resolve
Screenshots
codesandbox
https://codesandbox.io/s/spring-dawn-3cht3?file=/pages/api/stripe.js
terminal
https://user-images.githubusercontent.com/1196524/137531832-6b5fb6c8-e4f5-4c0d-9a2f-f16f1698f48c.mp4
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 2
- Comments: 15 (7 by maintainers)
I’ve implemented the fix in https://github.com/mswjs/interceptors/pull/165 but currently experience a regression in one of the tests. Once it’s resolved, the fix will be merged.
It seems I’ve finally found a way to properly clone the
IncomingMessageby piping it to aPassThroughstream in order to read its “data” twice: for the internal “response” event and for the arbitrary response event listeners that the request client (or developer) may attach.The fix will propagate with the next update of the
@mswjs/interceptorslibrary. We’re currently working on a few bug fixes we’d like to include in that next release. I’d expect it to be released this month.If I understood correctly, this has been fixed in the dependency. Is there an eta on when a new msw will be published?
Root cause
The following
responselistener is the root cause of why the request never resolves:https://github.com/mswjs/interceptors/blob/adc15848cb43e691dacf052792cb386bcad881c3/src/interceptors/ClientRequest/createClientRequestOverride.ts#L293-L300
It reads the
IncomingMessagebody and, once that’s done, any other listeners onres.on('data')will never get that event emitted. Here’s where Stripe attempts to get the response and parse it to JSON:https://github.com/stripe/stripe-node/blob/7dd6c7cf98f8a5fab5d551d70aad4cf2e844d0db/lib/net/NodeHttpClient.js#L107-L122
This entire promise never resolves because the
this._res.once('data')is never called once interceptors extract the response body viagetIncomingMessageBody. In particular, because this function removes all listeners on the response, including those attached by Stripe:https://github.com/mswjs/interceptors/blob/adc15848cb43e691dacf052792cb386bcad881c3/src/interceptors/ClientRequest/utils/getIncomingMessageBody.ts#L22
That’s rather strange, as we clone the incoming message to prevent this very issue from happening.