Consider a component with a button, and on click of the button, the state variable counter
of the component is updated. This variable is displayed on screen.
For the above functionality, we are going to write the unit test case in enzyme and in react-testing-library. You will understand the difference of writing unit test case in them.
Below is the code of the component we are going to test.
import React, { Component } from "react";
export default class App extends Component {
// counter variable init to 0
state = {
counter: 0
};
showLog = () => {
const { counter } = this.state;
this.setState({
counter: counter + 1
});
};
render() {
const { counter } = this.state;
return (
<div className="App">
<div>{counter}</div>
<button onClick={this.showLog} onMouseEnter={this.showLog}>
Click me
</button>
</div>
);
}
}
In Enzyme, we get the ability to access the state of the component and the methods (unlike react testing library). So we are going to write three unit test cases for the above component - each focusing on the specific functionality.
updateCounter
function is called. In the below test case, we get the shallow
rendered version of app component, and spy on the instance method updateCounter
. Then we force refresh the app to register the new spy method. Then we find the button and simulate the click event. In enzyme, the events such as mouse click, mouse over, drag drop events, custom events etc are simulated using simulate
function.it("should call showLog on click of button", () => {
const app = shallow(<App />);
const spy = jest.spyOn(app.instance(), "updateCounter");
app.instance().forceUpdate();
app.find("button").simulate("click");
expect(spy).toHaveBeenCalled();
});
updateCounter
actually increments the state counter variable. In the below unit test case, we call the function updateCounter
and check that the state variable counter
is incremented by 1. it("should update state counter in updateCounter", () => {
const app = shallow(<App />);
app.instance().updateCounter();
expect(app.state("counter")).toEqual(1);
});
it("should show counter from state", () => {
const app = shallow(<App />);
app.setState({
counter: 10
});
const counter = app.find(".counter").text();
expect(counter).toEqual("10");
});
When it comes to react testing library, as we discussed on the previous article about the differences between react testing library and enzyme, there are no methods available in React Testing Library to test the state or instance methods of component.
Its because react testing library encourages developers to write unit test cases which closely resemble the way user uses the app and to avoid writing brittle tests.
React Testing Library encourages you to test the functionality of the component rather then the implementation.
So for the above component, we are going to test that when the user clicks on the button, the counter variable displayed on the screen is also updated.
import React from "react";
import "@testing-library/jest-dom/extend-expect";
import { render, fireEvent } from "@testing-library/react";
import App from "./app";
describe("App Tests", () => {
it("should update counter on click of button", () => {
const { container } = render(<App />);
const button = container.querySelector("button");
fireEvent.click(button);
const counter = container.querySelector(".counter");
expect(counter).toHaveTextContent("1");
});
});
We get the rendered component using the code
render(<App />);
This returns the instance of the app, from which we get container
that it is rendered in.
const { container } = render(<App />);
We find the button in the component and fire the click event. In react testing library, events are fired using fireEvent
.
const button = container.querySelector("button");
fireEvent.click(button);
Then we check that the counter variable displayed on the screen is incremented by 1.
const counter = container.querySelector(".counter");
expect(counter).toHaveTextContent("1");
In order to test the mouseEnter
event, replace fireEvent.click
with fireEvent.mouseEnter
.
List of all the events
To get the list of all events, go to the link event-map.js
The above article is aimed at educating people on how the way we write the unit test case changes from enzyme to react testing library. Read this tutorial to understand the differences between brittle and non-brittle test, and this tutorial to understand the differences between enzyme and react testing library.