Unit testing is a crucial part of software development, ensuring that individual components of your application work as expected. Jest is a popular testing framework for JavaScript, particularly well-suited for testing React applications but also versatile enough for general JavaScript testing.

What is Jest?

Jest is a JavaScript testing framework developed by Facebook. It is widely used for its simplicity and powerful features, including:

  • Zero configuration: Works out of the box for most JavaScript projects.
  • Snapshot testing: Captures the output of a function or component and compares it to a reference snapshot.
  • Mocking: Easily mock functions, modules, and timers.
  • Code coverage: Provides detailed code coverage reports.

Setting Up Jest

Installation

To get started with Jest, you need to install it in your project. You can do this using npm or yarn:

# Using npm
npm install --save-dev jest

# Using yarn
yarn add --dev jest

Configuration

Jest can be configured in various ways, but it often works with zero configuration. However, you can customize it by adding a jest.config.js file in your project root:

module.exports = {
  testEnvironment: 'node', // or 'jsdom' for browser-like environment
  verbose: true,
};

Writing Your First Test

Basic Test Structure

A Jest test is composed of a test suite and individual test cases. A test suite is defined using the describe function, and test cases are defined using the test or it function.

// sum.js
function sum(a, b) {
  return a + b;
}

module.exports = sum;

// sum.test.js
const sum = require('./sum');

describe('sum function', () => {
  test('adds 1 + 2 to equal 3', () => {
    expect(sum(1, 2)).toBe(3);
  });

  test('adds -1 + 1 to equal 0', () => {
    expect(sum(-1, 1)).toBe(0);
  });
});

Running Tests

You can run your tests using the following command:

# Using npm
npm test

# Using yarn
yarn test

Common Matchers

Jest provides a variety of matchers to assert different conditions. Here are some common ones:

Basic Matchers

  • toBe(value): Checks if the value is exactly equal (using ===).
  • toEqual(value): Checks if the value is deeply equal (useful for objects and arrays).
  • toBeNull(): Checks if the value is null.
  • toBeUndefined(): Checks if the value is undefined.
  • toBeTruthy(): Checks if the value is truthy.
  • toBeFalsy(): Checks if the value is falsy.

Example

test('basic matchers', () => {
  expect(2 + 2).toBe(4);
  expect({ name: 'John' }).toEqual({ name: 'John' });
  expect(null).toBeNull();
  expect(undefined).toBeUndefined();
  expect(true).toBeTruthy();
  expect(false).toBeFalsy();
});

Numeric Matchers

  • toBeGreaterThan(value): Checks if the value is greater than the given value.
  • toBeLessThan(value): Checks if the value is less than the given value.
  • toBeGreaterThanOrEqual(value): Checks if the value is greater than or equal to the given value.
  • toBeLessThanOrEqual(value): Checks if the value is less than or equal to the given value.

Example

test('numeric matchers', () => {
  expect(10).toBeGreaterThan(5);
  expect(10).toBeGreaterThanOrEqual(10);
  expect(5).toBeLessThan(10);
  expect(5).toBeLessThanOrEqual(5);
});

Mocking Functions

Jest allows you to mock functions to isolate the code you are testing. This is particularly useful for testing functions that depend on external services or modules.

Example

// fetchData.js
const fetchData = (callback) => {
  setTimeout(() => {
    callback('peanut butter');
  }, 1000);
};

module.exports = fetchData;

// fetchData.test.js
const fetchData = require('./fetchData');

test('fetches data successfully', (done) => {
  function callback(data) {
    expect(data).toBe('peanut butter');
    done();
  }

  fetchData(callback);
});

Practical Exercise

Exercise

  1. Create a new file calculator.js and implement the following functions:

    • add(a, b): Returns the sum of a and b.
    • subtract(a, b): Returns the difference of a and b.
    • multiply(a, b): Returns the product of a and b.
    • divide(a, b): Returns the quotient of a and b.
  2. Create a new file calculator.test.js and write tests for each function using Jest.

Solution

// calculator.js
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

function multiply(a, b) {
  return a * b;
}

function divide(a, b) {
  if (b === 0) {
    throw new Error('Cannot divide by zero');
  }
  return a / b;
}

module.exports = { add, subtract, multiply, divide };

// calculator.test.js
const { add, subtract, multiply, divide } = require('./calculator');

describe('Calculator functions', () => {
  test('adds 1 + 2 to equal 3', () => {
    expect(add(1, 2)).toBe(3);
  });

  test('subtracts 5 - 2 to equal 3', () => {
    expect(subtract(5, 2)).toBe(3);
  });

  test('multiplies 2 * 3 to equal 6', () => {
    expect(multiply(2, 3)).toBe(6);
  });

  test('divides 6 / 2 to equal 3', () => {
    expect(divide(6, 2)).toBe(3);
  });

  test('throws error when dividing by zero', () => {
    expect(() => divide(1, 0)).toThrow('Cannot divide by zero');
  });
});

Conclusion

In this section, you learned how to set up and use Jest for unit testing in JavaScript. You covered the basics of writing tests, using matchers, and mocking functions. Unit testing is an essential skill for ensuring the reliability and maintainability of your code. In the next section, you will learn about integration testing and how it differs from unit testing.

JavaScript: From Beginner to Advanced

Module 1: Introduction to JavaScript

Module 2: Control Structures

Module 3: Functions

Module 4: Objects and Arrays

Module 5: Advanced Objects and Functions

Module 6: The Document Object Model (DOM)

Module 7: Browser APIs and Advanced Topics

Module 8: Testing and Debugging

Module 9: Performance and Optimization

Module 10: JavaScript Frameworks and Libraries

Module 11: Final Project

© Copyright 2024. All rights reserved