Testing is essential
Let’s say you start writing a new application, you participate throughout the project and know everything about the application you are working on. So why should you write tests about what you already know?
The larger your codebase is, the harder it is to maintain it. At some point you’ll add new features to the app. After that you have to start debugging, modify your existing code and hopefully won’t affect any other features. The problem is, you work with other developers, when you change old features or add new ones. Are you sure that what you do doesn’t affect the other features?
The solution to this problem is to write tests.
Benefits of writing tests:
- Refactor the code without affecting other feature, because the test will error when something goes wrong.
- Create new features easily.
- Spend less time manually testing the application.
In this article, we’ll take a look at a powerful tool for writing tests for JavaScript applications: Jest .
Introducing Jest
Jest is an all-in-one JavaScript testing tool built by Facebook. Why all-in-one ?, Because with Jest only, you can do all of the following:
- Run the test safely and quickly.
- Make sure your code is correct
- Mock function, modules
- Add the scope of code
- Snapshot testing
- and more
Setting
We add the package to the project:
npm install --save-dev jest \ of yarn add --save-dev jest
Then add the test script to package.json :
{ "scripts": { "test": "jest" } }
Running jest by default will find and run the file in the tests folder and have the extension * .spec.js * or .test.js
The structure of the test file
The structure of a test file:
- describe : used to group test cases and describe the behavior of functions / modules / class. It takes two parameters, the first one describing your group and having the data type string. The second parameter is a function callback in which you have test cases or hook functions.
- it , test : this is your test case, your test unit. It must be described, and the parameters must be exactly as described .
- beforeAll ( afterAll ): The hook function runs before (after) all tests. It takes one parameter and your function runs before (after) all tests.
- beforeEach ( afterEach ): The hook function runs before (after) each test. It takes one parameter, and your function runs before (after) each test.
Notes
- the beforeAll , beforeEach : and other hook functions are called as such because they allow you to call your own code and modify the actions of tests.
- You can skip the test using .skip in the describe and it : describe.skip (…) or it.skip (…) .
- You can run the specific test you want using .only in describe or it : describe.only (… ) or it.only (…) .
Matchers
When you write tests, you often need to make sure your code is correct. For example, you will see an error appear on the screen if a user provides the wrong password on the login screen. More generally, to make an assertion, you need an expected input and output. Jest allows us to do that easily by providing matchers tools to test our values:
expect(input).matcher(output)
Here are the common functions:
- toBe : compare primitive values (boolean, number, string) or references of objects and arrays:
xpect (1 + 1) .toBe (2)
const firstName = ‘Thomas’ const lastName = ‘Lombart’ expect ( ${firstName} ${lastName}
) .toBe (‘Thomas Lombart’)
const testsAreEssential = true expect (testsAreEssential) .toBe (true)
- isEqual : Compares all properties of objects, arrays:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | const fruits = ['banana', 'kiwi', 'strawberry'] const sameFruits = ['banana', 'kiwi', 'strawberry'] expect(fruits).toEqual(sameFruits) // Oops error! They don't have the same reference expect(fruits).toBe(sameFruits) const event = { title: 'My super event', description: 'Join me in this event!', } expect({ ...event, city: 'London' }).toEqual({ title: 'My super event', description: 'Join me in this event!', city: 'London', }) |
- toBeTruthy ( toBeFalsy ): checks for true or false :
expect (null) .toBeFalsy () expect (undefined) .toBeFalsy () expect (false) .toBeFalsy ()
expect ('Hello world'). toBeTruthy () expect ({foo: 'bar'}). toBeTruthy ()
- not : must be placed before a matcher and return the opposite result of the matcher :
1 2 3 4 5 | expect(null).not.toBeTruthy() // same as expect(null).toBeFalsy() expect([1]).not.toEqual([2]) |
- toContain : checks the array containing the parameter passed.
1 2 | expect(['Apple', 'Banana', 'Strawberry']).toContain('Apple') |
- toThrow : checks if the function fires an error:
1 2 3 4 5 6 | function connect() { throw new ConnectionError() } expect(connect).toThrow(ConnectionError) |
You can find out more details on jest docs
Jest CLI
Now that we’ve looked at the structure of the test file and the tools provided by Jest, let’s see how we can use its CLI to run the test:
Run the test
Now let’s assume you want to run specific tests, Jest allows you to do so with the -t option. For example, consider the following two test groups:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // calculator.test.js describe('calculator', () => { it('adds two numbers', () => { expect(2 + 2).toBe(4) }) it('substracts two numbers', () => { expect(2 - 2).toBe(0) }) it('computes something', () => { expect(2 * 2).toBe(4) }) }) // example.test.js describe('example', () => { it('does something', () => { expect(foo()).toEqual('bar') }) it('does another thing', () => { const firstName = 'John' const lastName = 'Doe' expect(`${firstName} ${lastName}`).toBe('John Doe') }) }) |
Run it with the command: jest -t numbers
Jest will run the first two test cases of Calculator.test.js but will ignore the rest.
Watch mode
Then what I think is, Jest’s most handy option: watch mode , which keeps track of files for changes and rerun the test cases related to them. To run it, you just need to use the –watch option:
jest --watch
Note : Jest knows which files have been modified with Git . So you have to enable git in your project to use that feature.
Coverage
Let’s take a look at one last option to show you how powerful Jest is: collect test scope, ie measure the amount of code covered by a test suite at runtime. This metric can be useful for ensuring your code is properly covered by your test cases. To use it, run the following command:
jest --coverage
continue(…)