Adding Tests for ESM using Jest framework
Tags: opensource, tutorial, webdev, javascript
Published: 2022-11-25 22:01:42

Writing tests for an application is a crucial process, as it helps make debugging easier and forces us, developers, to write better code. 

## What is Testing?
In essence, testing is writing code to _test_ that the functionality of your codebase is working and is not breaking in ways unimagined.

## Using Jest
[Jest](https://jestjs.io) is a testing framework for Javascript projects. It ensures that the implemented core functionality of the codebase is not prone to errors by allowing developers to write convenient tests. 

### Setting up Jest for [ESM](https://nodejs.org/api/esm.html)

The initial step is to install Jest as a `dev` dependency using `npm` or `yarn` 

Since I use `npm` to install `node` packages, I ran the following command:
```bash
npm install --save-dev jest
```
The next step is to create a `jest.config.js` file with the following content:

```node
export default { transform: {} }
```
Finally, we need to modify the `test` script in `package.json`. 

Typically you would replace the default `value` of the test with either `jest --` or `jest`. However, since we are using ECMAScript modules in our project, we have to set up the test `script`[accordingly](https://jestjs.io/docs/ecmascript-modules) as follows:

```node
"scripts": {
    "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
  },
```
### Writing the first test
Before you write your first test, create a `tests` or `__tests__` directory in the project's `root` directory.

Here's a sample function that checks if the user is eligible to cast a vote.
```node
// can-vote.js
const canVote = (age) => {
   if(age < 18){
   return false;
   }
  return true;
}
export default canVote;
```
Here's the test for the above function:

```node
import canVote from '../src/can-vote';

test('should return false if no value for age given', () => {
  expect(canVote()).toBe(false);
});
```

Let's run the test as follows:

```bash
npm test
```
In the above `test`, we expect `canVote` to return `false` when no argument is passed. This test should fail because we are not dealing with a use case in which the value for `age` is `undefined`. As a result, the function returns `true` with the above implementation. This mistake could go unnoticed when the function definition is more extended and complex. 

I encountered a similar bug in the `main` function of [my SSG](https://github.com/SerpentBytes/siteit), because there were no instances where the `main` function was invoked without passing a `value` in the codebase. 

To fix the problem in the test we wrote, we could modify our `canVote` function as follows:

```node
// can-vote.js
const canVote = (age = 0) => {
   if(age < 18){
   return false;
   }
  return true;
}
export default canVote;
```

Now, if we run `npm test` the `test` we wrote for `canVote` should pass, since we are using [default parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) value in the function declaration.

## Final Thoughts
Writing tests for my project helped me find bugs that would have otherwise gone unnoticed. It's not easy to write tests, but it's a skill I would like to improve. Also, I learned it is challenging to write tests for code you do not understand.