Jest Framework Intro

abhinav bussa
4 min readApr 27, 2021

--

I believe everyone heard of the Jest unit testing framework and we will go through a few of the important terminology which will help to understand Jest and the usage for giving a head start.

Before going through this please have a look at the other story which gives you the background info on Unit testing, Jest, and its basic usage here.

We will cover the most basic and most used methods which will give you a kick start in writing unit tests.

Let's just see the template of how a test suite looks like. Each suite can have multiple test cases.

// all importsdescribe("Testing component name/description", () => {
beforeEach(() => {
// runs before each test case
})
afterEach(() => {
// runs after each test case
})
it("test 1 description", () => {
//test code
})
it("test 2description", () => {
//test code
})
})

The common terminology is mocking, so what is mocking. For example, let's consider you have a Nodejs Server that has an API that gets a list of cities and their weather info from an external source(fetch using API url), filter it according to country and total under each country.

Now if you want to unit test this part of code in the controller, we would generally call the controller method and test the returned data against the test data, but that would fail as the controller data from an external source will be dynamic and we can't rely on external API to test our piece of software, it has to work independently of the data. So this is where we use mocking.

The purpose of mocking is to isolate and focus on the code being tested and not on the behavior or state of external dependencies.

  1. Mock Functions

Mock functions allow you to test the links between code by erasing the actual implementation of a function, capturing calls to the function (and the parameters passed in those calls), capturing instances of constructor functions when instantiated with new, and allowing test-time configuration of return values

In simpler terms, it will override the real identity of a piece of software and return data that looks like the original code is returning (similar to shadowing a piece of code).

With help of this, we can perform all below operations

script.js
const add = (a, b) => a + b;
script.test.js
// mocks whole add method implementation
let add = jest.fn().mockImplementation((a, b) => a - b)

2. Expect

When you’re writing tests, you often need to check that values meet certain conditions. expect gives you access to several "matchers" that let you validate different things.

This helps us to see if the test case has passed or failed. This is also called an assertion. There are many supported methods through which we can assert the values according to our requirement.

3. SpyOn

Creates a mock function similar to jest.fn but also tracks calls to object[methodName]. Returns a Jest mock function.

SpyOn in general mocks the function and calls the fake function in place original function, mock the response and return it if needed. The only difference is it is much simpler and neat way of mocking. Its purely dev choice.

script.js
const video = {
play() {
return true;
},
};
module.exports = video;script.test.js
const video = require(‘./video’);
test(‘plays video’, () => {
const spy = jest.spyOn(video, ‘play’).mockReturnThis(true);
const isPlaying = video.play();
expect(spy).toHaveBeenCalled();
expect(isPlaying).toBe(true);
});

Also, we need to reset mocks after each test case to remove the changes done on the mock function in the recent test case and the syntax looks something like this. we can do it in each test case or we can do it in afterEach block.

jest.resetAllMocks()

4. We can also perform Snapshot testing in Jest

What are snapshots and why they are so useful?

The first time I saw this functionality I thought it was something limited to enzyme and react unit testing. But it’s not! Snapshot is used to track changes in UI. Snapshot testing captures code of a component at a specific time to compare it to a reference snapshot stored alongside the test. You can use snapshots for any serializable object.

Let’s take a look.

Per say you want to test if a function returns a non-trivial value like an object with some nested data structures. This kind of code is frequent:

const data = funtionWeWantToTest()
assert.deepEqual(data, {
user: {
name: 'jest',
email: 'jest@example.com'
}
// ...
})

But, if some nested property is not exactly what you were expecting… You just get an error and you’ll need to find the differences visually!

assert.js:83
throw new AssertionError(obj);
^
AssertionError [ERR_ASSERTION]: { user:
{ name: 'jest',
email: 'jest@example.com' } } deepEqual { user:
{ name: 'jest',
email: 'jest@example.com' } }

If the testing function returns a random data, we cannot use this kind of mechanism(for example generating a unique uuid). In such case, you have to do it manually,

const data = funtionWeWantToTest()
assert.ok(data.user)
assert.equal(data.user.name, 'jest')
assert.equal(data.user.email, 'jest@example.com')
// ...

This looks better, but it’s a lot more work. If you find yourself doing these things, snapshots will solve your problem!

You will write something like this:

const data = funtionWeWantToTest()
expect(data).toMatchSnapshot()

When you run the test for the first time, jest will generate and store the data structure in a snapshot file that you can open and validate. Any time you run the test again, Jest will load the existing snapshot and compare it with the received data structure from the test. If there are any differences, Jest will print a colored diff to the output. Cool!

These are the main things that would help any beginner-level programmer on unit testing with the Jest framework. Using this basic knowledge we can perform different levels of unit testing based on the user software. I hope these will clear some of the questions you had on unit testing.

--

--