FE Unit Testing With Jest - Best Practices

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 29

Best practices document

Front End Unit Test with Jest


Logística - Comercial
27/04/2021
Table of contents

Scope and assumption .................................................................... 5

Why is unit testing inportant ........................................................... 5

Jest.................................................................................................... 6

Why Jest ........................................................................................... 6

Code coverage ............................................................................................. 6

Easy mocking ............................................................................................... 7

Great exceptions .......................................................................................... 7

toBe.......................................................................................................... 7

toBeCloseTo ............................................................................................ 8

toEqual ..................................................................................................... 8

toStrictEqual ............................................................................................. 9

toHaveProperty ........................................................................................ 9

toMatchSnapshot ................................................................................... 10

toThrowError .......................................................................................... 10

Getting started ............................................................................... 11

Best practices ................................................................................ 14

Test structure ............................................................................................. 14

Test file naming.......................................................................................... 14

Test naming ................................................................................................ 14

Assertions .................................................................................................. 16

toBe........................................................................................................ 16

toEqual ................................................................................................... 16

Front End Unit Test with Jest page 2 of 29


toMatchObject ........................................................................................ 16

not.toBe.................................................................................................. 17

Mocking ...................................................................................................... 17

Using a mock function .............................................................................. 17

Using a manual mock ................................................................................ 18

Other common mock functions ................................................................ 20

jest.spyOn .............................................................................................. 20

mockFn.mockReturnValue ..................................................................... 21

mockFn.mockReturnValueOnce ............................................................ 21

mockFn.mockResolvedValue ................................................................. 21

mockFn.mockResolvedValueOnce ........................................................ 22

mockFn.mockRejectedValue ................................................................. 22

mockFn.mockRejectedValueOnce ......................................................... 23

Example of snapshot testing ............................................................................ 23

Final tips and recomendations ......................................................................... 25

Create a new test for each new bug ......................................................... 25

Don't write tests for long and complex workflows.................................. 25

Don't write snapshot tests for all components ....................................... 25

Kill your mutations .................................................................................... 25

Validate if your mocked function have been called ................................ 25

.toHaveBeenCalled ................................................................................ 25

.toHaveBeenCalledTimes ...................................................................... 26

.toHaveBeenCalledWith ......................................................................... 26

How to render properly ............................................................................. 27

Front End Unit Test with Jest page 3 of 29


shallow ................................................................................................... 27

mount ..................................................................................................... 27

Front End Unit Test with Jest page 4 of 29


Scope and assumption
Although this document has a couple of examples and tips for the most common use
cases in Jest, this is not a guideline, it’s a best practices document therefore,
readers of this document should have knowledge in unit testing and should have
knowledge about the tool.

Why is unit testing important?


The use of unit testing helps to find and fix bugs in the code early in the development
cycle, which means efficiency and costs reduction. Sometimes developers think that
they can save time doing minimal unit testing, but this is wrong because it harder in
terms of time and costs to solve a bug found in the integration and UI testing stages.

Front End Unit Test with Jest page 5 of 29


Jest
Jest is a testing framework for JavaScript and TypeScript that works with node projects
based on React, Angular, Vue, Express among others.

Why Jest?

 Code coverage
Generate code coverage by adding the flag --coverage. No additional setup needed.
Jest can collect code coverage information from entire projects, including untested
files.

Front End Unit Test with Jest page 6 of 29


 Easy mocking
Jest uses a custom resolver for imports in your tests, making it simple to mock any
object outside of your test’s scope. You can use mocked imports with the rich Mock
Functions API to spy on function calls with readable test syntax.

 Great exceptions
Tests fail—when they do, Jest provides rich context why. Here are some examples:
toBe

Front End Unit Test with Jest page 7 of 29


toBeCloseTo

toEqual

Front End Unit Test with Jest page 8 of 29


toStrictEqual

toHaveProperty

Front End Unit Test with Jest page 9 of 29


toMatchSnapshot

