Javascript Unit Testing with Jest

The Wikipedia page for unit testing states that unit testing is "a software testing method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine whether they are fit for use".

What does that mean in english ?

It means that each function is one unit, and unit testing is testing each function separately. Once you test the functions, if an error or some unexpected behaviour happens later, you'll know for sure it's not from the functions but from something else.

Give me an example, a useful one, not 2 + 2 !

Ok. Let's say you have a sign up form where the user has to enter their name and it must not be empty:

<form id="myForm">
  <input type="text" id="name" onfocusout="validateName()" />
  <button type="submit">Sign Up</button>
</form>
...
<script src="index.js"></script>

Binding validateName() to onfocusout event excutes the validation function when the user goes to the next input or clicks somewhere else, (this is my favourite method of validing inputs because of the quick feedback, Facebook uses it on its sign up form).

In your Javascript file index.js you have this:

const nameField = document.getElementById('name');
const validateName = () => {
  if (!isEmpty(nameField.value)) {
    nameField.className = 'valid';
  } else {
    nameField.className = 'invalid';
  }
};
const isEmpty = string => {
  if (string === '') return true;
  return false;
};
module.exports = {
  isEmpty,
};

If you were to run this code, you will have the weird case of when you type and empty space ' ' the field will be set to valid, and you might be confused as to why this happens.

Obviously you should compare string.trim() to an empty string, duh!

Well, yes. But in a bigger application you might waste a big amount of time tracing a bug where you dont test your functions.

ENTER: Jest.

Jest is a fantastic Javascript framework for writting and runnig unit tests (and integration tests and end to end tests but we'll focus on unit tests for this post).

To be started, we need to initialize an npm project in our directory and install Jest:

npm init -y
npm install -D jest

After that, we need to create a test file where we test out isEmpty function. The good practice here is to create a file with the same name of your js file with a .spec or .test extension, I personally prefer .test because it makes more sense but I'll let you choose.

In the test file we need to import isEmpty and write a test with multiple test cases and run it:

const { isEmpty } = require('./index.js');

test('Testing isEmpty', () => {
  // Empty string
  let result = isEmpty('');
  expect(result).toBe(true);
  // Non-empty string
  result = isEmpty('john');
  expect(result).toBe(false);
  // White space
  result = isEmpty(' ');
  expect(result).toBe(true);
});

test takes a name to give the test a name, a callback function that is executed when the test is ran (and a timeOut value in case you think this test will take some time).

If the result is the same as the argument given to toBe in all cases, the test will succeed indicating that our function functions properly. We can run this test by running:

jest

Given our code, the test will fail on the third case as ' ' is not considered as an empty string. By running and failing this test, we realized that we need to change our isEmpty function to the following:

const isEmpty = string => {
  if (string.trim() === '') return true;
  return false;
};

By chaining .trim() to the string, we remove any extra white space on the sides, so that now if a user types white spaces as a name, it will be invalidated by our code.

This was a basic introduction to Jest, the library has a lot more powerful functionalies for running all sorts of tests. I will be releasing a video soon on my channel Classsed demonstrating how to use Jest for testing all kinds of functions.

Thank you for reading :)


Copyright © 2020 Ahmed Hadjou