Installation and Setup
npm install --save-dev jest
Basic Test Structure
// file.test.js|ts
describe("Subject of something to test", () => {
describe("block1", () => {
test("test point1-1", () => {
// test content
});
it("test point1-2", () => {
// test content
});
});
describe("block2", () => {
it("test point2-1", () => {
// test content
});
it("test point2-2", () => {
// test content
});
});
});
Running Tests
# Run all tests
jest
# Run single test file
jest path/to/my-test.js
# Test specific directory
jest api/
# Filter tests by filename pattern
jest --testPathPattern=api
# Match tests by name pattern
jest -t "Math" # Matches describe("Math test", fn)
Test Scope Control
// Run only this test in a suite
it.only("test example", fn)
// Skip this test
it.skip("test example", fn)
Setup and Teardown
Global Setup (jest.config.js)
module.exports = {
setupFiles: ["./tests/setup.ts"],
};
Setup File (setup.ts)
// Global setup (runs once before all tests)
beforeAll(() => {
// Connect to test database
});
// Global teardown (runs once after all tests)
afterAll(() => {
// Drop database or close connection
});
Scoped Setup (within test file)
// Applies to all tests in this file
beforeEach(() => {
return initializeCityDatabase();
});
test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});
describe('matching cities to foods', () => {
// Applies only to tests in this describe block
beforeEach(() => {
return initializeFoodDatabase();
});
test('Vienna <3 veal', () => {
expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
});
});
Common Matchers
Basic Equality
expect(fn).toBe(value) // Strict equality (===)
expect(n).not.toBe(value) // Negation
expect(fn).toEqual(value) // Value equality
Truthiness
expect(n).toBeNull();
expect(n).toBeDefined();
expect(n).not.toBeUndefined();
expect(n).not.toBeTruthy();
expect(n).toBeFalsy(); // Matches false, null, undefined, "", 0
Numbers
expect(value).toBeGreaterThan(3);
expect(value).toBeGreaterThanOrEqual(3.5);
expect(value).toBeLessThan(5);
expect(value).toBeLessThanOrEqual(4.5);
Strings
expect(string).toMatch(/stop/);
expect(string).not.toMatch(/I/);
Exceptions
function compileAndroidCode() {
throw new Error('you are using the wrong JDK!');
}
test('compiling android goes as expected', () => {
expect(() => compileAndroidCode()).toThrow();
expect(() => compileAndroidCode()).toThrow(Error);
expect(() => compileAndroidCode()).toThrow("error message");
});
Functions
// The mock function was called at least once
expect(mockFunc).toHaveBeenCalled();
// Called with specific arguments
expect(mockFunc).toHaveBeenCalledWith(arg1, arg2);
// Last call was with specific arguments
expect(mockFunc).toHaveBeenLastCalledWith(arg1, arg2);
// Compare to snapshot
expect(mockFunc).toMatchSnapshot();
Mock Functions
Basic Mock Usage
// forEach.js
export function forEach(items, callback) {
for (const item of items) {
callback(item);
}
}
// Test file
import { forEach } from './forEach';
test("test a function using mock parameter", () => {
const mockCb = jest.fn(x => x + 3);
forEach([0, 1], mockCb);
// Called 2 times
expect(mockCb.mock.calls).toHaveLength(2);
// First argument of first call was 0
expect(mockCb.mock.calls[0][0]).toBe(0);
// Return value of first call was 3
expect(mockCb.mock.results[0].value).toBe(3);
});
Mock Return Values
const myMock = jest.fn();
myMock.mockReturnValueOnce(10)
.mockReturnValueOnce('x')
.mockReturnValue(true);
console.log(myMock()); // 10
console.log(myMock()); // 'x'
console.log(myMock()); // true
Mock Implementations
const myMockFn = jest
.fn()
.mockReturnValue('default')
.mockImplementation(scalar => 42 + scalar)
.mockName('add42'); // Custom name for error messages
Mocking Modules
// app.js
import { add } from './math';
export function calculateTotal(x, y) {
return add(x, y);
}
// Test file
import * as math from './math';
import { calculateTotal } from './app';
jest.mock('./math'); // Automatically replaces all exports with mocks
test('calculateTotal uses mocked add', () => {
math.add.mockReturnValue(100);
const result = calculateTotal(1, 2); // Returns 100 instead of 3
expect(result).toBe(100);
});
Important Note on TypeScript Support
Although Jest is a classical full-functional testing framework, its native support for TypeScript is limited and relies on Babel for transpilation. This can lead to complex configuration and sometimes suboptimal developer experience.
For better TypeScript integration, consider these alternatives:
-
ts-jest: A Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.
-
Vitest: A modern testing framework built on Vite that provides excellent TypeScript support out of the box, with faster execution and a more intuitive developer experience. Many developers report significantly better testing experiences with Vitest when working with TypeScript projects.