When building backend applications with Node.js, most developers focus heavily on APIs, databases, and business logic—but often skip testing until bugs start showing up.
Unit testing helps you catch bugs early, improve code quality, and refactor with confidence.
In this blog, we’ll learn how to set up unit testing in a Node.js + TypeScript project using Jest.
What is Unit Testing?
Unit testing means testing small isolated pieces of code (functions, services, controllers) to verify they work as expected.
Example:
Instead of testing the full API flow:
Client → Route → Controller → Database
We test only:
Function → Input → Expected Output
This makes debugging faster and easier.
Why Use Jest?
Jest is one of the most popular testing frameworks because it provides:
✅ Zero-config setup
✅ Fast execution
✅ Mocking support
✅ Built-in assertions
✅ TypeScript support
✅ Code coverage reports
Step 1: Create a Node.js Project
Initialize a project:
npm init -y
Install TypeScript:
npm install typescript ts-node @types/node -D
Initialize TypeScript config:
npx tsc --init
Step 2: Install Jest
Install Jest and TypeScript support:
npm install jest ts-jest @types/jest -D
Initialize Jest config:
npx ts-jest config:init
This creates:
jest.config.js
Step 3: Configure TypeScript
Update tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"esModuleInterop": true,
"strict": true
}
}
Important settings:
-
target→ JavaScript version output -
module→ module system -
esModuleInterop→ better import compatibility
Step 4: Create Sample Code
Project structure:
src/
├── controllers/
│ └── itemController.ts
├── models/
│ └── item.ts
tests/
└── itemController.test.ts
Create model:
// src/models/item.ts
export const items: string[] = [];
Create controller:
// src/controllers/itemController.ts
import { Request, Response } from 'express';
import { items } from '../models/item';
export const getItems = (
req: Request,
res: Response
) => {
res.json(items);
};
Step 5: Write Your First Test
Create:
// tests/itemController.test.ts
import { Request, Response } from 'express';
import { getItems } from '../src/controllers/itemController';
import { items } from '../src/models/item';
describe('Item Controller', () => {
it('should return empty array', () => {
const req = {} as Request;
const res = {
json: jest.fn()
} as unknown as Response;
items.length = 0;
getItems(req, res);
expect(res.json).toHaveBeenCalledWith([]);
});
});
Understanding the Test
describe()
Groups related tests.
describe('Item Controller', () => {})
it()
Defines a single test case.
it('should return empty array', () => {})
jest.fn()
Creates a mock function.
json: jest.fn()
Useful for checking:
- was it called?
- how many times?
- what arguments?
expect()
Assertion API.
expect(res.json).toHaveBeenCalledWith([]);
Verifies output.
Step 6: Add Test Script
Update package.json
{
"scripts": {
"test": "jest"
}
}
Run tests:
npm test
Output:
PASS tests/itemController.test.ts
Common Jest Matchers
Check equality
expect(value).toBe(10);
Check object equality
expect(obj).toEqual({});
Check if function was called
expect(mockFn).toHaveBeenCalled();
Check call count
expect(mockFn).toHaveBeenCalledTimes(1);
Mocking Dependencies
Suppose your controller calls a service:
import { getData } from './service';
Mock it:
jest.mock('./service');
Set return value:
(getData as jest.Mock).mockReturnValue([]);
This isolates your unit.
Running Coverage
Generate coverage report:
npm test -- --coverage
Output:
Statements : 95%
Branches : 90%
Functions : 100%
Lines : 96%
Aim for good coverage, not just high numbers.
Best Practices
Keep tests isolated
Each test should run independently.
Mock external dependencies
Avoid hitting real databases or APIs.
Use descriptive test names
Good:
should return empty items array
Bad:
test 1
Follow AAA Pattern
Arrange → Act → Assert
Example:
// Arrange
const req = {};
// Act
getItems(req, res);
// Assert
expect(res.json).toHaveBeenCalled();
Final Thoughts
Unit testing is not optional in production-grade applications.
With Jest, getting started is simple:
- Install Jest
- Configure TypeScript
- Write tests
- Mock dependencies
- Run coverage
Start small.
Test one controller.
Then one service.
Then one utility.
Over time, your project becomes safer, cleaner, and easier to maintain.
Your future self will thank you.
Top comments (0)