How should I unit test my code-Part 2

Image result for testing
Image source: hackernoon

Getting Started

Hi everyone, in this article we will learn to write unit tests for some of the common scenarios in React. If you are new to unit testing, you can check out the article Why should I unit test my code?

If you need help with the setup of Jest and Enzyme before proceeding to write tests, check here.

I have created a repo at GitHub which contains all the setup and examples which we will be going through in this tutorial. Feel free to clone the repo or to refer to it at any point you get stuck while following through the below steps.

To clone the repo, use:

git clone https://github.com/anuk79/UnitTestingReactUsingJestAndEnzyme.git

We will follow the below pattern for each example:

  • Code to be tested
  • Test cases
  • Explanation

So, let’s get started 😎

Example 1: Testing React Component

We will write our first component(LoadingSpinner) with very basic code.

// loading-spinner.jsximport React from 'react';const LoadingSpinner = (props) => {return (
<div className={props.customClassName}>
{'...loading'}
</div>
);
}
export default LoadingSpinner;

Here, we have a functional component which renders only a div with text as …loading

To unit test this, we will use shallow rendering of enzyme which returns a wrapper instance around the rendered output. PFB the test cases:

// loading-spinner.test.jsconst wrapper = shallow(<LoadingSpinner customClassName="test-  class"/>);expect(shallowToJson(wrapper)).toMatchSnapshot();
expect(wrapper.find('div').length).toBe(1);
expect(wrapper.find('div').text()).toBe('...loading');
expect(wrapper.find('div').prop('className')).toBe('test-class');

Explanation:

  1. expect(shallowToJson(wrapper)).toMatchSnapshot();
    Here, we match the snapshot generated to the already stored snapshot of the component. Here, the test will fail while running for the first time via command yarn jest or npm run jest This is because the snapshot has not yet been generated. So, we need to generate the snapshot for the first time, which can be done by appending -u to the test command -> npm run jest -u or yarn jest -u
    This is useful in validating if the changes done are really intentional or possibly a mistake.
  2. In the following tests, we verify that the wrapper contains one div with text as ...loading and it’s className is test-class which was passed as props to the LoadingSpinner component.

So, we have successfully written test-case for a very basic component with some props. Let’s now move ahead to our next example with some event listeners

Example 2: Testing event handlers

We will create a component named InputComponent which will render an input element with attributes mapped to the props received.

const InputComponent = (props: Props) => {
return (
<input type={props.type} value={props.value} onChange={event => props.handleChange(event)} />
)
}

PFB test cases for it. We will focus only on testing the handleChange event

const handleChangeMock = jest.fn();const wrapper = shallow(<InputComponent handleChange={handleChangeMock}/>);
wrapper.find('input').simulate('change', 'testEvent');
expect(handleChangeMock).toBeCalledWith('testEvent');

Explanation:

  1. Here we will use the mocking concept. Since we are unit testing the component, we do not need to know what exactly the method handleChange , which has been received as props in our component, does. Instead, we can use jest.fn() to create a jest mock, which we then pass to the component InputComponent
  2. Now, we use the below line to simulate (or call) the change event of the input element.
wrapper.find('input').simulate('change', 'testEvent');

3. Now, the last line will assert if the method received in props (handleChangeMock in our case) was actually called with the testEvent as passed which simulating the change event of the input.

To read more about mocking, refer — https://jestjs.io/docs/en/mock-functions

Also, you can read more about mocking and spying in an awesome article titled Understanding Jest Mocks by Rick Hanlon II

Example 3: Testing asynchronous calls

We have a method here which uses fetch to asynchronously call an api.

// user.resolver.jsexport const getUserDetails = async () => {
try {
const response = await fetch('/api/get-user-details',
{
'method': 'GET',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'accept': 'application/json'
}
}
);

if (!response.ok) {
throw new Error(response.status);
} else {
return response.json();
}
} catch (error) {
throw new Error(error);
}
}

To test the above method, we will need to mock the fetch method. PFB the test cases:

// user.resolver.test.jsimport { getUserDetails } from './user.resolver';describe('User resolver', () => {
it('should return result when api call for userDetails succeeds', async () => {
const mockResult = { response: 'test response' }; window.fetch = jest.fn().mockImplementation(() => ({
ok: true,
status: 200,
response: 'test response',
json: () => new Promise(resolve => { resolve(mockResult); })
})); const userDetails = await getUserDetails(); expect(userDetails.response).toEqual('test response');});
it('should throw error when api call for userDetails fails', async () => {
window.fetch = jest.fn().mockImplementation(() => ({
ok: false,
status: 404
}));
try {
await getUserDetails();
} catch (e) {
expect(e.message).toEqual('Error: 404');
}
});
});

Explanation:

  1. Here, we are using jest.fn().mockImplementation which accepts a function that should be used as the implementation of the mock. Since we need to test for both success and failure results for the api call, we will return different values each time while mocking the implementation of the fetch method.
  2. We need to mark the test case as async to inform the test case that we are performing asynchronous operations inside of it. We do so by prepending the async keyword to the test case callback.
  3. Inside the test, we call the method using keyword await prepended to it
  4. For the success scenario, we will assert if the response returned is as expected (i.e., the same response as returned from our mock implementation)
  5. For the error scenario, we will use try-catch so that the error thrown by the actual code is caught in the catch block where we can expect the error message.

To read more about async/await, refer — https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

This brings us to the end of this article. Here, we have learned how to test some basic React components, event handlers and asynchronous calls which we use frequently in Redux.

Once again, you can refer to the git repo here to refer to more examples and test cases — https://github.com/anuk79/UnitTestingReactUsingJestAndEnzyme

Note: This article covers the examples for unit testing the React and Redux code. PFB the series topics:

  1. Why should I unit test my code?
  2. How should I unit test my code?
    2.1. Setup
    2.2. Examples (this article)
  3. What should I unit test in my code?

Stay tuned and catch you in the next article !! Any feedback is highly appreciable.

Please drop comments if you are facing issues while testing any specific scenario, and I will be glad to try it out and help :)

Thanks for reading, have a great day!!

Web Developer, Accessibility Advocate, Google Developers Expert, MDE @Cloudinary. https://.anuradhakumari.com/ ‘Choose RIGHT over easy, always!’

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Angular 13 - Updates

Why i don’t think React is necessary

How to Use the Fetch API with Star Wars Examples ⭐️ 🚀

How to visualise ROS images in ReactJS

How to use VueJs instead of jQuery

Fundamental React concept and Virtual-DOM

Multiple content projections in angular

How to Parallax Like a Boss

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Anuradha Kumari

Anuradha Kumari

Web Developer, Accessibility Advocate, Google Developers Expert, MDE @Cloudinary. https://.anuradhakumari.com/ ‘Choose RIGHT over easy, always!’

More from Medium

.toBe or .toEqual?

What does a front-end developer do?

How does CORS work?

Declarative vs. Imperative Coding