Open In App

Testing with Jest

Improve
Improve
Like Article
Like
Save
Share
Report

Jest is a Javascript Testing Framework by Facebook. It is used most commonly for unit testing. Unit testing is when you provide input to a unit of code(usually, a function) and match the output with the expected output. 

Jest Features: 
 

  • zero config: As we will see later in this article, close to none configuration is required to get started with writing tests and deploying them. However, a config file can be supplied to the test suite as well.
  • snapshots: Jest has the ability to enable snapshot testing as well. Essentially, the snapshots are matched with the saved snapshot and check for matching functionality.
  • isolated tests: Jest tests are run parallelly to improve run time.

Setting up a jest project 
 

  • Install Jest using npm: 
     
npm install jest. The -D keyword installs jest as dev dependency

npm install jest. The -D keyword installs jest as dev dependency

  • Project Structure: 
    In the project root directory, make a tests folder. This folder will store all the test files. 
    Note that the js files(which are to be tested) are mapped by their names. 
    For example, index.js is mapped to index.test.js. This index.test.js file is placed in the ‘tests’ folder. This is the conventional project structure.

Start testing: 
 

  • To start, lets see a basic test workflow. 
     
test - adding two pos nums

test – adding two pos nums

  • To run the test, use the script 
     
npm run test
  • This will look for the test script mentioned in the package.json of the project. 
     
pkg-json-test-script-ss

pkg-json-test-script-ss. See test in scripts

We will use the ‘expect’ method to test our functions. The functions can also be tested using ‘describe’ and ‘it’

A basic test: adding two positive nums and checking result. 
 

//index.js
testForAdd: (a, b) => { return (a + b) },

//index.test.js
test('test adding two positive nums', function() {
    expect(testFns.testForAdd(4, 5)).toBe(9);
});

When the ‘npm run test’ is run, the index.test.js file is gone through. Then the testForAdd function is run which is placed in the ‘testFns’ object. The toBe is used to ‘match’ the returned response from the test to what is expected. This ‘result matching’ leads to either a ‘fail’ or a ‘pass’

 

test adding two pos nums

test adding two pos nums

The following test will fail because of the ‘toBe(8)’. 
 

//example of a failing test
 test('test adding two positive nums - failing test', function() {
     expect(testFns.testForAdd(4, 5)).toBe(8);
 });

Opposite of toBe: not.toBe() 
The opposite of the ‘toBe’ matcher is created by simply prefixing it with ‘not.’ 
For example: 
 

//test successful - test for opposite of a matcher.
//The following test will 'Pass' if the returned value is not equal to 8.
test('test adding two positive nums - failing test', function() {
    expect(testFns.testForAdd(4, 5)).not.toBe(8);
});

Using ‘toBe’ with JS Objects: 
Let’s think of a case where every field of a JS object is to be tested. Jest provides us a way to do this using ‘toEqual’. The ‘toEqual’ is a deep-matcher(checks every field and sub-fields possible). 
 

//expect toEqual example - check every field's value
// testFns.test_toEqual(gfgObj)
test('check gfgObj toEqual', () => {
    let gfgObj = { name: "GFG" };
    gfgObj['type'] = "company";
    expect(gfgObj).toEqual({ name: "GFG", type: "company" });
});

Running the above test will ‘Pass’. 
 

gfgobj toEqual

gfgobj toEqual

Another variation of doing this is matching two objects using the ‘toEqual’
This is done so like this : 
 

test('check gfgObj toEqual', () => {
    let gfgObj = {
        name: "GFG",
        type: "company",
        members: {
            employees: 100,
            contributors: 500
        }
    };

    let testObj = {
        name: "GFG",
        type: "company",
        members: {
            employees: 100,
            contributors: 500
        }
    };
    expect(gfgObj).toEqual(testObj);
});

This test demonstrates the deep-matching feature of toEqual. 
The above test passes as every key-pair in gfgObj matches with testObj. 
 

gfgobj-testobj-toequal

gfgobj-testobj-toequal

toBeCloseTo – for floating point numbers and other approximate matches 
 

//see here that a+b != c even though simple addition is taking place.
> var a = 1.32
> undefined
> var b = 2.31
> undefined
> c = a+b;
> 3.63
> var res = false;
> if(c==(a+b)) {c=true;}
> undefined
> c
> false

In such conditions, it is good to use ‘toBeCloseTo’ matcher from the Jest library. 
 

test('floating point number - use toBeCloseTo instead', function() {
    // const num1 = 0.3;
    // const num2 = 0.2;
    const result = 9.31 + 9.2;

    expect(result).toBeCloseTo(18.51);
})

The above test passes too. 

matching truthy and falsy: 
https://jestjs.io/docs/en/using-matchers#truthiness 
A lot of times, tests are written to check for truthy and falsy values returned by ‘expect’. 
Falsy values in JS. 
Truthy values in JS. 
 

