Gal Ziv
Gal Ziv

Reputation: 7372

How to setup jsdom when working with jest

I'm trying to migrate from AVA to Jest. In AVA you can set ava.setup, in which you set the jsdom environment. For example, creating the DOM structure and doing necessary polyfills (localStorage).

How do I accomplish that in Jest? Currently, I'm using beforeEach in each test suite, which doesn't feel like the best solution.

Upvotes: 25

Views: 45342

Answers (3)

David
David

Reputation: 543

Update 2022. Version 28 does not ship jsdom by default anymore:

As of Jest 28 "jsdom" is no longer shipped by default, make sure to install it separately.

You'll need to install jsdom manually:

# npm
npm install -D jest-environment-jsdom
# yarn
yarn add -D jest-environment-jsdom

credit to: https://stackoverflow.com/a/72013609/7089048

Upvotes: 15

ggorlen
ggorlen

Reputation: 56935

Here's a complete, minimal example.

package.json:

{
  "scripts": {
    "test": "jest"
  },
  "devDependencies": {
    "jest": "^29.7.0",
    "jest-environment-jsdom": "^29.7.0"
  }
}

jest.config.js:

module.exports = {
  testEnvironment: "jsdom",
  setupFilesAfterEnv: ["<rootDir>/setup.js"],
};

setup.js:

Object.defineProperty(global, "localStorage", {
  value: {
    getItem: jest.fn().mockReturnValue("hello world!")
  },
  writable: true
});

hello.js:

const hello = () => {
  document.body.textContent = localStorage.getItem("foo");
};

module.exports = {hello};

__tests__/hello.test.js:

const {hello} = require("../hello");

it("should say 'hello world'", () => {
  hello();
  expect(document.body.textContent).toBe("hello world!");
});

Output from npx jest or npm run test:

 PASS  __tests__/hello.test.js
  ✓ should say 'hello world' (2 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.303 s, estimated 1 s
Ran all test suites.

That said, you may not need to do anything in terms of mocking or polyfills, since localStorage works out of the box in JSDOM. Removing the setup code and using a non-mocked localStorage passes the test as well:

const hello = () => {
  localStorage.setItem("foo", "hello world!");
  document.body.textContent = localStorage.getItem("foo");
};

module.exports = {hello};

Upvotes: 1

Rick Hanlon II
Rick Hanlon II

Reputation: 21667

Great question.

Jest actually ships with jsdom and the environment already configured. You can override it with the testEnvironment setting.

If you need to set up more aspects of the environment though, you can use the setupTestFrameworkScriptFile setting to point to a file that executes before all of your tests run.

For example, if you need window.yourVar to be available on the window for all your tests, you would add this to your package.json:

"jest": {
    "setupTestFrameworkScriptFile": "tests/setup.js"
}

And in tests/setup.js:

Object.defineProperty(window, 'yourVar', { value: 'yourValue' });

Upvotes: 42

Related Questions