Posted in

Writing Unit Tests with Jest: A Complete Guide for JavaScript Developers

Writing Unit Tests with Jest: A Complete Guide for JavaScript Developers

In modern JavaScript development, writing clean and reliable code is only half the battle. The other half is ensuring that the code behaves as expected — now and in the future. This is where unit testing comes into play, and among the many testing frameworks available, Jest has emerged as the most popular choice for JavaScript and React developers.

In this blog, we’ll take a deep dive into unit testing with Jest, understand how it works, write various types of tests, and follow best practices to ensure maintainability and scalability of your test suites.

What is Unit Testing?

Unit testing involves testing individual pieces (units) of code in isolation to verify they work as intended. These “units” are typically functions or methods in your codebase.

Why Unit Test?

  • Detect bugs early
  • Ensure code reliability
  • Refactor safely
  • Improve documentation
  • Enable CI/CD workflows

What is Jest?

Jest is a delightful JavaScript Testing Framework developed by Meta (Facebook). It works out-of-the-box for most JavaScript projects and includes powerful features like:

  • Zero configuration
  • Test runners
  • Snapshot testing
  • Code coverage
  • Mocking
  • Parallel test execution

Jest is especially popular in React projects, but it works just as well in Node.js and vanilla JavaScript projects.

Getting Started with Jest

1. Install Jest

To install Jest in your project, run:

npm install --save-dev jest

Update the package.json to add a test script:

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

Create a sum.js file:

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

module.exports = sum;

Now create a test file named sum.test.js:

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

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

Run your test:

npm test

Anatomy of a Jest Test

test('description of the test', () => {
// Arrange: Setup the necessary data
// Act: Call the function under test
// Assert: Check the expected result
});

Or using describe blocks for grouping:

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

Common Matchers in Jest

Jest provides rich matchers via the expect() API.

MatcherDescription
.toBe()Exact match (===)
.toEqual()Deep equality (objects, arrays)
.toBeNull()Checks for null
.toBeTruthy()Checks if value is true in boolean
.toContain()Array or string contains value
.toThrow()Function throws an error

Example:

expect([1, 2, 3]).toContain(2);
expect(() => someFunc()).toThrow('error message');

Testing Async Code

Async/Await Example:

async function fetchData() {
return 'data';
}

test('fetches data', async () => {
const data = await fetchData();
expect(data).toBe('data');
});

Using .resolves and .rejects:

ttest('resolves to data', () => {
return expect(fetchData()).resolves.toBe('data');
});

Mocking Functions in Jest

Jest makes mocking easy using jest.fn().

Manual Mock Example:

const mockFn = jest.fn();
mockFn('hello');

expect(mockFn).toHaveBeenCalledWith('hello');

Mocking External Modules:

Suppose you want to mock axios:

jest.mock('axios');
const axios = require('axios');

axios.get.mockResolvedValue({ data: 'Mocked Data' });

Testing React Components (Bonus)

With React, use @testing-library/react alongside Jest:

npm install --save-dev @testing-library/react
// Button.js
export default function Button({ onClick }) {
return <button onClick={onClick}>Click me</button>;
}
// Button.test.js
import { render, fireEvent } from '@testing-library/react';
import Button from './Button';

test('calls onClick when clicked', () => {
const handleClick = jest.fn();
const { getByText } = render(<Button onClick={handleClick} />);
fireEvent.click(getByText('Click me'));
expect(handleClick).toHaveBeenCalledTimes(1);
});

Generating Code Coverage Report

Run Jest with the --coverage flag:

npm test -- --coverage

It will generate a coverage report like this:

File       | % Stmts | % Branch | % Funcs | % Lines
-----------|---------|----------|---------|---------
sum.js | 100 | 100 | 100 | 100

Best Practices for Writing Unit Tests

  1. Test one thing per test case – Keep tests focused.
  2. Use descriptive test names – Improve readability.
  3. Arrange-Act-Assert pattern – Structure test cases clearly.
  4. Avoid testing implementation details – Focus on behavior.
  5. Mock dependencies, not your own code – Mock only external APIs.
  6. Keep tests fast and isolated – They shouldn’t rely on DBs or APIs.
  7. Run tests frequently – Integrate with CI pipelines.

TDD with Jest (Test Driven Development)

  1. Write a failing test – Define the expected behavior.
  2. Write the minimal code – Make the test pass.
  3. Refactor confidently – Rely on passing tests for validation.

This encourages cleaner, well-designed, and better-tested code.

Useful Jest Plugins & Tools

Sample Project Structure for Testing

my-app/
├── src/
│ ├── utils/
│ │ └── sum.js
│ ├── components/
│ │ └── Button.js
├── tests/
│ ├── unit/
│ │ └── sum.test.js
│ ├── integration/
│ │ └── api.test.js

Separate test types for better organization and maintainability.

Conclusion

Unit testing isn’t just a safety net — it’s a way to build confidence, write robust code, and move fast without breaking things. With Jest, testing becomes seamless, powerful, and even enjoyable.

Whether you’re building small utility functions or complex React applications, integrating Jest into your workflow is one of the smartest investments you can make.

Ready to Test Smarter?

Try converting one of your existing JavaScript files into a testable module and write a simple Jest test for it. Practice will make you more fluent, and Jest will become a natural part of your dev toolkit.

Useful Resources