Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSW + Jest: Transferring of ReadableStream cannot be properly polyfilled in this engine #1931

Closed
4 tasks done
Samflyn opened this issue Dec 15, 2023 · 8 comments
Closed
4 tasks done
Labels
bug Something isn't working needs:triage Issues that have not been investigated yet. scope:node Related to MSW running in Node

Comments

@Samflyn
Copy link

Samflyn commented Dec 15, 2023

Prerequisites

Environment check

  • I'm using the latest msw version
  • I'm using Node.js version 18 or higher

Node.js version

v21.4.0

Reproduction repository

https://github.com/Samflyn/msw-react

Reproduction steps

Running the App test should replicate the issue

Current behavior

There are two requests in App, where in one with payload and the other without, the request with payload is not intercepted by msw handler while the one without payload is intercepted fine.

Expected behavior

The request with payload should be intercepted by msw handler

@Samflyn Samflyn added bug Something isn't working needs:triage Issues that have not been investigated yet. scope:node Related to MSW running in Node labels Dec 15, 2023
@chawax
Copy link

chawax commented Dec 18, 2023

It looks like the problem I have too : #1915

@kettanaito
Copy link
Member

Hi. Thanks for reporting this. @chawax, thanks for the extensive discussion. Let's get to the bottom of this.

Root cause

First, let's see why the request fails. If we inspect the actual error preserved by Undici, we see this:

    DataCloneError: Transferring of ReadableStream cannot be properly polyfilled in this engine
        at throwUnpolyfillable (/msw-request-with-body-ignored/node_modules/core-js/modules/web.structured-clone.js:120:9)
        at tryToTransfer (/msw-request-with-body-ignored/node_modules/core-js/modules/web.structured-clone.js:485:9)
        at structuredClone (/msw-request-with-body-ignored/node_modules/core-js/modules/web.structured-clone.js:520:17)
        at cloneBody (/msw-request-with-body-ignored/node_modules/undici/lib/fetch/body.js:277:21)

This hints that Jest is having serious trouble with ReadableStream.

This error is caused by core-js. One of our community members shared that removing core-js solved this error for them: mswjs/interceptors#475 (comment).

To be more specific, this is what happens:

  1. undici tries to clone the response body using the standard structuredClone function. This is a global function in Node.js that can clone ReadableStream just fine.
// node_modules/undici/lib/fetch/body.js:277:21
const out2Clone = structuredClone(out2, { transfer: [out2] })
  1. But, since we are using Jest, we need to rely on core-js to polyfill structuredClone. The structuredClone from core-js just throws if the data it tries to transfer is ReadableStream, claiming it as unpolyfillable:
// node_modules/core-js/modules/web.structured-clone.js:485:9
switch (type) {
  ...
  case 'MediaSourceHandle':
  case 'MessagePort':
  case 'OffscreenCanvas':
  case 'ReadableStream':
  case 'TransformStream':
  case 'WritableStream':
    throwUnpolyfillable(type, TRANSFERRING);
}

This is a bold statement, especially since we polyfill ReadableStream in jest.polyfills.js. But core-js never checks for that, just assumes a no-op and throws.

The solution seems to be, once again, force Jest to use the platform, to use Node.js where things function correctly.

@kettanaito
Copy link
Member

Jest depends on core-js, there's nothing we can do about that. Node.js doesn't provide the means to directly import structuredClone, it's set directly on the internal messaging binding in C++. No way to suggest require('node:???').structuredClone to "polyfill" it in jest.polyfills.js.

There's literally nothing I can do here. Jest doesn't respect your environment. I highly recommend you migrate away from Jest to tools like Vitest and forget about these sorts of errors. I know it's not ideal, I know migrations take time, but it's either one-time migration or lifetime of dealing with this shenanigans that nobody but Jest can properly address.

@kettanaito kettanaito changed the title MSW does not intercept requests with payload MSW + Jest: Transferring of ReadableStream cannot be properly polyfilled in this engine Jan 13, 2024
@kettanaito
Copy link
Member

Some folks are having success by downgrading undici to v5: #1934 (reply in thread). This may be a temporary option for those who cannot migrate to other testing frameworks as of now.

@chawax
Copy link

chawax commented Jan 15, 2024

Yes, migrating to Vitest is definitely the only long term solution

@kettanaito
Copy link
Member

Also a note of warning: this seems to be specific to JSDOM. ReadableStream and other Node.js globals work fine in Jest's node environment. But since jest-environment-jsdom isn't based on jest-environment-node, you don't get that. You can try swapping it with HappyDOM to see if they respect the Node.js globals better.

@chawax
Copy link

chawax commented Jan 15, 2024

Well, I was using HappyDOM in my project, and it looks like that was the reason why downgrading Undici didn't work for me. Using Jest Environement JSDom solved instead of HappyDOM solved my problem indeed.

@kettanaito
Copy link
Member

Related.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs:triage Issues that have not been investigated yet. scope:node Related to MSW running in Node
Projects
None yet
Development

No branches or pull requests

3 participants