Testing Node.js with Jest
Write tests for Node.js applications using Jest. Learn unit tests, mocking, and testing async code.
Testing Node.js with Jest
Jest is the most popular testing framework. Simple, fast, feature-rich.
Setup
```bash npm install --save-dev jest ```
```json // package.json { "scripts": { "test": "jest", "test:watch": "jest --watch" } } ```
First Test
```javascript // math.js function add(a, b) { return a + b; } module.exports = { add };
// math.test.js const { add } = require('./math');
test('adds 1 + 2 to equal 3', () => { expect(add(1, 2)).toBe(3); }); ```
Run: `npm test`
Common Matchers
```javascript // Equality expect(2 + 2).toBe(4); expect({ name: 'Alice' }).toEqual({ name: 'Alice' });
// Truthiness expect(null).toBeNull(); expect(undefined).toBeUndefined(); expect(true).toBeTruthy(); expect(false).toBeFalsy();
// Numbers expect(4).toBeGreaterThan(3); expect(4).toBeLessThan(5); expect(0.1 + 0.2).toBeCloseTo(0.3);
// Strings expect('team').toMatch(/tea/);
// Arrays expect(['Alice', 'Bob']).toContain('Alice');
// Exceptions expect(() => throwError()).toThrow(); expect(() => throwError()).toThrow('error message'); ```
Grouping Tests
```javascript describe('Math functions', () => { describe('add', () => { test('adds positive numbers', () => { expect(add(1, 2)).toBe(3); }); test('adds negative numbers', () => { expect(add(-1, -2)).toBe(-3); }); }); describe('multiply', () => { test('multiplies numbers', () => { expect(multiply(2, 3)).toBe(6); }); }); }); ```
Testing Async Code
```javascript // With async/await test('fetches user', async () => { const user = await fetchUser(1); expect(user.name).toBe('Alice'); });
// With promises test('fetches user', () => { return fetchUser(1).then(user => { expect(user.name).toBe('Alice'); }); });
// With done callback test('fetches user', (done) => { fetchUser(1, (user) => { expect(user.name).toBe('Alice'); done(); }); }); ```
Mocking
```javascript // Mock function const mockFn = jest.fn(); mockFn('hello');
expect(mockFn).toHaveBeenCalled(); expect(mockFn).toHaveBeenCalledWith('hello'); expect(mockFn).toHaveBeenCalledTimes(1);
// Mock return value const mockFn = jest.fn().mockReturnValue(42); expect(mockFn()).toBe(42);
// Mock async const mockAsync = jest.fn().mockResolvedValue({ id: 1 }); await mockAsync(); ```
Mocking Modules
```javascript // Mock entire module jest.mock('./database'); const db = require('./database');
db.query.mockResolvedValue([{ id: 1, name: 'Alice' }]);
test('gets users from database', async () => { const users = await getUsers(); expect(users).toHaveLength(1); }); ```
Testing Express Routes
```javascript const request = require('supertest'); const app = require('./app');
describe('GET /api/users', () => { test('returns users', async () => { const response = await request(app) .get('/api/users') .expect('Content-Type', /json/) .expect(200); expect(response.body).toBeInstanceOf(Array); }); });
describe('POST /api/users', () => { test('creates user', async () => { const response = await request(app) .post('/api/users') .send({ name: 'Alice', email: 'alice@example.com' }) .expect(201); expect(response.body.name).toBe('Alice'); }); test('returns 400 for invalid data', async () => { await request(app) .post('/api/users') .send({ name: '' }) .expect(400); }); }); ```
Setup and Teardown
```javascript describe('User tests', () => { beforeAll(async () => { // Run once before all tests await connectDB(); }); afterAll(async () => { // Run once after all tests await disconnectDB(); }); beforeEach(async () => { // Run before each test await clearDatabase(); }); afterEach(() => { // Run after each test jest.clearAllMocks(); }); test('test 1', () => { ... }); test('test 2', () => { ... }); }); ```
Coverage
```bash npm test -- --coverage ```
```json // package.json { "jest": { "collectCoverageFrom": ["src/**/*.js"], "coverageThreshold": { "global": { "branches": 80, "functions": 80, "lines": 80 } } } } ```
Key Takeaway
Jest makes testing easy. Use `describe` to group tests, `test` for individual cases. Mock external dependencies. Test Express routes with supertest. Aim for high coverage but focus on meaningful tests.