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.Ā
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.
š¤ 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! š©āš»
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.
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!
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.
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.

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! š

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:

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)
})
})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Ā .

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!Ā š

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.
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!