Jest got introduced by Facebook for testing JavaScript and especially React applications. Itâs one of the most popular ways to test React components nowadays. Since it comes with its own test runner, you can simply call Jest from the command line to run all your tests. All your tests are defined as test suites (e.g. describe -block) and test cases (e.g. it -block or test -block).
The Jest setup allows you to add optional configuration, to introduce a setup routine yourself, or to define custom npm scripts to run your Jest tests. In this tutorial, you will learn how to perform all of it. Aside from all the setup, Jest comes with a rich API for test assertions (e.g. true to equal true). The tutorial will show you how to use these test assertions for your React components and JavaScript functions. Also you will learn about Snapshot Tests to test your React components.
Before implementing the test setup and writing the first React component tests, you will need a simple React application which can be tested in the first place. Start with the src/index.js file where you can import and render the App component which is not implemented yet:
The App component in your src/App.js file will be a React Function Component with React Hooks . It uses axios as third-party library, so make sure to install the node package on the command line with npm install axios for your React application.
The React application is doing two things:
First, it renders a Counter component which receives props to render a counter property. The counter property is managed as state up in the App component with a useState React Hook . In addition, the counter state can be updated with two buttons by incrementing and decrementing the state.
Second, the App component fetches data from a third-party API when itâs rendered for the first time. Here we are using Reactâs useReducer Hook to manage the data state â which is either the actual data or an error. If there is an error, we render an error message. If there is data, we render the data as a list of items in our React component .
Note that we already export our two components and the reducer function from the file to make them testable in our test file(s) later on. This way, every component and the reducer can be tested in isolation â which makes especially sense for the reducer function to test the state transitions from one to another state. Thatâs what you would call a real unit test: The function is tested with an input and the test asserts an expected output.
In addition, we have a relationship between two React components, because they are parent and child components. Thatâs another scenario which can be tested as integration test. If you would test each component in isolation, you would have unit tests. But by testing them together in their context, for instance rendering the parent component with its child component, you have an integration test for both components.
In order to get our tests up and running, set up Jest by installing it on the command line as development dependencies:
In your package.json file, create a new npm script which runs Jest:
In addition, we want to have more configuration in our tests written with Jest. Hence, pass an additional Jest configuration file to your Jest script:
Next, we can define this optional configuration for Jest in a configuration file. Create it on the command line:
In this Jest configuration file, add the following test pattern matching to run all the test files which shall be executed by Jest:
The testRegex configuration is a regular expression that can be used to specify the naming of the files where your Jest tests will be located. In this case, the files will have the name *spec.js . Thatâs how you can separate them clearly from other files in your src/ folder. Finally, add a test file next to your App componentâs file in a new src/App.spec.js file. First, create the test file on the command line:
And second, implement your first test case in a test suite in this new file:
Now you should be able to run npm test to execute your test suites with your test cases. The test should be green (valid, successful) for your previous test case, but if you change the test to something else, letâs say expect(true).toEqual(false); , it should be red (invalid, failed). Congratulations, you have run your first test with Jest!
Last but not least, add another npm script for watching your Jest tests. By using this command, you can have your tests running continuously in one command line tab, while you start your application in another command line tab. Every time you change source code while developing your application, your tests will run again with this watch script.
Now you can run your Jest tests in watch mode. Doing it this way, you would have one open terminal tab for your Jest tests in watch mode with npm run test:watch and one open terminal tab to start your React application with npm start . Every time you change a source file, your tests should run again because of the watch mode.
Jest introduced the so-called Snapshot Test. Basically a Snapshot Test creates a snapshot â which is stored in a separate file â of your rendered componentâs output when you run your test. This snapshot is used for diffing it to the next snapshot when you run your test again. If your rendered componentâs output has changed, the diff of both snapshots will show it and the Snapshot Test will fail. Thatâs not bad at all, because the Snapshot Test should only inform you when the output of your rendered component has changed. In case a Snapshot Test fails, you can either accept the changes or deny them and fix your componentâs implementation regarding of its rendered output.
By using Jest for Snapshot Tests, you can keep your tests lightweight, without worrying too much about implementation details of the component. Letâs see how these work in React. First, install the react-test-renderer utility library commonly used for Jest to render your actual component in your tests:
Second, implement your first Snapshot Test with Jest. First, render a component with the new renderer, transform it into JSON, and match the snapshot to the previously stored snapshot:
Now run your Jest tests in watch mode again: npm run test:watch . Running your tests in watch mode, when having Snapshot Tests in place, gives you the opportunity to run your tests interactively with Jest. For instance, once your watch mode is active, change the div element to a span element in your React component:
The command line with the tests running in watch mode should show you a failed Snapshot Test:
The previous snapshot doesnât match the new snapshot of the React component anymore. Furthermore, the command line offers you things to do now (optionally you have to hit w on your keyboard):
Pressing a or f will run all or only your failed tests. If you press u , you accept the âfailedâ test as being valid and the new snapshot of your React component will be stored. If you donât want to accept it as a new snapshot, then fix your test by fixing your component.
Afterward, the Snapshot Test should turn green again:
Anyway, try it yourself by changing the component and either accepting the new snapshot or fixing your React component again. Also add another Snapshot Test for your App component:
Most of the time, Snapshot Tests look the same for every React component. You render the component, transform its rendered output to JSON to make it comparable, and match it with the previous snapshot. Having Snapshot Tests in place keeps testing React components more lightweight. Also, Snapshot Tests can be perfectly used to supplement your unit testing and integration tests, because they donât test any implementation logic explicitly.
Note: If you are using Styled Components in React for CSS-in-JS, check out jest-styled-components for testing your CSS style defintions with snapshot tests as well.
Jest can be used to test your JavaScript logic as integration or unit tests as well. For instance, your App component fetches data and stores the result as state with a reducer function by using a React Hook. This reducer function is exported as standalone JavaScript function which doesnât know anything about React. Thus, there doesnât need to be any rendering for the React component and we can test this reducer function as plain JavaScript function.
Write two additional tests to cover other parts of your reducer function and edge cases. These two other parts are called the ânot so happyâ-path, because they donât assume a successful outcome (e.g. data fetching fails). By writing your tests this way, you cover all conditional paths in your applicationâs logic.
Once you run your tests, you should see the following output on the command line. If a test fails, for instance during watch mode, you will be notified immediately.
You have seen how Jest can also be used to test plain JavaScript functions. It doesnât need to be used for only React. If you have more complex functions in your applications, donât hesitate to extract them as standalone functions which can be exported to make them testable. Then you are always assured that your complex business logic works, because it has been covered by your Jest assertions.
Jest gives you (almost) everything you need to test your React components. You can run all your tests from the command line, give it additional configuration, and define test suites and test cases in your test files. Snapshot Tests give you a lightweight way to test your React components by just diffing the rendered output to the previous output. Also you have seen how Jest can be used for testing only JavaScript functions, so itâs not strictly bound to React testing.
However, testing the DOM of a React component with Jest is more difficult. Thatâs why there exist other third-party libraries such as React Testing Library or Enzyme to make React component unit testing possible for you. Follow the tutorial series for more testing examples in React.