Unit Testing in JS with Jest
Published: 2021-09-06 22:55:51

Why does unit testing get overlooked at times? When we write code and something is not working we usually continue trying to fix it by manually testing our application until it shows us the results we want. Once it is working we are ready to move on and continue building something else or adding to the application. Some think "The effort of writing a test at this point is overkill and I just want to move on." 
  
That may seem like a rational thought at the time. However if you plan to come back and work on this application in the future I recommend implementing some form of testing to help avoid bugs when refactoring. Imagine if someone else might work on this as well. The overall amount of time saved by writing tests is going to be worth it in the end. 

To get started with writing your first test let's take on a very simple problem that we can later expand on. We will start with a sum function that takes in two arguments a & b.

We are going to use the Jest testing framework and this is what we need to get started.  

Open up a new project in VScode and create a file called sum.js. 

run the following commands to set up your test environment.

npm init -y 

this will initialize with all the default values and is our starting point for package.json

```js
{
  "name": "file_name_of_your_choice",
  "version": "1.0.0",
  "description": "",
  "main": "sum.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
```

Then run 

npm i --save-dev jest 

This is saved as a development dependency because we only use the testing library in development. 

You can see that it added the devDependencies 

```js
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "jest": "^27.1.0"
  }
}
```
Now go into the package.json and change the test script to jest.

Was 
```js
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
```
Now 
```js
"scripts": {
    "test": "jest"
  },
```

run npm test and it will now run the tests

But none have been written! 

Let's write our sum function in sum.js 

```js
const sum = (a,b) => {
    return a + b
}

module.exports = sum
```

We have to export the sum function so that we can import it to our test file.  

Create a file called 

sum.test.js

This is naming convention to name your test file with the same name as the file that you are testing. 

First we need to import sum and then we can write tests in sum.test.js. 

Start with a simple test to determine if sum is a function.  Pay attention to the syntax here.

```js
const sum = require('./sum')

test('Check if sum is a function', () => {
    expect(typeof sum).toBe('function')
})
```

Run npm test and you should see that you have 1 test passing.

The test we have written is labeled with whatever you write in parentheses and then expect typeof sum means that we are checking the constant sum type, and we expect it to be 'function' type.  If we change 'function' to 'object' our test will fail. 

Ok let's take it a step further and check if our sum function is properly adding two numbers. Directly below our first test we will write our second test. 

```js
test('Properly adds two numbers', () => {
    expect(sum(4,5)).toBe(9)
})
```

Again run npm test and see that your tests pass. 

To show an example of why testing is important make a simple addition to our file. 

We want to create a function where we subtract the sum of our first function from a number we choose. It is going to look similar with just the two parameters passed in as seen here. 

```js
const subtractSum = (a, b) => {
    return a - b
}
``` 

So that when we run 
```js 
subtractSum(10, sum(4,5)) 
```

We expect to get a return value of 1 and we do. So we should write a test to check this function. We need to change our import and export calls to this. 

in the sum.js file
```js
module.exports = {sum, subtractSum}
```

in the sum.test.js file
```js 
const {sum, subtractSum} = require('./sum')
```

Now we can write our test 
```js
test('Properly subtracts sum from number', () => {
    expect(subtractSum(10, sum(4,5))).toBe(1)
})
```

All three tests are currently passing.

Now here is why the tests are important. You pass this application off to a friend who works on it. They come back to you and say that something is broken. This is what you have to look at without tests. 

```js
const sum = (a,b) => {
    return a * b 
}

const subtractSum = (a, b) => {
    return a - b
}
```  
Now figure out what is wrong. This is going to take some console.logging to check what returns you are getting when you run subtractSum(10, sum(4,5)) or whatever other ways you manually debug this. 

But if you have tests you can just run your test suite and see where the errors are. 

Run the tests and see two errors 

Properly adds two numbers is failing 
Properly subtracts sum from number is also failing

This tells me that we need to look into the properly adds two numbers test first. The second test relies on that one to pass so this seems easy enough.  

Now there is a focused approach to our debugging and quickly find that your friend changed the '+' to a '*' in the sum function. Fix that and run the tests again. No problems now all tests are passing. 

This is clearly a simple approach but even with something like this it begins to become very clear why testing in your applications is so important. If we didn't have these tests we might have been messing around with the subtractSum function for a while before realizing the root of the problem.  

There is so much more you can do with the jest framework and the best way to learn is to try new things and work your way through some of these problems. In the end this will help you in your application building process.