Unit Testing with Jest
Master unit testing with Jest framework for reliable JavaScript applications. This is a foundational concept in programming and web interactivity that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world JavaScript experience. Take your time with each section and practice the examples
Jest Setup & Configuration
Jest is a JavaScript testing framework that provides a complete testing solution with built-in mocking, assertions, and test runners.. This is an essential concept that every JavaScript developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
Basic Test Structure
// Basic Jest test
describe('Calculator', () => {
test('adds 1 + 2 to equal 3', () => {
expect(1 + 2).toBe(3);
});
test('multiplies 3 * 4 to equal 12', () => {
expect(3 * 4).toBe(12);
});
});Testing Functions
// Function to test
function add(a, b) {
return a + b;
}
function divide(a, b) {
if (b === 0) throw new Error('Division by zero');
return a / b;
}
// Tests
describe('Math Functions', () => {
test('add function works correctly', () => {
expect(add(2, 3)).toBe(5);
expect(add(-1, 1)).toBe(0);
expect(add(0, 0)).toBe(0);
});
test('divide function handles division by zero', () => {
expect(() => divide(5, 0)).toThrow('Division by zero');
expect(divide(10, 2)).toBe(5);
});
});Mocking & Spies
// Mock functions
const mockCallback = jest.fn();
mockCallback('test');
expect(mockCallback).toHaveBeenCalledWith('test');
// Mock modules
jest.mock('./api', () => ({
fetchUser: jest.fn(() => Promise.resolve({ id: 1, name: 'John' }))
}));Async Testing
// Testing async functions
async function fetchData() {
const response = await fetch('/api/data');
return response.json();
}
test('fetchData returns data', async () => {
const data = await fetchData();
expect(data).toBeDefined();
});Mini-Project: Complete Test Suite
// UserService.js
class UserService {
constructor(apiClient) {
this.apiClient = apiClient;
}
async getUser(id) {
if (!id) throw new Error('User ID is required');
return await this.apiClient.fetchUser(id);
}
async createUser(userData) {
if (!userData.name) throw new Error('Name is required');
return await this.apiClient.createUser(userData);
}
}
// UserService.test.js
describe('UserService', () => {
let userService;
let mockApiClient;
beforeEach(() => {
mockApiClient = {
fetchUser: jest.fn(),
createUser: jest.fn()
};
userService = new UserService(mockApiClient);
});
describe('getUser', () => {
test('should fetch user successfully', async () => {
const mockUser = { id: 1, name: 'John' };
mockApiClient.fetchUser.mockResolvedValue(mockUser);
const result = await userService.getUser(1);
expect(mockApiClient.fetchUser).toHaveBeenCalledWith(1);
expect(result).toEqual(mockUser);
});
test('should throw error for invalid ID', async () => {
await expect(userService.getUser(null)).rejects.toThrow('User ID is required');
});
});
});