//checking for truthy values - All the tests will return truthy.
test('check for truthy', function() {
    const gfgObj = {
        first: null,
        second: undefined,
        third: false
    }
    expect(gfgObj.first).not.toBeTruthy(); // True - Pass
    expect(gfgObj.second).toBeUndefined(); // True - Pass
    expect(gfgObj.third).toBeFalsy();      // True - Pass
})

The above test passes. 
 

truthy-test-js-all-test-passing

truthy-test-js-all-test-passing

However, if any of the ‘expect’ above fails, Jest returns meaningful error messages like below. 

Note that in above case, if any of the ‘expect’-s fail, the test also completely fails. 
 

truthy-test-js-one-expect-failing-so-test-failing

truthy-test-js-one-expect-failing-so-test-failing

Matching Numbers: 
 

//tests for Number matches
test('test for numbers', function() {
    const result = 3 + 9;
    // expect(result).toBe(12); //the plain old matcher
    expect(result).not.toBeLessThan(10); // result > 10
    expect(result).toBeLessThan(15);  // result < 15
    expect(result).not.toBeGreaterThan(15); // result  10
    expect(result).toBeGreaterThanOrEqual(12);  //result >= 12
    // expect(result).not.toBeGreaterThanOrEqual(12); // result == 12, this Fails
    // expect(result).toBeLessThanOrEqual(10); // result >= 10, this Fails
})

 

number matching using jest

number matching using jest

Testing values contained in arrays: 
We can also test if particular values are contained in an array. Note that this test will ‘Fail’ if at least one value is not present in the array. For example, 
 

//testing arrays
const gfgUsers = [
    'user1',
    'user2',
    'user3'
];
test('test for a value in gfgUsers', function() {
    // expect(gfgUsers).toContain('user2');
    // expect(gfgUsers).not.toContain('user2');
    //expect array containing
     expect(gfgUsers).toEqual(expect.arrayContaining(['user1', 'user3']));
})

Th above test passes as user1 and user3 are present in gfgUsers. 
 

user1-and-user3-in-gfgUsers

user1-and-user3-in-gfgUsers

However, the following test will fail because ‘user4’ is not present in gfgUsers. 
 

//testing arrays
const gfgUsers = [
    'user1',
    'user2',
    'user3'
];
test('test for a value in gfgUsers', function() {
    //expect array containing
     expect(gfgUsers).toEqual(expect.arrayContaining(['user1', 'user4']));
})

 

arraycontaining-fail-due-to-user4-absence

arraycontaining-fail-due-to-user4-absence

Testing using Regex: 
 

test('string match tests - toMatch - used for regex-es', function() {
    const str = 'GeeksforGeeks';
    // expect(str).toMatch(/f/);
    // expect(str).toMatch(/Z/);
    //you can create more complex Regexes
    const str1 = 'This is a test paragraph. I wrote it.'
    expect(str1).toMatch(/[pP][hH][\.]/);  //matches 'ph.' in the word 'paragraph'
})

 

tomatch-matching-ph-in-paragraphq

tomatch-matching-ph-in-paragraph

Extending the Matchers 
Jest also has the provision to extend its ‘Matchers’ functionality, which is accomplished using the ‘expect.extend()’ keyword. The .extend() function is passed matchers as objects. 
Syntax: expect.extend({matcher1, matcher2}) ; 
For example, if we want to build a matcher that checks for a phrase presence in a string: 
 

expect.extend({
stringPresent(receivedString, phraseString) {
bool phrasePresent = true;
var re = new RegExp(phraseString);
if (re.test(receivedString)) {
    phrasePresent = true;
} else {
    phrasePresent = false;
}
if (phrasePresent === true) {
      return {
        message: () =>
          `string present`,
        pass: true,
      };
    } else {
      return {
        message: () =>
          `string absent`,
        pass: false,
      };
    }
},
});

Dealing with exceptions 
We can also check the types of errors that a unit of code throws. We can check the error thrown by name, message, object, etc. 

Syntax:expect( fnName() ).toThrow( error ); 
The error parameter/argument is optional here. 

Let’s suppose that we want to test a function by the message of the error thrown. 
 

function testGFGMessage() {
  throw new Error('this is testGFGMessage function error');
}
test('testing testGFGMessage', function(){
  expect(testGFGMessage).toThrow('this is testGFGMessage function error');
})

There are many other ways to throw Errors and check for them. A detailed reference can be found here

Skipping/Running a subset of tests 
https://jestjs.io/docs/en/api#testskipname-fn 
Jest also has a provision for skipping specific tests while running the test suite. 
To implement it, simply use the ‘skip’ keyword. For example, 
 

function addFn(num1, num2){
  return num1 + num2;
}

test.skip('skip test example - skipping the addition test', () => {
  expect(addFn(2, 3)).toBe(5);
});

The opposite of this is implementing only a subset of tests, which is achieved by using the ‘only’ keyword. For example, 
 

function addFn(num1, num2){
  return num1 + num2;
}

test.only('skip test example - skipping the addition test', () => {
  expect(addFn(2, 3)).toBe(5);
});

 



Last Updated : 27 Jan, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads