Fixing "Not implemented: X" on Jest + JSDOM for component unit tests

This article was published on Jul 27, 2022, and takes approximately 2 minutes to read.

If you're writing unit tests for your components with Jest, you're probably using it under the hood, JSDOM.

JSDOM is a pure-JavaScript implementation of many web standards. In other words, because our tests do not run in the browser but in node, we need, somehow, to have the same API available in the browser to fake render the components.

The problem is that it does not implement every single web api, which would be unpractical and not necessary to be fair, and sometimes, our code relies on global methods, and we want to test that.

Problem

In my current project, I've implemented a React component that has a URL auto generated based on input values (like project name, environment, etc.) and a button the user could click and open in another tab this URL.

I could not use native anchor elements and pass href. Instead, I had to use a component from our component library to have the company look and fill and force this navigation via window.open:

Copied
<ButtonCircular
  color="outline"
  onClick={() => {
window.open(repoUrl, "_blank");
}} > Open </ButtonCircular>;

So, I wanted to test that whenever the user fills the fields and presses the open button, we call window.open with the generated URL.

Copied
it("opens another browser tab with the repository URL", () => {
  // ... setup code

  const openSpy = jest.spyOn(window, "open");

const openUrlElement = screen.getByTestId("open-url");
fireEvent.click(openUrlElement);
expect(openSpy).toHaveBeenCalledWith(inputUrlElement.value, "_blank");
});

But then, I got this error:

Copied
    console.error
      Error: Not implemented: window.open
          at module.exports (/Users/raulmelo/development/test/node_modules/jsdom/lib/jsdom/browser/not-implemented.js:9:17)

Solution

As I said before, JSDOM does not implement ALL browser methods.

You can check a list of not implemented methods here

To solve that, we could assign a jest mock function (jest.fn) to window.open and assert against that.

Jest has a configuration called setupFilesAfterEnv, which receives a list of files that jest will run before executing the assertions. You can understand that as an "environment preparation" for your tests.

In this context, we can add the window.open.

I'm going to call this file jest.setup.js and place it at the root project level but feel free to give the name you want and place it wherever you desire:

Copied
jest.setup.js
/**
 * JSDOM does not implement global "open" function
 */
window.open = jest.fn();

Now, all I need is to reference this file in jest.config.js:

Copied
jest.config.js
module.exports = {
  // ... other configs
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js']
}

By doing that, now in my test environment, window.open will be defined, and it'll be a jest function where I can assert against it.

Conclusion

window.open isn't the only method not implemented, and you probably will face more problems like that.

Luckily the solution could be the same for all of them.

Resources