It is essential first to understand what testing is. Testing is a 3 step process that looks something like this: The first step is to Arrange. This includes arranging the step in a specific original state. Like there would be a button or header on a page. I am designing and considering coming under the Arrange state.
The second step is Act. It includes clicking on the page, entering the input field, etc. Like, click on a button on the page, or toggle a header.
The third step is Assert. It is the first test primary step of the testing. It considers the hypothesis of our web app's state, like when clicked on the button, how it will react component behave, and where it'll redirect. If the test passes, it is working fine, and if the test fails, we need to check and fix the bug.
We can test React components using multiple test runner environments. Unlike react components, the test does not run on individual components in the browser and needs any test runner.
React provides the Jest framework, which acts as a testing environment and runs the test. That is why we don’t need to export and describe it to write the tests. We will know about it in detail in the coming section.
Testing is a great discipline that can lead to an 80% reduction in bug density. It also has other important benefits like it -
Improves your code architecture and maintainability.
It gives quick feedback on testing whether or not your changes worked.
It gives excellent safety while adding new features or refactoring existing features.
That’s a term used in programming practice where you write the before. Let’s look into it with an example if we are going to create a function. We are doing it for the expected input element and output, so here we will make a test with output type like there is a function of calculating 2 numbers then it should give a number output as expected.
If const component is not, the test will fail, & let us know the error. If we use Test Driven Development(TDD), this will let us reduce our functions to a small part of logic, & you can make sure on your code and detect errors in the dev process before the integration.
The Do and Don't do for Unit testing in React are explained below:
We test the application's functionality and check if it is working fine. We checked the functionality that the app is working fine for the end-users.
We can now check how it will behave with the end-users. Writing the unit test cases and covering all the major scenarios gives the developer the confidence that it will work fine in production.
Writing tests for the test cases makes our application more robust and less error-prone. If testing is done correctly from the developer’s end, it is more likely to work fine in each intended case and lead to fewer bugs.
The test doesn't include testing the implementation details the end-user does not care about. We should not test the variable and function names. Like the constant variable name or the function name changes, then the test will fail, but the end-user doesn’t care about what function name we have given.
Suppose there is a javascript function named ‘handleClick’ and we tested the functionality using this name, it worked fine. But if we change the function name to on Submit, the test will fail, but the functionality would work as expected. Also, the end-user does not care about it.
Our aim to write tests should be to test the functionality to work fine as intended on clicking the button. So, changing variable names expect method name & function names is not our responsibility to test.
Also, we should not test third-party libraries, it is our responsibility to work correctly to integrate with our certain functionality. We need to do the basic check before using it in our application that it is adequately tested by the developers and is production-ready to use.
Or we can check the library's source code, whether it includes the test cases or not. After verifying all these details, we can confidently use some of the third-party libraries with our application & will not cause any issues in the production and development environment.
In React, the testing of multiple components can be done in three ways using:-
React testing Library
Jest
Enzyme
We will read more about each method in detail with the implementation.
The react testing library is a lightweight package which is created by Kent C. Dodds. It is built on top of React-Dom and react-dom/test-utils. It also encourages the best testing practices. The primary guiding principle of reacting testing library is -
The closer your tests are to how your program is used, the more trust you'll have in it.
This library does not deal with any rendered nodes. It directly deals with the actual nodes. The library provides querying the DOM nodes like finding elements, buttons, etc. Also, it provides more accessibility & provides such an environment where we can test how the user will use the application.
This library is not:-
A test runner or framework.
It can be used with any specific framework.
Now, let’s go deep dive into the implementation of the React testing library:-
for this basic knowledge of React is a plus to enhance our software development process
It can be installed using:-
npm install --save-dev @testing-library/react
The react testing library needs to be implemented using Jest. It can be run without using Jest, but it is not the preferred way of doing it.
So testing react, using the React testing library with Jest is implemented below.
About Jest
Jest is a JavaScript Framework focusing on simple ways, and it works with the project using -Babel, Node, TypeScript, React, Vue & more. It can be installed using npm or Yarn.
Jest perfectly fits with better usability known as test runner (runner focused on running or debugging a specific test or test-suite, while jest is in-process current test cases every time we change it). It creates snapshots when we run our file. It works as -
Fig:- Snapshots creation
Configuration of Jest
To get our tests up and to run tests, we can setup jest by installing it on dev dependencies -
npm install --save-dev jest
In package.json, add test to jest.
{ ..."scripts": {"start": "react-app-start","test": "jest"},...}
Now we create a test suite file. Here we created it as cfs.test.js.
Mention below, we are using a single component of reacting named Footer & placed it into cfs.test.js. We can use enzyme along with jest for further functionality for testing components, which is also mentioned below. Then in the package.json file, we need to add the following configuration to the jest file -
"jest": {"setupFilesAfterEnv": ["<rootDir>src / pages / checkFreeScore / checkFreeScore /cfs.test.js"],"snapshotSerializers": ["enzyme-to-json / serializer"]},
We run the test case using the command npm run test or npm test, which does the following in the package.json file:-
Here we are going yarn test with a single UI section component < Footer / > where the test scenario will depend on the rendering components and functions that will be any result.
After running any test, it creates snapshots of it you can find complete code below:
// Jest Snapshot v1,
exports [`BaseButton renders correctly 1`] = `
<Context Consumer>
<Component />
</ContextConsumer>
`;
exports [`Footer section renders correctly 1`] = `
<ContextConsumer>
<Component />
</Context Consumer>
`;
exports [`matches snapshot 1`] = `
<ContextConsumer>
<Component />
</ContextConsumer>
`;
About Enzyme
The Enzyme is a javascript testing utility for testing React components that makes it easier to assert, manipulate & traverse the components. It was created by Airbnb and later transferred to an independent Organization. It was developed around December 2015. It provides manageable methods to find elements, render components and interact with the elements.
Jest and Enzyme
Both Jest and Enzyme are meant to test the react applications. Jest can be used with any other Javascript framework, but Enzyme is meant to test run only on react apps only.
Jest can be used without Enzyme & snapshots can be created and tested perfectly fine. But the Enzyme adds additional functionality to it.
An enzyme can also be used without Jest, but we need any other test runner paired with it.
So, In our application, we have used:-
Jest - Jest as a test runner, assertion library & mocking library.
Enzyme - To provide additional testing utilities to interact with elements.
Setup
We need to create a setupTest.js file. It will contain all the settings & configurations for the enzyme test setup.
The setupTest.js file would look like this -
import Enzyme, { shallow, render } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import element Dataset Polyfill from "element-dataset";
// React 16 Enzyme adapter
Enzyme.configure({ adapter: new Adapter() });
// Make Enzyme functions available in all test files without importing
global.shallow = shallow;
global.render = render;
element Dataset Polyfill();
const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
clear: jest.fn()
};
global.sessionStorage = jest.genMockFunction();
global.sessionStorage.setItem = jest.genMockFunction();
global.sessionStorage.getItem = jest.genMockFunction();
global.sessionStorage.removeItem = jest.genMockFunction();
global.localStorage = localStorageMock;
Then in the package.json file, we need to add the following configuration to the jest file:-
"jest": {
"snapshotSerializers": [
"enzyme-to-json/serializer"
],
"setupFiles": [
"./config/setupTest.js"
],
}More details of the setup and implementation can be found here:- React Unit testing and Enzyme setup.We run the test case using the command npm run test, which does the following in the package.json file:-"test": "jest test -- --coverage -- updateSnapshot",
Implementation of Enzyme
Here I have picked the login component for writing unit tests, which looks something like this -
The reason for choosing Enzyme testing for the login component was, it is using the mapStateToProps, without & connect method for passing the data in the component. The entire component, using these methods can only be tested by Enzyme.
Before starting the unit tests case, we need to create a test functionality like login.test.js. The file should be created using the folder name test. This is the standard convention for the folder name for testing.
Implementation of Login Testing
Scenarios to Test in the Login Component
The cases would be:-
Should render the login component correctly.
Should render the form.
Has helmet tag(used in the component)
Has h1 on the page.
Has login text for users.
Has forgotten password text and redirects to forgot password page on click.
Has logo on the page.
Has login button present.
The login button should show an error message when the fields are empty and clicked.
Has email field and state changes on click.
Has password field and state changes on click.
Should show an error message when the invalid email is clicked.
Show call login function when correct details are provided and show loader.
Should successfully login when correct details are provided.
Example:-
//checked if login component rendered correctly.
it('should render correctly ', () => {
wrapper = shallow(<Memory Router>
<Login Component store={store} />
</Memory Router>);
expect (wrapper.getElements()). to MatchSnapshot();
})
Here, we are checking that the login component renders correctly. Also, we are using the shallow rendering method of the Enzyme.
We have used MemoryRouter to mock the router component used this way we can check our test file. Then we have passed the mocked data to the component and provided it the mock environment for testing.
Then we have done the testing of the component using expect. We check that does it matches with the correct snapshot created. After implementing all the scenarios of login testing, the final output of the npm run test would look like:-
So, We found that unit testing is compulsory for developers to do. It seems a bit of extra work but when it comes to better performance and a great experience for users with fewer bugs, testing becomes compulsory, developers should also focus on snapshot testing and integration testing.
Following the TDD approach, helps us to find the bugs at an early stage and resolve them. It also helps us to develop faster applications. We saw various methods of unit testing in react, which can be adopted as per our requirements & development.
Even many companies add a stage in a pipeline as build. So, it becomes compulsory for each developer to fix the failing test cases after the implementation of the functionality.
This website uses cookies to analyze website traffic and optimize your website experience. By continuing, you agree to our use of cookies as described in our Privacy Policy.