Testing is one of the most important practices in modern software development. Writing tests helps developers catch bugs early, improve code quality, and confidently release new features without breaking existing functionality.
Among the many testing frameworks available today, Jest has become one of the most popular choices for JavaScript and Node.js applications due to its simplicity, speed, and extensive feature set.
In this complete tutorial, you'll learn how to get started with Jest, write different types of tests, use mocks, measure code coverage, and follow testing best practices.
What Is Jest?
Jest is an open-source JavaScript testing framework developed by Meta (Facebook). It provides everything needed for testing JavaScript applications, including:
- Test runner
- Assertion library
- Mocking capabilities
- Code coverage reporting
- Snapshot testing
Jest works well with:
- JavaScript
- TypeScript
- Node.js
- React
- Next.js
- Express.js
Why Use Jest?
Jest offers several advantages compared to other testing frameworks.
Easy Setup
Jest requires minimal configuration and can be added to most projects within minutes.
Fast Performance
Tests run in parallel, making execution faster even in large projects.
Built-In Mocking
Jest includes powerful mocking tools without requiring additional libraries.
Code Coverage
Generate detailed reports showing which parts of your code are covered by tests.
Great Developer Experience
Readable syntax and helpful error messages make debugging easier.
Installing Jest
Create a new Node.js project:
npm init -y
Install Jest:
npm install --save-dev jest
Update your package.json:
{
"scripts": {
"test": "jest"
}
}
Now run:
npm test
Jest is ready to use.
Writing Your First Test
Create a file:
sum.js
function sum(a, b) {
return a + b;
}
module.exports = sum;
Create a test file:
sum.test.js
const sum = require("./sum");
test("adds two numbers", () => {
expect(sum(2, 3)).toBe(5);
});
Run:
npm test
Output:
PASS sum.test.js
Congratulations! You just wrote your first Jest test.
Understanding Test Structure
A typical Jest test looks like this:
test("description", () => {
expect(actual).toBe(expected);
});
Components:
-
test()defines a test case -
expect()creates an assertion -
toBe()compares values
Common Matchers
toBe()
expect(10).toBe(10);
toEqual()
Useful for objects and arrays:
expect({
name: "John"
}).toEqual({
name: "John"
});
toContain()
expect(["apple", "banana"])
.toContain("banana");
toBeTruthy()
expect(true).toBeTruthy();
toBeFalsy()
expect(false).toBeFalsy();
toThrow()
expect(() => {
throw new Error();
}).toThrow();
Grouping Tests
Use describe() to organize related tests.
describe("Math Functions", () => {
test("addition", () => {
expect(2 + 2).toBe(4);
});
test("subtraction", () => {
expect(5 - 2).toBe(3);
});
});
This improves readability in larger test suites.
Testing Async Functions
Create:
async function fetchUser() {
return {
id: 1,
name: "John"
};
}
module.exports = fetchUser;
Test:
const fetchUser =
require("./fetchUser");
test("returns user data", async () => {
const user =
await fetchUser();
expect(user.name)
.toBe("John");
});
Jest handles asynchronous testing seamlessly.
Mock Functions
Mocks allow you to simulate behavior without calling real implementations.
Example:
const mockFunction =
jest.fn();
mockFunction();
expect(mockFunction)
.toHaveBeenCalled();
Verify call count:
expect(mockFunction)
.toHaveBeenCalledTimes(1);
Mocking API Calls
Example:
global.fetch = jest.fn(() =>
Promise.resolve({
json: () =>
Promise.resolve({
success: true
})
})
);
Now your tests can run without making real API requests.
Mocking Modules
Suppose you have:
const database =
require("./database");
Mock it:
jest.mock("./database");
Define behavior:
database.getUser.mockReturnValue({
id: 1,
name: "John"
});
This isolates your unit tests from external systems.
Setup and Cleanup
Run code before each test:
beforeEach(() => {
});
Run code after each test:
afterEach(() => {
});
Example:
beforeEach(() => {
console.log("Setup");
});
afterEach(() => {
console.log("Cleanup");
});
Useful for resetting mocks and preparing test environments.
Measuring Code Coverage
Run:
npx jest --coverage
Example output:
Statements : 95%
Branches : 90%
Functions : 100%
Lines : 95%
Coverage reports help identify untested code.
Testing Express APIs
Example route:
app.get("/users", (req, res) => {
res.json({
success: true
});
});
Install Supertest:
npm install supertest
Test:
const request =
require("supertest");
test("GET /users", async () => {
const response =
await request(app)
.get("/users");
expect(response.status)
.toBe(200);
});
This allows API endpoint testing without launching a real server.
Snapshot Testing
Snapshot testing is commonly used in React applications.
expect(component)
.toMatchSnapshot();
Jest stores snapshots and compares future renders automatically.
This helps detect unexpected UI changes.
Best Practices
Keep Tests Independent
Each test should run successfully on its own.
Test Behavior, Not Implementation
Focus on outcomes rather than internal code structure.
Use Descriptive Test Names
Bad:
test("test1")
Good:
test("returns user when ID exists")
Mock External Dependencies
Avoid real API calls and database operations in unit tests.
Maintain High Coverage
Aim for meaningful coverage rather than simply increasing percentages.
Conclusion
Jest has become the go-to testing framework for JavaScript developers because it combines simplicity, speed, and powerful testing capabilities into a single package.
Whether you're testing utility functions, APIs, React components, or complete Node.js applications, Jest provides the tools needed to build reliable software with confidence.
By mastering unit testing, mocking, asynchronous testing, and code coverage, you'll be able to catch bugs earlier, improve code quality, and ship features faster.
Top comments (0)