banner image 1 banner image 2

An Insight to Jest

February 22, 2022
7 mins
command
blog-img 1
Dharshinisivakumar
Author

A guide on what Jest is, why we need it and how to implement it

By Dharshinisivakumar, a social butterfly!


Jest — Delightful JavaScript Testing

Unit testing is an integral part of Test Driven Development (TDD) where we define the actions of a function and its expected result even before working on the actual function!

Why TDD ?

The most common question in mind!

My code works fine without TDD, then why?

There are some hidden perks of incorporating TDD into our development process

  1. Detects software bugs early!

2. TDD stands by the proverb Time is precious , thus saves the development time.

3. Definitely improves the quality of code.

Guess you have changed your mind now ! Let’s get into knowing about jest.

What is jest?

Every programming language has its own framework for unit tests. For JavaScript , Jest is one of the widely used testing frameworks, maintained by Facebook, Inc. Jest is also known for its simplicity !

Samples with Jest

Let us assume that the following code is written in

addition.js

function add(a,b)
{
return a+b
}
module.exports = add

Test cases for the same are written in a file named addition.test.js for Jest to automatically pick it up.

addition.test.js

const addition = require(‘./addition’)
describe(“testing the sum of two numbers”,() =>
{
it(“pass”,() => {
const expectedOutput = 50;
expect(addition(25,25)).toEqual(expectedOutput);
})
it(“pass case 2”,()=>{
const wrongOutput = 511;
expect(addition(4,4)).not.toEqual(wrongOutput)
})
})

That was really simple isn’t it ?

Why jest?

1. The installation step in jest is pretty simple.

The installation can be done with either npm or yarn

  • yarn add — dev jest or
  • npm install — save-dev jest

2. Jest is fast. Very fast.

When your tests are CPU bound, it can save significant time from your test runs.

  • Tests that take 45 minutes with mocha, will take 14.5 minutes with Jest. As fast as lightning!

Why is jest so fast?

  1. Parallelization: this is pretty obvious, and other test frameworks use it too.
  2. Run slowest tests first: this ensures all cores are utilized to the max.
  3. Caching babel transforms: reduces CPU-intensive babel transforms.

3. Jest has awesome mocks! Mocking allows us to reduce irrelevant dependencies and reduces the lines of code and also makes the test cases run faster. We have discussed more about mocks later in this blog.

4. Jest does snapshot testing!

It lets you capture a string that represents your rendered component and store it in a file. Then you can compare it later to ensure that the UI didn’t change. If you actually change your UI then you need to update your snapshot files to reflect it of course.

5. Jest watches you all the time!

When you run your test cases with — watchAll command line argument. Jest can run in watch mode. Whenever your code is changed the test cases run automatically to test the new changes.

Jest has a rich mocking library which deserves a mention!

1. Simple Mock Functions

Unit tests and mocking are inseparable. If your code does operations on a file, calls remote service, access a database, it will be complicated to configure these in your tests. In such cases Mocks are our superheroes. We can replace the real dependency with mock function that does nothing but just records the fact it was called, so you can verify the workflow. The jest.fn() mock function lets you provide canned return values

Sample code

For a function like
function forEach(items, callback) {
for (let index = 0; index < items.length; index++) {
callback(items[index]);
}
}
Mock functions can be used
const mockCallback = jest.fn(x => 42 + x);
forEach([0, 1], mockCallback);
// The first argument of the first call to the function was 0
expect(mockCallback.mock.calls[0][0]).toBe(0);

2. Manual Module Mocks

Sometimes you may need to replace a whole module with its data rather than a couple of functions. Jest lets you do that by placing your own module with the same name in a __mocks__ sub-directory. The syntax of manual mock is jest.mock(moduleName, factory, options)

Whenever your code is using the target module, it will access your mock rather than the real module. You can even selectively choose for some tests to use the original module by calling jest.Unmock(‘moduleName’).

Sample code

Lets see an example of a module which provides the summary of all files in a directory

FileSummarizer.js

