Discover the Basics of Testing in React With Jest

Use Automated Testing in ReactĀ 

Tests are an integral part of any developer’s job (even front end) regardless of the language you develop in. They ensure theĀ reliabilityĀ of your code.Ā 

What Are Tests For?

Writing tests takesĀ timeĀ andĀ consideration. But count yourself lucky – over the past few years, tools have appeared to make testing JS easier. Again, when you’re working alone coding a small application, it seems like a lot of work for little reward, but try to think bigger. ✨

When you’re working on a codebase withĀ various featuresĀ asĀ part of a team, it’s easy to make a change that leads to aĀ regressionĀ (the introduction of a bug in production), especially when you’re dealing with code that you didn’t write, and you’re not familiar with. In situations like this, it’s good toĀ rely on testsĀ to flag errors! As a result, you’llĀ avoid regressionsĀ and beĀ more confident with your modifications.Ā Ā 

Test is a small word for a vast topic because there are several different types of them.

Discover Different Types of Test

šŸ¤“ What type of test should I run?Ā 

As you can see, the main types are unit, integration, and end-to-end testing.Ā 

That’s not to say that you should completely abandon unit and end-to-end testing: it’s important to find a happy medium between the three types. For example, you might choose to implement end-to-end testing for specific, critical features of your application.Ā 

Time to get to work! šŸ‘©ā€šŸ’»

Create Your First Test With JestĀ 

Like everything with JavaScript, the testing ecosystem is quick to evolve. So here, we’ll be usingĀ JestĀ andĀ React Testing Library.

For many years, Jest has stood out as one of the best-regarded tools for testing, and it even comes ready-installed with Create React App. Not a bad place to start. šŸš€

On the other hand, React Testing Library provides access to even more tools for testing your components. We’ll look at this in the following two chapters.

If you’re wondering how the two fit together, imagine that Jest is the basic testing tool, and React Testing Library makes component testing easier.

Dive into the world of testing with a Jest example in the screencast belowšŸ‘‡:

Let’s begin by writing a unit test.

Prepare Your Code

To test code independently, pull out a part of your logic on theĀ Ā /Results/index.jsxĀ page and do the following function:

export function formatJobList(title, listLength, index) {
   if (index === listLength - 1) {
      return title
   }
   return `${title},`
}

And put this into JSX:

<ResultsTitle theme={theme}>
   The skills you need:
   {resultsData &&
      resultsData.map((result, index) => (
         <JobTitle
            key={`result-title-${index}-${result.title}`}
            theme={theme}
         >
            {formatJobList(result.title, resultsData.length, index)}
         </JobTitle>
      ))}

</ResultsTitle>

TimeĀ to run a test!

Create Your Test File

Throughout this course, you learned how to organize files into folders with a specific name and an Ā index.jsxĀ  file. This filing method will be useful here because it lets youĀ place tests directly at the file root.Ā 

Start with Ā /ResultsĀ  , create an Ā index.test.jsĀ  file, and job done!

But how will Jest find the test file?

Don’t worry! Jest is configured to search all subfolders (except forĀ  Ā node_modulesĀ  andĀ  Ā .git )Ā  for files ending with Ā spec.jsĀ  orĀ  Ā test.jsĀ  , preceded by a hyphen (Ā  -Ā  ) or a dot (Ā  .Ā  ).Ā  Another option is to put your tests into a Ā __tests__Ā  folder.

How to Write Tests

Now let’s look at writing the test.

First,Ā import the element that needs testing, and then use testĀ  .

We’re using Ā testĀ  , but we haven’t imported it anywhere. Why isn’t this an error?

Well, test is a tool that you can access globally in a file, thanks to Jest. Learn about other global tools in Jest’s documentation.

To see if the test works, import the function inĀ Results/results.test.jsĀ  and prepare the test:

import { formatJobList } from './'

test('This is my first test', () => {})

Notice that Ā test()Ā  takes a Ā stringĀ  as its first Ā argumentĀ  , and then a function as its second argument.

Let’s try to launch the commandĀ  yarnĀ  runĀ  testĀ  Ā in terminal.

No files found
No files found

That’s completely normal. We didn't write the core of the test, i.e. to run the function and compare with a reference.

