"In Jest, there is truth" -William Shakespeare.
By using Jest, you will know the truth about your application. The Jest
is a javascript testing tool that is installed via NPM or Yarn and run via the command line. It is a great testing library and many react team members are involved building it, so it happens to work very well for testing react applications. Jest is built on top of Jasmine and Mocha but some additional features like snapshot testing and parallel test execution are provided by Jest. It also comes with built-in mocking and assertion abilities.
Puppeteer is a Node library that is used for browser automation. Puppeteer provides a high-level API to control the browser. It can work with Chrome, Chromium, or Firefox. By default, this library runs the browser in headless mode, but it can be also configured to run Chrome or Chromium fully (non-headless).
Installation And Requirements
This guide is based on Ubuntu 18.04. Some commands will be different if you have another OS installed on your computer. Before getting started with Jest, You need to have npm
and an app for which you will be writing tests.
If your app is not yet ready for testing then you can just clone this basic todo app and follow along.
Jest Versions
Jest is the test runner library for creating, executing, and structuring tests. Jest CLI is a tool that you use from the command line to run and provide configuration options to jest. It configures jest based on whatever argument you give while running jest. The version is important because jest is a dynamic library and different versions of jest might work differently. While writing this blog, I am using jest version 24.9.0
. So, some features might be different if you are using some other version.
Jest installation and Running Tests
You can install the latest version of jest from NPM using
npm i jest --save-dev
Now, its time to configure the NPM script for running a test from the command line. For this, open your package.json
and add the test
script as follows:
"scripts": {
"test": "jest"
},
Tests are run by using the Jest CLI (typing jest
followed by arguments in the command line).
For example, in the todo app in my GitHub, you can run the test with the command npm run test
since I have added "test": "jest"
in the script of my package.json
With the above-mentioned way, jest can be configured within your package.json
. That is the easy way for jest configuration. Alternatively, you can also use the jest configuration file for which you should create a jest.config.js
file and include that file in the command to run the test. For example, your package.json scripts section should include
"scripts": {
"test": "jest --config ./jest.config.js"
},
And, in the root path alongside the package.json, your jest.config.js
should contain the following configurations
module.exports = {
verbose: true,
roots: [
"./__tests__"
]
}
By using the jest configuration file, you have many other options as well. You can find the details about that in the jest documentation. However, in this blog, I will focus on configuring jest using the package.json
Install Puppeteer
Use the following command to install puppeteer in your project.
npm i puppeteer --save-dev
Puppeteer will download the latest version of chrome. If you need to work with firefox then you need to install the puppeteer-firefox
library. Refer to Puppeteer for Firefox in the npmjs website for further details.
By the end of the installation of jest and puppeteer, you should have the following dependencies in the devDependencies
section of your package.json
.
"devDependencies": {
"jest": "^24.9.0",
"puppeteer": "^4.0.1"
}
Creating Test Files
The jest command runs the test files inside __tests__
folder or it will run any files with .spec.js
or .test.js
in their filename. So, you have to write your test in a file that ends with .spec.js
or test.js
. Or you can simply put all your tests inside the __tests__
folder.
Jest Globals
There are varieties of jest Globals but we will mainly need 2 important globals called describe
and it
. The table below tells about these two globals in more detail.
it | describe | |
---|---|---|
AKA | Tests | Test Suite |
Syntax | it(name, fn) | describe(name, fn) |
Description |
it() global is a method in which you pass a function as an argument, that function is executed as a block of tests by the test runner. You describe your test logic inside it() block. |
describe is an optional method for grouping any number of it() or test statements. describe() block contains related it blocks. |
In addition to it()
and describe()
methods, you might need the following methods to start testing with jest.
- afterAll(fn, timeout)
- afterEach(fn, timeout)
- beforeAll(fn, timeout)
- beforeEach(fn, timeout)
These functions are executed before and after the test scenarios. You can define these functions inside the describe()
method to make it applicable for all tests in the scope of that particular describe()
method.
Demo:
Here I have added a test for adding a task in my react ToDo app.
const puppeteer = require('puppeteer');
describe('Todo React', () => {
let browser
let page
beforeAll(async () => {
browser = await puppeteer.launch()
})
afterEach(async () => {
await page.close()
})
afterAll(async () => {
await browser.close()
})
describe('add task to the list', () => {
beforeEach(async () => {
page = await browser.newPage()
await page.goto('http://localhost:3000')
})
it('should be possible to add task to the list', async () => {
const taskInputField = await page.$x('//input[@placeholder="Enter task"]')
const taskToAdd = "New Task"
await taskInputField[0].click()
await taskInputField[0].type(taskToAdd)
await page.keyboard.press('Enter')
const lists = await page.$x("//div[@class='list']/p/input");
let toDo;
for( let list of lists ) {
toDo = await page.evaluate(el => el.getAttribute("value"), list);
}
expect(toDo).toBe(taskToAdd)
})
})
})
Explanation of Demo
In the above demo, I first imported the puppeteer library. And in before scenario, I launched the browser in headless mode. Before all the scenarios inside the first describe block, the browser is launched only once. And before each scenario, a new tab is opened in incognito mode. Similarly, after each scenario, the tab is closed and when all the scenarios are executed, the browser is closed.
The browser is launched in headless mode by default. However, if you want to launch the browser in non-headless mode then you can provide the browser launch option in puppeteer.launch()
. For example:
browser = await puppeteer.launch({headless:false})
In Jest, there are plenty of functions to simulate UI activities. For example, in the above demo, you can see click()
for clicking in an element, type()
for typing, etc.
Similarly, for assert operation, you can use expect()
. Many other matcher functions can be used with expect() such as .toContain(item)
, toBeTruthy()
etc. You can find more of these jest matchers
in the jest documentation.
Gherkin with Jest
In Jest, you do not have to write a feature file for your test cases. If you need to write features in a separate file then you can use jest-cucumber library. By using this library, you can replace describe
and it
blocks by Given
, When
, and Then
step definitions. The step definitions are linked with the respective steps in the feature files.
However, I would prefer Codecept.js
or nightwatch.js
instead of jest
if I need to use features of Cucumber.js
while testing my application. Because, with jest-cucumber, you need to specify which feature file is linked with a particular step definition file. While Codecept.js or nightwatch.js, you can write the step definition of a given
step in one file and the when
step of the same scenario in some other file. You might lose this kind of freedom if you are using jest-cucumber.
That's it for now. If you want to learn more about jest and it's commands, you can refer to jestjs.io
Hope you enjoy jesting.
ThankYou!
Top comments (1)
Thank you for this article, I was actually going to check both of these tools.