Hello! I’ve been using Jest and Enzyme a lot lately, and I just wanted to share some of the ways I use it to test my code. For those of you who don’t know, Jest is a Javascript testing framework and I use it with Enzyme, a Javascript testing utility for React.
A few notes on using Enzyme
Enzyme allows shallow and full DOM rendering. Shallow rendering is useful when you only need to test the component and not the functionalities of the child components. Full DOM rendering is useful when you want to test the full functionality of the component.
Be sure to look out for which apis work on wrappers and which on nodes. For example,
.at(index)
returns a wrapper and .get(index)
returns a node. Using the examples on airbnb.io/enzyme:
const wrapper = shallow(<MyComponent />);
expect(wrapper.find(Foo).at(0).props().foo).to.equal('bar');
expect(wrapper.find(Foo).get(0).props.foo).to.equal('bar');
The way we find foo is different in both cases.
Jest: Snapshot
Jest offers a few features and the ones I use more are snapshot testing and mocking functions. Snapshot tests are pretty useful when you want your UI to stay as it is.
import React from "react";
import { shallow } from 'enzyme';
import { Project } from "../path/to/project";
describe("<Project />", () => {
it("should render correctly", () => {
const wrapper = shallow(<Project />);
expect(wrapper).toMatchSnapshot();
});
});
If the Project component has layouts / classNames that are different, the shallow snapshot will fail. You can update it if you know that it did change or inspect further to see what caused the fail.
Jest: Global setup for test environment
If you’re using localStorage or windows.location.href in a few components, and you realise that its not working in the tests, you can add this to your setup files in Jest:
"jest": {
"setupFiles": ["../testHelpers/local-storage-mock.js", "../testHelpers/window-location.js"],
},
and in “../testHelpers/local-storage-mock.js”:
let store = {};
Object.defineProperty(global.window, "localStorage", {
writable: true,
value: {
getItem: (key) => {
return store[key];
},
setItem: (key, value) => {
store[key] = value.toString();
},
clear: () => { store = {}; },
removeItem: (key) => { delete store[key]; }
}
});
in “../testHelpers/window-location.js”:
Object.defineProperty(global.window.location, "href", {
writable: true,
value: "localhost:3000"
});
I got the above solution from here when I wasn’t able to get the expected value from window.location.href.
Jest & Enzyme: Mocking functions
Usually in my tests I mock the output of a function from another module. (Look at the mockImplementation method). The more useful function is mockImplementationOnce()
, which is what I use when I need to mock a function’s value more than once.
jest.mock("/path/to/module", () => {
const realModule = require.requireActual("path/to/module");
return {
...realModule.default,
functionToMock: jest.fn(() => { "default" })
.mockImplementationOnce(() => Promise.resolve({
somevalue: 1
}))
.mockImplementationOnce(() => Promise.resolve({
somevalue: 2
}))
}
});
const Module = require("path/to/module");
When I call Module.functionToMock()
the first time, the value i get back is { somevalue: 1 }
which is what the first implementation is doing. Now if I call it the second time, the value I get is { somevalue: 2 }
. After this, regardless of how many times I call Module.functionToMock()
, the value I get back will be "default"
.
So that’s all I have to share on testing React components with Jest and Enzyme. Let me know if you have any questions / things to add at [email protected] (:
♡, Hui Wen