I'm trying to test a new release of an internal component library, which recently upgraded some dependencies and now uses Jest 26 internally. That library also exports some testing helpers.
In another codebase that utilizes the aforementioned component library, I'm getting the following when running certain unit tests:
TypeError: MutationObserver is not a constructor
at /<path_to_repo>/node_modules/@testing-library/dom/dist/wait-for.js:78:18
This may or may not be related to the fact that the testing helpers exported by the component library relied on Jest 26. (It's hard to tell if these helpers are being used -- we've got some very big "unit" tests.)
Relevant package versions (in the consuming codebase):
Running yarn list jsdom
yields the following:
├─ jest-environment-jsdom-fourteen@1.0.1
│ └─ jsdom@14.1.0
├─ jest-environment-jsdom@24.9.0
│ └─ jsdom@11.12.0
└─ jsdom@16.4.0
I know that upgrading react-scripts
and Jest would likely fix this issue, but I'm trying to find a way that doesn't involve that. (We ideally don't want this to be a prerequisite for upgrading to our new component library version.)
jsdom
First I tried adding
"resolutions": {
"jsdom": "^14.0.0"
},
to my package.json
. This did make yarn list jsdom
output only jsdom@14.1.0
, but I still got the same TypeError
. Resolving to ^15.0.0
resulted in the same error, and resolving to ^16.0.0
gave me the following error:
TypeError: this.dom.runVMScript is not a function
at JSDOMEnvironment.runScript (node_modules/jest-environment-jsdom/build/index.js:187:23)
jest-environment-jsdom-*
I tried following this thread by installing jest-environment-jsom-sixteen
. Altering my test
script in package.json
and running yarn test --showConfig
yields a bunch of info including the following line:
"testEnvironment": "/<path_to_repo>/node_modules/jest-environment-jsdom-sixteen/lib/index.js",
If I add a console.log(navigator.userAgent)
to my test, I also get
Mozilla/5.0 (darwin) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/16.4.0
However, I still get the same TypeError: MutationObserver is not a constructor
.
I also tried jest-environment-jsdom-fourteen
and jest-environment-jsdom-fifteen
, and tried while forcing jsdom
to ^14.0.0
. Same result.
mutationobserver-shim
I ran yarn add -D mutationobserver-shim
and imported it (with import 'mutationobserver-shim'
) in my jestSetup.ts
(which is what globalSetup
in my Jest configuration points to), but that resulted in the following error:
ReferenceError: window is not defined
at Object.<anonymous> (/<path_to_repo>/node_modules/mutationobserver-shim/dist/mutationobserver.min.js:12:1)
Adding the import instead to my test file yielded the same TypeError
as above, and adding a console.log(global.MutationObserver)
to my test file yielded undefined
.
After a lot of trial and error, I discovered that if I 1) have jest-environment-jsdom-sixteen
installed and tell Jest to use it and 2) add import 'mutationobserver-shim'
in my test file, and the tests will pass. However, if I put add the import to my Jest globalSetup
file, it doesn't work. I get the same ReferenceError: window is not defined
error as before.
How can I get rid of both errors without requiring users of our component library to add an import statement to all of their test files?
A polyfill should be applied in setupFilesAfterEnv
, because this is where the jsdom environment is instantiated and window
becomes available. window
isn't supposed to be available in globalSetup
because it doesn't run in a test scope.
In case this is an unejected create-react-app project, the setup file that corresponds to setupFilesAfterEnv
is src/setupTests.ts
(src/setupTests.js
).
That the newer jsdom
version causes an error means it's incompatible with the old Jest version (24). They should be ejected and upgraded, or newer CRA (react-scripts@4
) with Jest 26 support has to be used.