Testing with Jest
Tags: javascript, testing
Published: 2022-04-23 12:41:43

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`
:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8d51r9lc8c99p6o4oau.png)

 **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.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/72bk37cyf8lfu1qj0q47.png)

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.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rmstjo2qxe8fkez0j1z3.png)
 
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**'.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pjfuke7rg4r7p3a3muw4.png)

**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**'.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/79ffdq9rtl3uyjthouzv.png)

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.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fbap2xmdqqdo111yb5qc.png)

**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.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r4e6j0nxmxrn1kxixg53.png)
 

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.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ycqkxekv63kai39m3pc0.png)
** 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
})
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hutr8bcgb94iaddkafz.png)
** 
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.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3nzf2nb03yfzy0i1akix.png)

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']));
}) 
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dxbgjv2ele1dmfrs3mk0.png)

```
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'
}) 
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t71phxztyxd1sbrpa4hx.png)

**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);
});
```
 **Reference**:
[](https://www.geeksforgeeks.org/testing-with-jest/)