msw: TypeError: performance.markResourceTiming is not a function
Prerequisites
- I confirm my issue is not in the opened issues
- I confirm the Frequently Asked Questions didn’t contain the answer to my issue
Environment check
- I’m using the latest
msw
version - I’m using Node.js version 18 or higher
Node.js version
20.9.0
Reproduction steps
- Follow the 1.x -> 2.x migration steps
- Create a jest.polyfills.js file to work around #1796 (docs)
- Install undici as instructed (currently v5.27.2)
- Set the undici global origin to work around #1625 (example)
Current behavior
undici will throw an error: TypeError: performance.markResourceTiming is not a function
. I’m guessing this is because performance.markResourceTiming
is not a browser API, but the jest.polyfills.js file replaces fetch with undici
which attempts to call this Node API here.
Expected behavior
fetch should work
I worked around the issue by adding performance
to my jest.polyfills.js.
/* global globalThis */
/**
* @note The block below contains polyfills for Node.js globals
* required for Jest to function when running JSDOM tests.
* These HAVE to be require's and HAVE to be in this exact
* order, since "undici" depends on the "TextEncoder" global API.
*
* Consider migrating to a more modern test runner if
* you don't want to deal with this.
*/
const { performance } = require('node:perf_hooks')
const { TextDecoder, TextEncoder } = require('node:util')
Object.defineProperties(globalThis, {
TextDecoder: { value: TextDecoder },
TextEncoder: { value: TextEncoder },
performance: { value: performance },
})
const { Blob } = require('node:buffer')
const { fetch, Headers, FormData, Request, Response } = require('undici')
Object.defineProperties(globalThis, {
fetch: { value: fetch, writable: true },
Blob: { value: Blob },
Headers: { value: Headers },
FormData: { value: FormData },
Request: { value: Request },
Response: { value: Response },
})
Apologies for not creating a reproduction repository. Hopefully this is the correct workaround and it helps someone.
About this issue
- Original URL
- State: closed
- Created 8 months ago
- Reactions: 1
- Comments: 18 (7 by maintainers)
@samanthaburboz Here’s what my jest.polyfills.js looks like. I think
performance
andclearImmediate
need to be imported and added toglobalThis
beforeundici
is imported.Yeah, if the assumption is correct—that undici is trying to use missing globals in JSDom—then I’m wondering:
@kettanaito what do you think?
It’s possible that something is wrong with my setup, but logging
process.version
during the test setup gives me v20.9.0I’ll see if I can put together a minimal reproduction at some point. It’s a little tough because our app is an ejected create-react-app that has been modified a fair bit.
Yes I think this is the core issue, not the lack of Node v18 support in RTL (that might be a separate issue, but I don’t think it’s the one I’m hitting in this ticket).
In my test I’m attempting to use the Clipboard API that RTL stubs out:
Which throws this error from the
convert()
function in JSDomHere is the
convert()
function in JSDom’s Blob.js.If I console.log the steps from
is()
then it shows that we are failing the second and third steps where it checks for the existence of a Symbol on the BlobMy guess is that when we replace JSDom’s Blob with Node’s Blob in jest.polyfills.js, it allows for the creation of Blobs that are missing a Symbol that JSDom normally attaches to them. When code tries to interact with the Blob in JSDom, it fails this identity check.
If I remove Blob from my jest.polyfills.js then the test passes. I suspect this happens because I’m not yet using any part of undici that depends on a Node-specific version of Blob.
I’m really curious to see how Vitest works around this? I’m going to try to recreate the issue with RTL in a Vitest app to see if everything “just works”.
I’m starting to think this might be a bigger issue and this polyfills file might make msw incompatible with Jest and libraries designed to work with Jest.
Here are some examples from our tests that I don’t know how to work around:
If I comment out the polyfills then all of the above issues go away and the tests pass again.
edit:
Maybe a possible fix for the clearImmediate issue would be to make it writeable?
But i’m not sure how to work around the other issues with FormData and Blob
interesting! definitely looks like that 404 / clearImmediate relates to node apis that jsdom doesn’t implement.
The issue of “node” and “jsdom” implementations and how they kind of leak between eachother is…fun
It looks like we are using
"jest-environment-jsdom": "^29.7.0"
and we havetestEnvironment: 'jest-environment-jsdom',
set in our jest config.jest-environment-jsdom v29.7.0 uses jsdom v20
jsdom v20.0.0 does have the
performance
object defined on window, but it does not implementmarkResourceTiming
. Neither does the current version of jsdom.I think
markResourceTiming
is a Node API, not a browser API, so it would make sense that jsdom would not implement it.In jest.polyfills.js we set
fetch
to be undici’s version but I’m a little confused as to where undici is looking when it tries to accessperformance.markResourceTiming
— is it trying to access the performance object defined in jsdom or Node itself?Hi, @robdodson. This error implies you are running a version of Node.js older than 18.2.0 (see this). Please upgrade your Node.js version and that will fix the issue.