React Testing for beginners

Why test your code at all?

React Testing for beginners

Why test your code at all?

Implementing tests for your React application can give you a wide variety of pros, for example:

  • First of all, it will make you stand out from the crowd of average developers. Most of the devs do not even know how to implement tests in their code, if you learn how to do it, you will not only be satisfied with following pros but also other programmers, employers will see you as an advanced programmer.
  • It will save your time. Writing good tests for complex components can make you debug an error earlier, so that you can not sit hours and hours reading documentation and ‘googling’ the solution.
  • Tests will definitely boost quality of your code. To implement tests properly, it is necessary to divide components for smaller parts which can be tested more efficient. This can teach every dev, to write clean, understandable code.
  • Properly written tests are great documentation for your app. New developer can go through tests files and see which part of a code is responsible for.
  • Tests help to smoothly deploy an application. If you wrote and implemented tests for entire production time, there will be easier to merge code with other contributor without hours or days of debugging.

How to perform testing of React application?

Assuming that we have cleaned up our folder structure, we can start testing our component. Below is the example of tested component.

src 
|  
 - components 
  | 
  |- __tests__ 
  | | 
  |  -todo.tests.js 
  | 
   - todo.js

To implement our code, I have created ‘App.js’ and ‘todo.js’ files. App.js file includes there an array of ‘todos’ actions, which is mapped through and using prop drilling, displayed in declared hierarchy.

You can see that below:

import './App.css'; 
import Todo from './components/todo';
function App() { 
  const todos = [ 
    { id: 1, description: 'learn javascript testing', completed: false }, 
    { id: 2, description: 'go to the gym', completed: true }, 
    { id: 3, description: 'clean the house', completed: true }, 
  ];
return ( 
    <div className="App"> 
      {todos.map((todo) => { 
        return <Todo todo={todo} />; 
      })} 
    </div> 
  ); 
}
export default App;

Todo.js file looks like below:

import React from 'react';
function Todo({ todo }) { 
  return ( 
    <div data-testid={`Nr-${todo?.id}`}> 
      <h1>{todo?.description}</h1> 
    </div> 
  ); 
}
export default Todo;

Using prop drilling, each action of todos array (todo variable) is transferred to main div. We will be focused on that ‘data-testid’ in next paragraph.

Our goal is to test a “todo” component, which indicates what we have done or not. ‘Todo.js’ is placed in ‘components’ folder. Moreover, there is a special folder ‘__tests__’, which contains ‘todo.tests.js’ file, responsible for testing our component.

Ok, now we can go through the fundamental part of testing.

npm i --save-dev @testing-library/react react-test-renderer

Firstly, install needed dependencies. In this case, we will use react testing library which supports every react application.

Let’s go to the terminal once again and start test by running a following command.

npm run test

It will launch tests in your terminal.

Now let’s go to ‘todo.test.js’ file.

import { render, screen, cleanup } from '@testing-library/react'; 
import Todo from '../todo';
afterEach(() => { 
  cleanup(); 
});
test('should render component', () => { 
  const todo = { 
    id: 1, 
    description: 'learn javascript testing', 
    completed: false, 
  }; 
  render(<Todo todo={todo} />); 
  const todoElement = screen.getByTestId('Nr-1'); 
  expect(todoElement).toBeInTheDocument(); 
  expect(todoElement).toHaveTextContent('learn javascript testing'); 
});

This piece of code firstly, imports our component and needed library. Then, after each test, cleans everything up, using the following lines of code:

import { render, screen, cleanup } from '@testing-library/react'; 
import Todo from '../todo'; 
import renderer from 'react-test-renderer';
afterEach(() => { 
  cleanup(); 
});

Next part is responsible for the proper test. We will check if in our component is a ‘todo’ with text content ‘learn javascript testing’.

To perform that, we need to declare ‘const todo’ (one of the todos) which we test, and then render our tested component ‘<Todo/>’. To go through getting test id, it is necessary to name proper html element in tested component. Let’s go to file ‘todo.js’.

import React from 'react';
function Todo({ todo }) { 
  return ( 
    <div data-testid={`Nr-${todo?.id}`}> 
      <h1>{todo?.description}</h1> 
    </div> 
  ); 
}
export default Todo;

You can see a new variable in our div element. You can find a ‘data-testid’ which is equal to the id of todo record.

After each save of an app, in the terminal we can see the output of performed testing.

For this lines of code the output looks like this:

PASS  src/components/__tests__/todo.tests.js (9.656 s) 
  √ should render component (84 ms)
Test Suites: 1 passed, 1 total 
Tests:       1 passed, 1 total 
Snapshots:   0 total 
Time:        26.342 s 
Ran all test suites related to changed files.
Watch Usage: Press w to show more.

If we change our tested Text Content, the test will catch an error immediately. Let’s do that…

In ‘todo.tests.js’ file the ‘learn javaScript testing’ phrase will be changed to ‘read a book’.

import { render, screen, cleanup } from '@testing-library/react'; 
import Todo from '../todo';
afterEach(() => { 
  cleanup(); 
});
test('should render component', () => { 
  const todo = { 
    id: 1, 
    description: 'learn javascript testing', 
    completed: false, 
  }; 
  render(<Todo todo={todo} />); 
  const todoElement = screen.getByTestId('Nr-1'); 
  expect(todoElement).toBeInTheDocument(); 
  expect(todoElement).toHaveTextContent('read a book'); 
});

The result is shown below.

FAIL  src/components/__tests__/todo.tests.js (6.535 s) 
  × should render component (58 ms)
● should render component
expect(element).toHaveTextContent()
Expected element to have text content: 
      read a book 
    Received: 
      learn javascript testing
15 |   const todoElement = screen.getByTestId('Nr-1'); 
      16 |   expect(todoElement).toBeInTheDocument(); 
    > 17 |   expect(todoElement).toHaveTextContent('read a book'); 
         |                       ^ 
      18 | }); 
      19 |
at Object.<anonymous> (src/components/__tests__/todo.tests.js:17:23)
Test Suites: 1 failed, 1 total 
Tests:       1 failed, 1 total 
Snapshots:   0 total 
Time:        10.945 s 
Ran all test suites related to changed files.
Watch Usage: Press w to show more.

Conclusion

This is the simplest way of using tests in react app. We only performed one test which checks the text content. The truth is that tests can check pretty every aspect of your app. If you learn javaScript, reserve few days for learning how to write simple tests and definitely implement it in every project!.

Happy coding!