For this test, let’s useĀ expectĀ andĀ toEqualĀ  , which isĀ a JestĀ ā€œmatcher.ā€ Use theĀ expect()Ā  function, which will compare an element withĀ the matcher. This means you have to know what you want to get from Ā formatJobListĀ  .

For example, takeĀ Ā item2Ā  , which will be the second item on the list (its index is 1), but won’t be the last, meaning that you want the title to add a comma.

Which gives you:

import { formatJobList } from './'

test('This is my first test', () => {
   const expectedState = 'item2,'
   expect(JobTitle('item2', 3, 1)).toEqual(expectedState)
})

Save, and then the tests will run automatically (unless you quitĀ  Ā watchĀ  mode). It’s green! Yay! šŸŽ‰

screenshot of the successful test
The first test passed!

Not so hard, was it?

Other functions exist, such as Ā describe()Ā  .

DescribeĀ lets you group several related tests (you can choose the link) and displays everything in a more readable way when you run your tests. In our example, you could add a test to check that your function does not put a comma on the final item:Ā 

import { formatJobList } from './'

describe('The function formatJobList, () => {
   test('add a comma to an item', () => {
      const expectedState = 'item2,'
      expect(formatJobList('item2', 3, 1)).toEqual(expectedState)
   })
   test('does not add a comma to the last element', () => {
      const expectedState = 'item3'
      expect(formatJobList('item3', 3, 2)).toEqual(expectedState)
   })
})

Resulting in:

Both tests work
Both tests work!

Much easier to read, isn’t it? šŸ‘€

Like with everything, conventions apply when writing tests to make them as explicit as possible. One option is startingĀ them with ā€œshould.ā€ Here, it’s even more explicit to use the alias Ā itĀ ,Ā  which would look like this:Ā 

import { formatJobList } from './'

describe('The formatJobList function', () => {
   it('should add a comma to a word', () => {
      const expectedState = 'item2,'
      expect(formatJobList('item2', 3, 1)).toEqual(expectedState)
   })
   
   it('should not add a comma to the last element of the list', () => {
      const expectedState = 'item3'
      expect(formatJobList('item3', 3, 2)).toEqual(expectedState)
   })
})

Ensure You Have Ideal Code Coverage

When running tests, you can measureĀ code coverageĀ (the percentage of code covered by tests). You can then identify the untested parts (or insufficiently tested) and work out where to focus your next efforts.Ā 

Here's the command for checking code coverage.

For this, writeĀ  Ā yarn test -- --coverageĀ  .

Test coverage is displayed in table form on the terminal
Test coverage is displayed in table form on the terminal

You now have the details of your test coverage, including the lines not covered by your tests.

Some services let you use test coverage as a criterion for blocking the integration of new code to your projects, setting a minimum rate, or preventing lowering the existing rate for allowing a pull request to be merged into the destination branch.

It can be very satisfying to increase your code coverage to the maximum. Be careful, though—it can be tricky. You might waste time trying to get to 100% coverage, which is unnecessary. You should be maintaining your tests over time, with the same logic in mind. Another point to be aware of is that coverage does not consider your tests’ relevance. Don’t go into it blind!Ā  šŸ™ˆ

Give It a Go!

For this exercise, you’re going to continue testing Ā pages/results/index.jsxĀ  with the function Ā formatQueryParamsĀ  . As usual, you’ll find the codebase you need for this exercise on branchĀ P3C1-begin.

Create two different tests for Ā formatQueryParamsĀ  within a series of tests (grouped together in Ā describe()Ā  ).

You can find the solution on branch P3C1-solution.

Let’s Recap!

  • Tests provide security when modifying a codebase, especially when you integrate them into continuous deployment practices.

  • The main types of testing are unit, integration, and end-to-end testing.Ā 

  • Integration testing is a good compromise between the time spent writing tests and the security they provide.Ā 

  • Jest and React Testing Library give developers access to a set of tools and functions that can be used to test an application.Ā 

Tests might seem scary, but they’re not that bad, are they? Nothing impossible so far? Great—let's continue your testing journey in the next chapter, where you’ll learn how to use React Testing Library to test your components. šŸ’£

See you there!

Ever considered an OpenClassrooms diploma?
  • Up to 100% of your training program funded
  • Flexible start date
  • Career-focused projects
  • Individual mentoring
Find the training program and funding option that suits you best