DEV Community

Hauke T.
Hauke T.

Posted on

Updating to Jest 30 is Frustrating (it's JSDOM)

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
Enter fullscreen mode Exit fullscreen mode

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: '' },
});
Enter fullscreen mode Exit fullscreen mode

Possible workarounds are discussed, but none are satisfactory.

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",
    }
}
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
n4zroth profile image
Fabian Guenter

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 ...

Collapse
 
htho profile image
Hauke T.

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?

Collapse
 
anoveskey1 profile image
anoveskey

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.

Collapse
 
htho profile image
Hauke T.

Hi, thank you for your approach.

This means you use pushState window.history.pushState({}, "", "./some-other-docutment.html") in your app instead of window.location.href = "./some-other-docutment.html"?

And in your tests you mock/spy window.history.pushState?

Collapse
 
anoveskey1 profile image
anoveskey

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,

it("should not render the navigation buttons when on root path", () => {
    window.history.pushState({}, "", "/");

    render(
      <PageContainer>
        <div>Test Content</div>
      </PageContainer>,
    );

    const navigationButtons = screen.queryByRole("button", { name: /back/i });
    expect(navigationButtons).not.toBeInTheDocument();
  });
Enter fullscreen mode Exit fullscreen mode

For further context, my corresponding dependencies are
"jest": "^29.7.0" and "jest-environment-jsdom": "^30.2.0".

Hope that helps.

Thread Thread
 
htho profile image
Hauke T.

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.

Thread Thread
 
htho profile image
Hauke T.

does jsdom implement pushState?