htmx
JavaScript

Jest.js: A Friendly Guide to JavaScipt testing

JavaScript Testing with Jest.js: Testing your code is like a seatbelt for your JavaScript projects — it protects you from bugs, improves the structure of your code and gives you the confidence to extend your applications. Jest.js is one of the most popular tools for testing JavaScript code, and for good reason. It’s easy to use, fast and offers many features that make writing and executing tests a breeze.

By the end of this guide, you’ll be well-equipped to test everything from simple functions to complex React components with Jest. Let’s go!

Why testing is important

Testing can feel like extra work, but in the long run it saves you a lot of headaches. Here’s why testing is worth your time:

  • Detect bugs early: Imagine finding a bug in your code just before launch. Testing helps you detect such problems during development.
  • Encourage modular design: When you write tests, you often break your code into smaller, more testable pieces, which naturally leads to a better design.
  • Simplify collaboration: If you’re working in a team, tests ensure that everyone’s changes don’t break the existing codebase.
  • Document your code: Tests serve as a form of documentation that shows how your code should behave.
  • Reduce the fear of refactoring: Without tests, making changes to your code feels like walking a tightrope. With tests, you can refactor with confidence, knowing that your changes won’t break anything.

In short, testing isn’t a burden — it’s a way to future-proof your code.

Introduction to Jest

If you don’t know Jest yet, let’s take a closer look at what makes it special:

Features of Jest

  • Easy to use: Jest requires minimal configuration to get started. In most cases, it works right out of the box.
  • Rich API: Jest comes with built-in matchers, spies and mocks, so you don’t need additional libraries for these functions.
  • Great performance: Jest is optimized for speed, running tests in parallel and using intelligent caching to minimize test execution time.
  • Versatile: Whether you’re writing Node.js backends, front-end JavaScript or React components, Jest can handle it.
  • Community and ecosystem: Jest has a huge community, meaning there are many tutorials, plugins and integrations to discover.

Whether you want to test a simple JavaScript function or a complex application, Jest has you covered.

Set up Jest in your project

Getting started with Jest is easy, even if you’ve never used a test library before. Follow these steps to integrate Jest into your project.

Step 1: Install Jest

Use npm or Yarn to install Jest as a development dependency:

npm install --save-dev jest

or

yarn add --dev jest

This ensures that Jest is only available during development and does not bloat your production build.

Step 2: Configure Jest

Jest works by default, but you can customize it with a configuration file. Create one by executing it:

npm jest --init

This command will prompt you to set options like:

  • Collect code coverage
  • Use TypeScript
  • Set a test environment (Node.js or browser)
    The generated file “jest.config.js” could look like this:
module.exports = {
testEnvironment: 'node',
collectCoverage: true,
coverageDirectory: 'coverage',
};

Step 3: Update package.json

Add a test script to your package.json file:

"scripts": {
"test": "jest"
}

Now you can run all your tests by typing:

npm test

That’s it! Jest is ready to test your code.

Core concepts of Jest

If you understand the building blocks of Jest, writing tests becomes much easier. Here are the most important concepts:

Test suites

A test suite is a collection of related tests, usually in a single file. Jest treats each test file as a test suite.
For example, you could create a file “math.test.js” to group all tests related to math functions.

Test cases

Each individual test is called a test case. In Jest, you define test cases with test() or its alias, it():

test('adds 1 + 2 to make 3', () => {
expect(1 + 2).toBe(3);
});

Matching

Matchers are functions that compare the expected result with the actual result. Jest has a large number of matchers:

  • .toBe(value) for primitive values
  • .toEqual(value) for objects and arrays
  • .toBeTruthy() and .toBeFalsy()
  • .toContain(item) for arrays
  • .toThrow(error) for exceptions

Build and dismantle

Sometimes you need to prepare the environment before you can run tests. Jest offers lifecycle hooks:

  • beforeEach(): Runs before every test in a suite.
  • afterEach(): Runs after each test.
  • beforeAll(): Runs once before all tests in a suite.
  • afterAll(): Runs once after all tests.
    Example:
beforeEach(() => {
initializeDatabase();
});
afterEach(() => {
clearDatabase();
});

Write your first test

Let’s write a simple test to see Jest in action.

Step 1: Create the code to be tested

Create a file called sum.js:

function sum(a, b) {
return a + b;
}
module.exports = sum;

Step 2: Writing the test

Create a test file called sum.test.js:

const sum = require('./sum');
test('add 1 + 2 to get 3', () => {
expect(sum(1, 2)).toBe(3);
});

Step 3: Execute the test

Start Jest via your terminal:

npm test

You will see an output like this:

PASS ./sum.test.js
✓ adds 1 + 2 to 3 (5ms)

Congratulations! You have just written your first Jest test.

Testing asynchronous code

JavaScript is asynchronous by nature, and Jest makes it easy to test asynchronous code.

Callbacks

For callback-based code, use the done parameter:

test('fetch data with callback', (done) => {
fetchData((data) => {
expect(data).toBe('Hello, Jest!');
done();
});
});

Promise

For promise-based code, you return the promise from your test:

test('fetch data with promise', () => {
return fetchData().then((data) => {
expect(data).toBe('Hello, Jest!');
});
});

Async/Await

Use the modern async/await syntax for cleaner tests:

test('fetch data with async/await', async () => {
const data = await fetchData();
expect(data).toBe('Hello, Jest!');
});

Mocking in Jest

Mocks are important to isolate your tests. With Jest, mocking functions and modules is a breeze.

Mock functions

Mock a function with jest.fn():

const mockFn = jest.fn();
mockFn('test');
expect(mockFn).toHaveBeenCalledWith('test');

Mock modules

Mock an entire module with jest.mock():

jest.mock('./api');
const api = require('./api');
api.getData.mockResolvedValue('Mocked Data');
expect(await api.getData()).toBe('Mocked Data');

Testing React components with Jest.js

Combine Jest with the React Testing Library to test React components.

Install React Testing Library

npm install @testing-library/react

Write a test

Here is an example of testing a button component:

import { render, fireEvent } from '@testing-library/react';
import Button from './Button';
test('calls onClick when clicked', () => {
const handleClick = jest.fn();
const { getByText } = render(Click Me);
fireEvent.click(getByText('Click Me'));
expect(handleClick).toHaveBeenCalledTimes(1);
});

Snapshot testing

Snapshot testing is to ensure that your user interface does not change unexpectedly.

Example of Snapshot Testing

Render your component and save a snapshot:

import { render } from '@testing-library/react';
import MyComponent from './MyComponent';
test('matches snapshot', () => {
const { asFragment } = render();
expect(asFragment()).toMatchSnapshot();
});

If the component changes, Jest warns you to update the snapshot.

Extended Jest functions

Coverage reports

Check the code coverage:

npm test -- --coverage

Monitoring mode

Run tests interactively:

npm test -- - --watch

Custom matchers

Add custom matchers with libraries like jest-extended.

Common pitfalls in testing and how to avoid them

  • Test implementation instead of behavior: Focus on what the code does, not how it works.
  • Omit edge cases: Write tests for edge cases to ensure robustness.
  • Overuse mocks: Use mocks only when necessary to make the tests meaningful.

Best practices for testing with Jest.js

  • Test the behavior, not the implementation
  • Keep tests small and focused
  • Execute tests frequently
  • Write meaningful names for the tests

Conclusion

Testing with Jest.js doesn’t have to be intimidating. With its simple syntax and powerful features, Jest makes testing a natural part of your development process. By now, you should feel comfortable writing reliable and maintainable tests for your JavaScript projects. Have fun testing!