DEV Community

Sammy Abukmeil
Sammy Abukmeil

Posted on • Updated on

JavaScript Testing Basics

Table of Contents



What is Testing

Testing is all about writing code ("tests") which automates the process of checking whether your application is working as intended.

You can run the tests:

  • After you make changes (to ensure your changes didn't break anything else)
  • During your CI/CD pipeline to ensure you're not pushing bugs to production

Benifits of Testing

Testing helps with:

  • Confidence when refactoring (you'll be sure that your changes haven't broken anything)
  • Less bugs in production
  • Less manual testing
  • Forces you to write better code (code that's easy to test)

Types of Tests

There are a few different categories of tests which test different things, and you should aim to add each of these to your app:

Unit Tests

Test the smallest building blocks ("units") of your app (e.g. a function, a class, or a component in React).

Integration Tests

Test multiple units to ensure they work well together.

End-to-End Tests

Test an entire flow/feature of your app (e.g. a user uploading an image).

Generally, you want:

  • A lot of unit tests
  • Less integrations tests
  • A small amount of end-to-end tests

As shown in this testing pyramid
Testing Pyramid


Local Development Setup

We need a tool to achieve the following:

  • Test Runner - Runs the tests and shows the results
  • Assertion Library - The test themselves, what to check etc

A popular tool for both of these features is Jest, however, Jest can be slow when executing tests, and requires extra setup to use ECMAScript modules (i.e. import x from "y" syntax)

A modern alternative is Vitest (prounounced "vee-test") which works in the same way as Jest, is fast and supports ECMAScript modules out of the box.

Let's start by making a directory

mkdir testing
cd testing
Enter fullscreen mode Exit fullscreen mode

Create a package.json file

npm init -y
Enter fullscreen mode Exit fullscreen mode

Install vitest as a dev dependency

npm i vitest --save-dev
Enter fullscreen mode Exit fullscreen mode

Create a index.js file with the following contents

const add = (numbers) => {
  let sum = 0;

  numbers.forEach((number) => {
    sum += number;
  })

  return sum;
}
Enter fullscreen mode Exit fullscreen mode

This is the first function we'll test

Create a index.test.js file with the following code

import { expect, test } from "vitest";
import { add } from "./index";

test("should sum all numbers in an array", () => {
  const result = add([1, 2, 3]);

  expect(result).toBe(6);
});
Enter fullscreen mode Exit fullscreen mode

The test in the file name is important, Vitest looks for files with test in and executes the tests within them.

In your package.json file add a script to run vitest

{
  "scripts": {
    "test": "vitest"
  },
  "devDependencies": {
    "vitest": "^1.6.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Now run the test script

npm test
Enter fullscreen mode Exit fullscreen mode

You should see the following output

Vitest output

Writing our First Test

Now we have our test runner & assertion library setup, let's revisit our test

test("should sum all numbers in an array", () => {
  const result = add([1, 2, 3]);

  expect(result).toBe(6);
});
Enter fullscreen mode Exit fullscreen mode

The test() method sets up a new test and takes two arguments

  • A string describing what we're testing
  • A callback function to execute when the test executes

Inside the callback function, we simply execute the function we want to test and store the result in a variable: const result = add([1, 2, 3])

The expect() method takes one argument:

  • The value that the assertion library will check

The toBe() method takes one argument:

  • Checks if the value that was given to expect() is a particular value

In this case, the sum of [1, 2, 3] should result in 6, hence expect(result).toBe(6)

Catching Bugs Early

If another developer on your team makes a change to the original function e.g. changing let sum = 0 to let sum

export function add(numbers) {
  let sum;

  numbers.forEach((number) => {
    sum += number;
  });

  return sum;
}
Enter fullscreen mode Exit fullscreen mode

When the tests run, an issue is detected and the test fails

Failed Test

The output tells you the following:

  • Which test(s) failed
  • What value the test was expecting
  • What value the test actaully recieved
index.test.js
   × should sum all numbers in an array

AssertionError: expected NaN to be 6

- Expected
+ Received

- 6
+ NaN
Enter fullscreen mode Exit fullscreen mode

This is happening since the variable sum is now undefined , and adding a number to undefined results in NaN

This will prompt the developer to review their change, and therefore the presence of this unit test has prevented a bug from being committed 🎉

Top comments (0)