It's time to update from Jest 29 to 30 for me.
Except I can't. At least not completely.
The Easy Part
They changed the snapshot files: the link in the header changed. I find short-links disturbing anyway.
- // Jest Snapshot v1, https://goo.gl/fbAQLP
+ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
Then they removed some deprecated matcher aliases. ( → expect(fn).toBeCalled()expect(fn).toHaveBeenCalled()) It took a while but was manageable.
Then I got really confused when I found out some modules are not mocked anymore. As it turns out jest.mock("./path/to/module") is case-sensitive now.
The Hard Part
Jest updated JSDOM from Version 20 to 26.
It added show-stopping CSS-bugs for me (el.style.boxShadow = undefined became el.style.boxShadow === "undefined" instead of the expected el.style.boxShadow === ""), fixed them in Version 27 and introduced new show-stopping CSS-bugs for me.
While this is manageable, my tests regarding navigation began to fail...
The impossible Part
JSDOM does not implement window.location which is fine.
Up until now it was possible to mock window.location, but this stopped working in JSDOM v21.
// does not work anymore
delete window.location;
Object.defineProperty(window, 'location', { // TypeError: Cannot redefine property: location
writable: true,
value: { search: '' },
});
Possible workarounds are discussed, but none are satisfactory.
- JSDOM does not plan to do anything about this.
-
Using
reconfigure({url: "..."})does not help me, because I want to know if the location was changed to the desired value. - Some even suggest to patch the jsdom package. I really don't want to do this. (But it may help for a while).
- I wanted to be clever and thought we might manipulate the JSDOM Window Object with Proxies and apply them using
@jest/environment-jsdom-abstract- but I was wrong....
The "Solution"
So at this point its Jest 30 with JSDOM 20 (from Jest 29). 🤮
// package.json
{
// ...
"devDependencies": {
"jest": "^30.2.0",
"jest-environment-jsdom": "^29.7.0",
}
}
Uh and on the End-To-End test side, things became complicated since chrome complains when websites try to connect to localhost and local ip-adresses.
Testing is a nightmare right now.
Top comments (7)
Thanks for the article, just ran into the same problems, helped me a lot. Had a small talk about a different issue on JSDOM's Github issues. Their attitude kinda seems to explain why they don't support this anymore ...
Thank you for your comment. I am glad I could help.
Whenever I think about this, there is this little voice in my head: "Just create a fork of JSDOM, that applies a simple patch that allows us to use JSDOM for testing".
But then I start to overthink it, like: How would I version this?
The solution that worked for me was to replace
Object.defineProperty(window, "location", {
value: {
pathname: "/",
},
writable: true,
});
with
window.history.pushState({}, "", "/");Hopefully it will work for you as well.
Hi, thank you for your approach.
This means you use pushState
window.history.pushState({}, "", "./some-other-docutment.html")in your app instead ofwindow.location.href = "./some-other-docutment.html"?And in your tests you mock/spy
window.history.pushState?No. I made no changes to the behavior of the application. My suggestion is specific to failing unit tests.
In my case, the unit tests were not actually testing the location value, but the behavior of my components when the path was different (i.e. - hiding certain DOM elements).
For example,
For further context, my corresponding dependencies are
"jest": "^29.7.0"and"jest-environment-jsdom": "^30.2.0".Hope that helps.
I kind of understand what you are doing.
You want to test if a component behaves as expected if the url has a certain value.
I want to test if a simulated action changes the url.
does jsdom implement pushState?