Reactjs testing with Jest 101

Manoj Masakorala
7 min readJul 6, 2021
React testing with jest and enzyme
image courtesy realpython.com

OK, let’s get to the point straight away. Why do we need frontend unit testing? Is it a real necessity? wouldn’t it consume additional effort and time of frontend developers? or would it? I think as a developer deep down you will all understand that you would need to write unit testing even though you hate it as a newbie. Let’s find out why and how we do it.

TDD

TDD or Test-driven-development is the way to do frontend Testing. It means writing tests before writing code. So the idea is to write a shell version of a code initially. What that means is simply defining may be an empty function. An empty function won’t do anything. It would probably get failed which is the red part of red-green testing. You will find tests getting failed always before they get to succeed.

Testing has saved my bacon enough times that I feel uneasy coding without it, like rock climbing without a rope. — Bonnie Schulkin

TDD is efficient. Because it would take a considerable amount of time to test and retest again, and again when you do changes while developing. If you wait till the end to write unit testing, you are not taking the advantage of testing while code progresses. Also, you would end up with better code. You will have to plan before you code which leads to better code quality. and better organized too. And the code you write is more testable. Since you are writing tests while you are developing the feature, you don’t have to rewrite the code because of testing. Finally, TDD would lead to fewer bugs or bugs being caught sooner. Not to mention how helpful when a regression is built-in and all the tests would be re-run whenever you do a code change.

Every project is different
So keep that in mind that every project is different. If you get used to the test practice of one project does not mean that you can jump into another project and start writing tests right away. Some projects may mock functionality full some do partially. Some do isolated testing some don’t.

Types of testing

  • Unit testing — testing one piece of code. Usually one function.
  • Integrated testing — Checking how multiple functions work together.
  • End-to-end testing — Testing the end-to-end flow by using an actual browser and connections to the server. May have to use tools like Cyprus/selenium.
  • Functional testing — can be any of the above which focuses on user flow. Testing user behavior is functional testing.

Jest

Jest is a javascript testing framework. It works with many other javascript libraries and frameworks such as Babel, Typescript, Node, React, Angular, Vue, and many more. With Jest, you can start right away with zero configurations. Not to mention how easy to take snapshots with Jest. Jest is fast compared to other testing frameworks and it generates reports so that we can keep a track of code coverage. Mocking plays an important role in testing. Because we may come across some scenarios that we have to mock the actual behavior. for example, if we need to get the response from an API call we will have to mock it. With jest it’s super easy.

Jest — watch
Jest watch mode watches for changes and re-runs the tests. How does Jest know which files to lookup? So normally we name our javascript files as button.js/button.jsx or button.tsx. For the correspondent test file, we name as button.spec.tsx. spec keyword can be any keyword you prefer. You have to config it in jest configuration file.

testMatch: [‘<rootDir>/src/main/app/**/@(*.)@(spec.ts?(x))’]

Enzyme vs react testing library.

Different is philosophical. Both the above libs provide utility functions for jest. Both Enzyme and react testing libraries are used to test virtual DOM. Hence allows us to run tests without a browser. Both create virtual DOMs. Enzyme is widely used and has been in the market for the longest. Enzyme also supports isolated testing and has cool features like shallow rendering.
React testing library on the other hand is the most popular and trending one. It strongly prefers functional testing which means it would test, interacting as a user would.

Testing behavior vs Testing implementation.

Let me explain with an example. Assume there is a button. When clicking on the button an alert would pop up. So when testing behavior, it would test in the DOM whether the button is there and when the user clicks it whether the pop up appears in the dom. So it tests the user flow as an actual user would interact with the application.

On the other hand, when testing implementation, we would have to check internal implementation as well. When the user clicks on the button we will have to check if a particular internal state gets change so that a pop-up would appear. when re validate state changes again when pop up gets closed. likewise.

  • Downside of functional testing — when testing user behavior it exposes less granularity when pointing where the test fails.
  • Upside — Less code refactoring when code changes. for example, if you are moving to functional components from class components you will have a lot of code changes internally but from a testing perspective, user flow would not get change. If dom does not get the change we can reuse existing tests with no or minimal changes.

So it’s a trade-off that we have to make on tracking down errors vs time spent on maintaining tests.

Shallow rendering

Since I mentioned shallow rendering previously let me explain that too real quickly. Rendering component only one level deep is shallow rendering. Render parent but use a placeholder for children. Which leads to faster loading. With shallow rendering, components are tested isolated. An issue in children does not cause the parent to fail.

Shallow rendering and opposite of shallow is mount

Simple counter app

Following includes a simple react component where it contains a counter.

So basically we are using react testing lib instead of Enzyme. Here we are checking if,
1. header <h1> text exist in dom
2. check if the button available in dom
3. check if label change on user click event

Jest snapshot testing

This is a way to freeze a component and take a snapshot of the component. When you re-run the tests, if there are any changes to the output when compared to the snapshot taken, tests would fail. We can’t practice TDD with this approach. Any changes to component tests would fail. When tests fail it’s difficult to diagnose. So avoid it unless you know what you are doing or if it’s necessary.

Mocking

Mocking a function is simply a fake function that runs instead of a real function. Can run alternate code or act as a placeholder. Jest can replace function with mocks.

Why should we mock.
1. keep real function from running — prevent side effects — eg: network calls
2. Spy on a function to see when it called
3. Provide return values.

Mocking Types

  • Jest.fn — mock a function
  • Jest.mock — mock a module
  • Jest.spyOn — Spy or mock a function

Mock an API call

So we are going to call an public API and get some posts. We will be mocking this endpoint when testing because we don’t want an dependancy with thrid part service, when running our tests.

Above is the Posts.js file. Bellow is how we mock the api call. First of all we have to mock axios module. then moack the get function of that module. We will pass expected response value as well.

Test redux reducer

Following is a header reducer where is has an action called loadHeader. Load header will set a new header to the headerTitle state.

Following is how we test it. We need to test initial state. Should test update state scenario. And also actions.

Sinon

Finally you can also use external libs such as sinon for mocking.
Sinon is a standalone and test framework agnostic JavaScript test spies, stubs and mock. You can simply use it as follows.

import axios from 'axios';
import sinon from 'sinon';
const resolvedObject = { value: 'whatever' };
axios.get = sinon.stub().returns(Promise.resolve(resolvedObject));

So we will stop here at mocking. Will catch you all with another episode of frontend unit testing with Jest.

References

https://reactjs.org/docs/create-a-new-react-app.html

https://reactjs.org/docs/testing.html

https://jestjs.io/

https://enzymejs.github.io/enzyme/

https://github.com/manoj-mass/reactjs-testing-playground

https://jestjs.io/docs/snapshot-testing

https://www.npmjs.com/package/sinon

--

--