const fs = require(‘fs’);
function summarizeFilesInDirectorySync(directory) {
return fs.readdirSync(directory).map(fileName => ({
directory,
fileName,
}));
}
exports.summarizeFilesInDirectorySync = summarizeFilesInDirectorySync;

To prevent our tests from actually hitting the disk (that’s pretty slow), we will be creating a manual mock for the file system module by extending an automatic mock. Our manual mock will implement custom versions of the above APIs.

__mocks__/fs.js

const path = require(‘path’);
const fs = jest.createMockFromModule(‘fs’);
// This is a custom function that our tests can use during setup to specify
// what the files on the “mock” filesystem should look like when any of the
// `fs` APIs are used.
let mockFiles = Object.create(null);
function __setMockFiles(newMockFiles) {
mockFiles = Object.create(null);
for (const file in newMockFiles) {
const dir = path.dirname(file);
if (!mockFiles[dir]) {
mockFiles[dir] = [];
}
mockFiles[dir].push(path.basename(file));
}
}
// A custom version of `readdirSync` that reads from the special mocked out
// file list set via __setMockFiles
function readdirSync(directoryPath) {
return mockFiles[directoryPath] || [];
}
fs.__setMockFiles = __setMockFiles;
fs.readdirSync = readdirSync;
module.exports = fs;

Now the test comes into picture

FileSummarizer.test.js

jest.mock(‘fs’);
describe(‘listFilesInDirectorySync’, () => {
const MOCK_FILE_INFO = {
‘/path/to/file1.js’: ‘console.log(“file1 contents”);’,
‘/path/to/file2.txt’: ‘file2 contents’,
};
beforeEach(() => {
// Set up some mocked out file info before each test
require(‘fs’).__setMockFiles(MOCK_FILE_INFO);
});
test(‘includes all files in the directory in the summary’, () => {
const FileSummarizer = require(‘../FileSummarizer’);
const fileSummary =
FileSummarizer.summarizeFilesInDirectorySync(‘/path/to’);
expect(fileSummary.length).toBe(2);
});
});

In the above code the line

jest.mock(‘fs’);

instructs our tests to mock the fs module we have created.

3. Timer Mocks

Timing is the scourge of unit tests. What if you want to test code that times out after a minute? Code that fires every 30 seconds? Special code that runs an algorithm at the end of the month?

Those are difficult to test. You can either succumb to the timing requirements of the original code (and then your tests will be very slow), or you can manipulate time, which is much more useful. Jest lets you control the following timer-related functions:

  • setTimeout()
  • setInterval()
  • clearTimeout()
  • clearInterval()

Sample code

mainfile.js

function timerGame(callback) {
console.log(‘Ready….go!’);
setTimeout(() => {
console.log(“Time’s up — stop!”);
callback && callback();
}, 1000);
}
module.exports = timerGame;

mainfile.test.js

jest.useFakeTimers();
jest.spyOn(global, ‘setTimeout’);
test(‘waits 1 second before ending the game’, () => {
const timerGame = require(‘../timerGame’);
timerGame();
expect(setTimeout).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 1000);
});

In a nutshell, Jest is an entrancing testing framework with a simple installation procedure and an elegant testing approach and also it comes with a rich mocking library, which makes testing enjoyable and faster. Jest also helps in maximum code coverage. Most importantly jest creates a developer friendly environment for testing. To know more about this awesome testing tool, visit the official site.

Happy testing & jesting!


[embed]https://medium.com/@dharshinisivakumar373[/embed]
We at CaratLane are solving some of the most intriguing challenges to make our mark in the relatively uncharted omnichannel jewellery industry. If you are interested in tackling such obstacles, feel free to send in your updated resume/CV to careers@caratlane.com.
blog-img 2

Discussions

blog-img 3
5 mins
May 17, 2023
Sharing Data Between Controllers: Best Practices S...

This article will help you to understand the diffe

By Naveen C

blog-img 3
5 mins
March 21, 2023
Understanding Auto Layout and Constraints in Swift...

This article gives you an easy way of understandin

By Ramasamy P