toThrowError

Front End Unit Test with Jest page 10 of 29


Getting started
If you we are using the archetype from commercial, in our main/config folder we
can find the jest.config.js file otherwise, if we are using the default archetype from
amiga, we probably won’t find this file so, we can generate it by running the
command “amg eject build” and it’ll generates this file, so we can configure it
according to the project needs:

Front End Unit Test with Jest page 11 of 29


Jest supports Typescript with our default configuration, with the above command we
can also generate the babel.config.js and we can find it the config folder like this:

Front End Unit Test with Jest page 12 of 29


As you can see in the screenshot below, we used a base config from amiga-
tools/config module, please let’s use the amiga configurations as much as we can,
we can also use our own config if needed

In our package.json file we need to add the following commands on the scripts
section

Front End Unit Test with Jest page 13 of 29


Best practices
Test structure
The test file (artifact-info.test.js) should be placed into a test folder for each module
folder at the same level of the module we want to test (index.tsx)

Test file naming


The correct naming of the test file should follow the following syntax: <module
name>.test.js it is necessary to use test or spec word because in that way Jest will
find all the test files in the project regardless of where they are placed.

Test naming
It is important to know that a test report can be reviewed by many team members that
don’t need to know exactly how the code is implemented for example a QA Engineer,
a DevOps Engineer, even for the developer in the future, for this reason, we need to
ask ourselves three questions when we want to name a test:

1. What we are going to test?


For our example we are going to test the artifact-info module, so we can start with
Artifact Info (line 5) in the title for the global describe instance.

Front End Unit Test with Jest page 14 of 29


2. Under what circumstances and scenario?
In order to test that our artifact-info renders correctly we need to set some parameters
to the modal, so in our test instance we can say: When setting modal with valid
parameters (line 6)

3. Which will be the expected result?


Finally, we expect that our modal renders correctly or not, so in our test instance we
can finish with then the modal should renders correctly
And of course, don’t forget the AAA pattern (Arrange, Act and Assert)
Arrange: In this section you only have code required to setup that specific test. Here
objects would be created, mocks setup (if you are using one) and potentially
expectations would be set.
Act: This section should be the invocation of the method being tested
Assert: In this section you would simply check whether the expectations were met.
Therefore, following our naming best practices our result should be as follows

Front End Unit Test with Jest page 15 of 29


That way if our test fails, we can know easily what is failing in our code

Assertions
Jest use matchers to make the assertions in different ways, the following are the most
common matchers that you can use in your tests.

toBe
Recommended for matching numbers. If you want to simply test that 4 - 2 is 2 with
exact equality, we can do something like this:

toEqual
Recommended for matching strings. If we want to check the value of a string, we can
do something like this:

toMatchObject
Recommended for matching objects. If you want to check a value of an object you can
do something like this:

Front End Unit Test with Jest page 16 of 29


not.toBe
If we want to test the opposite of a matcher, we can do something like this:

For more information about this topic please take a look at the Jest Matchers
documentation.

Mocking
There are two ways to mock functions: Either by creating a mock function to use in
test code, or writing a manual mock to override a module dependency.

Using a mock function


Let's imagine we're testing an implementation of a function forEach(), which invokes
a callback for each item in a supplied array.

To test this function, we can use a mock function, and inspect the mock's state to
ensure the callback is invoked as expected.

Front End Unit Test with Jest page 17 of 29


Using a manual mock
On the following example we have a module that uses 3 external components
<DComPopover> (line 75), <DComDescriptionButton> (line 84) and <DComIcon>
(line 90)

Front End Unit Test with Jest page 18 of 29


As we need to use those components, in order to test this module, we need to create
a manual mock for these components in our test file (lines 5 to 10):

Front End Unit Test with Jest page 19 of 29


