Basics of Testing JavaScript with Jest

Learn the fundamentals of automating testing with Jest in your JavaScript projects.

Mano lingam
Bits and Pieces

--

In this article, we will be talking about testing our code in JavaScript. We will then proceed with the explanation through Q&A’s as I hope this approach would be better than writing a long story. Let’s dive in without wasting much time.

What are tests?

It’s as simple as the name suggests. We expect something to work as expected and we check if it does. It can be your homework, task or anything which you wanna check for something expected. And in our case, we want our program to work as expected, so we test it.

Why test?

Most of you could say, “Hey, we can manually check for that. Why write a separate program to check another program?” Yeah, What you are thinking is right but only for small programs. We could easily check for issues if our code is only a few lines. But think of a program with more than 1000 lines with asynchronous functions, values jumping from one part of the program to the other, etc. In this case, even a small mistake in naming a variable or typo could make the program behave unexpectedly. And it would be a nightmare debugging the logic and 1000 lines of code.

At the end of the day, the problem can be a simple typo. LOL!

So this is where we might wanna write tests for our code.

How to test?

We use libraries for testing. Some may be inbuilt and some may need to be added as a package. And this depends on the programming language we use or the application we wanna test.

How testing is done in JavaScript?

There are various libraries for testing JavaScript code like Mocha, Jest, etc. And in this article, we will be using Jest for testing though you can use Mocha or any other libraries you like.

What is Jest?

Jest is a testing library for JavaScript and it’s developed by Facebook for use within ReactJS (which is also developed by them). And hence Jest came out. Jest is built-in with React but for other JS applications, we might wanna add it as a package from NPM.

How to setup Jest?

For this example, we will not dive deep into advanced Jest functionalities but keep it simple with just a few basic tests.

So, for the setup, we need NPM and Node. So if you haven’t installed it on your system, go on and install. If you have it, then proceed.

  1. Create a folder with any name you like. Am going to create a folder with mkdir test-js and cd into it cd test-js.
  2. Since we will be installing Jest as a package, we need to initialize our folder with NPM with npm init -y.
  3. We can now add Jest with npm install --save-dev jest. We need to add it as a developer dependency and hence we use the flag --save-dev.
  4. In your package.json file, you might need to change the test script command as jest so we can just run npm test whenever we need to test our code.

5. Now, we can create our JavaScript file named functions.js to write our code which will be tested using Jest.

6. And to write our tests we need to create a file functions.test.js.

Note that we need to have our test file similar to the name of the JavaScript file we wanna test except adding a .test in-between.

And that’s it. We are now ready to get started writing code and tests.

How to write tests?

Writing Javascript

In our functions.js file, let us write some code to test.

We have an object containing a few functions and we export the code using module.exports = functions to import the object into our test file which is to be written.

Note that functions in module.exports is not the filename. Instead, it’s the name of the object we have declared. And you can write down the functions separately too instead of using an object. But don’t forget to export each of them.

Writing tests

Now that we have three functions written, let us test it using Jest.

I know it’s too simple to write tests for the fucntions I have. But let’s make it simple for now. Later you can write some complex functions on your own better than me :)

Okay. So in our functions.test.js file,

Note that we haven’t included the copyArray function in our test and that’s because we have something to talk about it later.

Now run npm test and hurray!🏆 That’s it! We have our tests now. You may see the test pass in the terminal and it’s expected as we have our functions & tests bug-free.

But we haven’t explained what’s there in the test. So let us break down the code now.

What’s there in the test file?

  • In our test file, the first thing we wanna do is to import the module that is needed from our JavaScript file. In our case, we exported the functions object. So let us import that using const functions = require('./functions.js'). Now our test file knows the functions inside our object from the functions.js file.
  • Then we have a function called test which has two params. The first one is simply a string that defines what we wanna do/ what the test is gonna do. The second param is again a function.
  • In the function, we expect something to be something. And in our case, we expect the add function to return the sum of whatever the params we pass to it. So expect(functions.add(1, 5)).toBe(6) is the test case we have defined for our add function.
  • Similarly, we expect the results to be something for the subtract function too.

That is a raw explanation of what’s written there. But there are several terminologies that Jest has which we need to understand.

  • test
  • expect
  • matches (toBe, not.toBe, toEqual, etc)

test

‘test’ is simply a keyword in Jest. We write tests by using a function provided by Jest called test. It takes in two parameters, a string of what the test is gonna do and another function where we write our actual test. The syntax goes by, test("", () => {})

  • The first parameter is simply a definition of what the test is going to do.
  • The second parameter which is a function takes in the actual testing stuff. We use ‘expect’ and ‘matchers’ within this function.

expect

‘expect’ is also a keyword in Jest. As the name suggests, we expect something from our function or the code we have written. The overall syntax goes by, expect().matcher()

  • Within the expect function, we provide the inputs for our code from which we are expecting something.
  • .matcher is where we use different matchers like toBe, toEqual, etc. Consider these as the conditions the result from expect needs to match. It’s more of a kind of ‘==’.

matchers

‘matchers’ is not a keyword in Jest but is used to call a collection of methods in Jest. There’s a whole lot of matchers in Jest such as,

  • toBe
  • toEqual
  • toBeDefined
  • toBeFalsy, etc.

You can find a whole lot of them here.

A typical example would be the one we used in our test file, expect(functions.add(1, 5)).toBe(6). Here, the matcher used is toBe. In more simple terms, we are just doing a check like, is ‘1+5 == 6`? If so, we get the test passed.

Note that there are various matchers available in Jest and it’s impossible to mention everything here. So have a look at their documentation. It’s pretty simple and self-explanatory. The only thing you need to know is which matcher to use where.

toEqual

Remember we haven’t written a test for the copyArray function? Cause for this test, we will be using a different matcher called toEqual. So our test would be,

test('copies a new array', () => {
let arr = [1, 2, 3]
expect(functions.copyArray(arr)).toEqual([1,2,3])
})

In this example, we used toEqual instead of toBe because, in our function from the JavaScript file,

copyArray: (a) => { return [... a] }

we used the spread operator [... a]. And this would copy the contents of the array a we passed and returns a new array. So, if we use toBe, the compiler throws an error since the elements might be the same but not the location. The new array is created in a different location with the same elements of the array we passed on to the function. Hence we need to use toEqual to check accordingly and exactly.

Unit testing

What we have done is called Unit testing which is testing the lowest fundamental blocks or units of code. And that’s why using a test-driven approach is often better than manual testing as each and every fundamental block of the code is tested and verified.

Since our example code is only a few functions, it’s already a unit size. But for large programs, testing each smallest unit of the code is necessary and is what makes unit testing useful before going for production. We don’t want bugs!

--

--

Passionate in learning new industry related concepts in the field of computer science that actually matters in the application of real world problems.