Exploring Jest: A Beginners Guide to JavaScript Testing

by Liben Hailu
5 mins read

Jest, developed by Facebook, is a popular JavaScript testing framework extensively used for testing JavaScript code. This beginner's guide delves into the core concepts of Jest, offering insights into its basic concepts and effective testing usage.


What is Jest

Jest is a popular JavaScript testing framework developed by Facebook. It's widely used for testing JavaScript code. Jest is designed to be easy to set up and use while providing powerful features for writing comprehensive and reliable tests.

Describe function

The describe function is used for organizing test cases into logical groups. The describe function takes two parameters.

  • The description string
  • A callback function that contains the test cases

The describe string is used to explain the behavior or the outcome of the test. The callback function contains the test cases.

Test or It function

A test or It function is used to organize the test cases inside a describe function. It has two parameters:

  • Description String: This describes what the test is about.
  • Callback Function: This is where you write your test code.

Example:

describe("Caclulator", () => {
  it("should add two numbers", () => {
    expect(add(2, 3)).toEqual(5);
  });
});

A describe function can be nested inside another describe function for better organization of tests.

describe("Caclulator", () => {
  describe("Addition", () => {
    it("should add two numbers", () => {
      expect(add(2, 3)).toEqual(5);
    });
  });
});

Note: It is better to write the describe string like a user story or business context rather than a technical specification.

Setup and Teardown

Usually, while writing tests, some setup should happen before the tests run, and some things should happen after the tests run.

  • beforeEach This setup runs before each test case, automatically invoked by Jest, and is used to create a reusable new instance before each test.
  • afterEach This teardown runs after each test case, automatically invoked by Jest, and is used to clean up the resources created by the test after each test case run.
  • beforeAll This is used to set up tasks that are expensive and can be shared across multiple tests within a test suite.
  • afterAll This is used to perform cleanup tasks that need to run after all tests have completed.

Example:

beforeAll(() => {
  // Setup tasks that need to run once before all tests
  initializeDatabase();
});
 
beforeEach(() => {
  // Common setup tasks that need to run before each test
  createUserTestData();
});
 
afterEach(() => {
  // Cleanup tasks that need to run after each test
  cleanUpTestData();
});
 
afterAll(() => {
  // Cleanup tasks that need to run once after all tests
  closeDatabaseConnection();
});

Jest Matchers

Equality

The toBe and toEqual functions are both used to check equality. The toBe matcher does not perform a deep equality check for objects and arrays; it simply checks if they refer to the same object in memory. Therefore, it is usually used for primitive types, where it employs the strict equality (===) operator. However, the toEqual matcher is used to perform a deep equality check between two values. It checks if the properties and values of objects or arrays are equal, rather than checking if they are the same object in memory.

expect(1 + 1).toEqual(2); // PASS
expect(1 + 1).toBe(2); // PASS
expect({}).toEqual({}); // PASS
expect({}).toBe({}); // FAIL

Opposite

The not keyword is used with other matchers like toBe and toEqual to check for the opposite condition.

expect(1 + 1).not.toEqual(3); // PASS

Numbers

When working with numbers, Jest provides toBeGreaterThan,toBeGreaterThanOrEqual,toBeLessThan,toBeLessThanOrEqaul and toBeCloseTo matchers.

Example:

expect(1 + 2).toBeGreaterThan(2); // PASS
expect(1 + 1).toBeGreaterThanOrEqual(2); // PASS
expect(1 + 1).toBeLessThan(3); // PASS
expect(1 + 1).toBeLessThanOrEqual(3); // PASS
expect(1 + 1.2).toBeCloseTo(2.2); // PASS

String Patterns

Using the toMatch matcher, we can pass a regular expression to find a pattern in a string.

Example:

expect("Hello world").toMatch(/world/);

Arrays and Objects

toContain and toContainEqaul matchers are used when working with arrays and iterables. toContainEqual compares by value, while toContain compares by === strict comparison.

Example:

const array = [{ name: "apple" }, { name: "banana" }, { name: "orange" }];
const expectedItem = { name: "banana" };
expect(array).toContain(expectedItem); // FAIL
expect(array).toContain(array[1]); // PASS
expect(array).toContainEqual(expectedItem); // PASS

Truthiness

When testing, you want to know if something is defined, null, or false. Jest has got you covered with these matchers. toBeNull,toBeUndefined,toBeDefined,toBeTruthy and toBeFalsy.

Example:

const user = null;
let cars;
expect(user).toBeNull();
expect(user).toBeDefined();
expect(cars).toBeUndefined();
expect(true).toBeTruthy();
expect(false).toBeFalsy();

Mocking and Stabbing

The jest.spyOn or jest.fn function can be used for spying. Spying involves observing the behavior of a function by tracking its calls, arguments, return values, etc., without affecting its actual implementation. This is useful for verifying that certain functions are being called or how they're being called.

Example:

const mock = jest.fn();
mock();
expect(mock).toHaveBeenCalled();

jest.mock or jest.fn can be used to mock a fake version of a module or component in your tests. This is particularly useful when you want to isolate the code under test from its dependencies.

Example:

jest.mock("calculator");
Calculator.add.mockResolvedValue(5);

Stubbing involves replacing a specific function or method with a predetermined behavior or return value. It allows you to control the behavior of individual functions or methods within the code under test without replacing the entire dependency.

global.fetch = jest.fn().mockResolvedValue({
  json: jest.fn().mockResolvedValue({ message: "Mocked data" }),
});