Other common mock functions
Jest.spyOn()
Due to we are testing react components, in some cases, we need to use external
libraries that are not in the environment, so we can’t mock those as external modules.
For example, the window object from WebDriver. In these cases, we need to use
jest.spyOn() In the following example we need to use the setInterval (line 28) and
clearInterval (line 39) methods from window object, so the test should be as follows:

Front End Unit Test with Jest page 20 of 29


mockFn.mockReturnValue(value)

mockFn.mockReturnValueOnce(value)

mockFn.mockResolvedValue(value)

Front End Unit Test with Jest page 21 of 29


mockFn.mockResolvedValueOnce(value)

mockFn.mockRejectedValue(value)

Front End Unit Test with Jest page 22 of 29


mockFn.mockRejectedValueOnce(value)

Example of snapshot testing


On the following test we are going to verify the correct renderized of the home page
module for our CPLAYWEB, the following is the home page.

Then in our test file we use the shallow function from amiga-tools/testing module in
order to render our JSX.Element and the test should be as follows

Front End Unit Test with Jest page 23 of 29


After running the test, it will mention on the console that we have a snapshot

And will create a folder __snapshots__ into the test folder with the snapshot of the
rendered object

Front End Unit Test with Jest page 24 of 29


Final tips and recommendations

Create a new test for each new bug


After we fix a bug, we can create a test for this functionality that fails, doing this we
can ensure that this bug will never happen in the same way

Don’t write tests for long and complex workflows


All those workflows like submitting data or filling forms need to be tested by integration
or e2e testing.

Don’t write snapshot tests for all components


Please make snapshot tests only for key components that we need to know if
something changes or those that don’t change a lot because it could be difficult to
maintain those kinds of tests.

Kill your mutations


One of the best ways to know if your unit tests are robust enough, is to run the mutation
testing for each module tested, that way if your mutations survived that means that
you need to add more assertions or your tests need to be refactored.

Validate if your mocked functions have been called


Besides the matchers already written on this document it is important to use other
matchers if you are testing mocked functions the most common are:

.toHaveBeenCalled() or .toBeCalled()
It’s used to ensure that a mock function got called.
For example, let's say you have a drinkAll(drink, flavor) function that takes a drink
function and applies it to all available beverages. You might want to check that drink
gets called for 'lemon', but not for 'octopus', because 'octopus' flavor is really weird
and why would anything be octopus-flavored? You can do that with this test suite:

Front End Unit Test with Jest page 25 of 29


.toHaveBeenCalledTimes(number) or .toBeCalledTimes(number)
It’s used to ensure that a mock function got called exact number of times.
For example, let's say you have a drinkEach(drink, Array<flavor>) function that takes
a drink function and applies it to array of passed beverages. You might want to check
that drink function was called exact number of times. You can do that with this test
suite:

.toHaveBeenCalledWith(arg1, arg2, ...) or .toBeCalledWith()


It’s used to ensure that a mock function was called with specific arguments.
For example, let's say that you can register a beverage with a register function, and
applyToAll(f) should apply the function f to all registered beverages. To make sure this
works, you could write:

Front End Unit Test with Jest page 26 of 29


How to render properly
shallow()
It allows to test the component as a unit without dependency of parents or child
components it’s the most common, easiest and fastest for unit testing it also not
requires an external dependency like DOM to render the component because
everything can be managed for enzyme directly.
mount()
It can render child components but needs the JSDOM dependency to render the full
DOM it’s not recommended to use if you don´t need to render the full component
because it’s going to take more time. It's recommended if we need to test user
interactions (events)

Front End Unit Test with Jest page 27 of 29


On the following example we are going to render a basic component and we will see
the differences between shallow() and mount()
The component

The test with shallow() The test with mount()

The rendered component The rendered component

Front End Unit Test with Jest page 28 of 29


As you see on the tests above, we use debug() method (line 10) to see on the console
how the component was rendered it is a useful tool to see how we are rendering the
components. If we are using VSCode we also can use the Jest Runner plugin to run
and debug our tests.

Front End Unit Test with Jest page 29 of 29

You might also like