TypeScript Testing (Jest/Mocha)
Writing and running tests for TypeScript applications
๐งช What is TypeScript Testing?
Testing ensures your TypeScript code works correctly. Jest and Mocha are popular testing frameworks that help you write automated tests, catch bugs early, and maintain code quality with type-safe test suites.
// Simple test example
function add(a: number, b: number): number {
return a + b;
}
test('adds 1 + 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});
Testing Frameworks
Jest
All-in-one testing framework
describe('Calculator', () => {
test('adds numbers', () => {
expect(2 + 2).toBe(4);
});
});
Mocha
Flexible testing framework
describe('Calculator', () => {
it('adds numbers', () => {
assert.equal(2 + 2, 4);
});
});
Assertions
Verify expected outcomes
expect(value).toBe(5);
expect(array).toContain('item');
expect(obj).toHaveProperty('key');
Mocking
Simulate dependencies
const mockFn = jest.fn();
mockFn.mockReturnValue(42);
expect(mockFn()).toBe(42);
๐น Setting Up Jest
Install Jest for TypeScript:
# Install Jest and TypeScript support
npm install --save-dev jest @types/jest ts-jest
# Initialize Jest configuration
npx ts-jest config:init
Create jest.config.js :
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: ['<rootDir>/src'],
testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
collectCoverageFrom: ['src/**/*.ts'],
};
๐น Writing Jest Tests
Create a test file calculator.test.ts :
// calculator.ts
export class Calculator {
add(a: number, b: number): number {
return a + b;
}
subtract(a: number, b: number): number {
return a - b;
}
multiply(a: number, b: number): number {
return a * b;
}
}
// calculator.test.ts
import { Calculator } from './calculator';
describe('Calculator', () => {
let calculator: Calculator;
beforeEach(() => {
calculator = new Calculator();
});
test('should add two numbers', () => {
expect(calculator.add(2, 3)).toBe(5);
});
test('should subtract two numbers', () => {
expect(calculator.subtract(5, 3)).toBe(2);
});
test('should multiply two numbers', () => {
expect(calculator.multiply(4, 3)).toBe(12);
});
});
๐น Setting Up Mocha
Install Mocha with TypeScript:
# Install Mocha, Chai, and TypeScript support
npm install --save-dev mocha @types/mocha chai @types/chai ts-node
Create .mocharc.json :
{
"require": ["ts-node/register"],
"extensions": ["ts"],
"spec": ["src/**/*.test.ts"],
"watch-files": ["src"]
}
๐น Writing Mocha Tests
Create a test file with Mocha and Chai:
// user.ts
export interface User {
id: number;
name: string;
email: string;
}
export class UserService {
private users: User[] = [];
addUser(user: User): void {
this.users.push(user);
}
getUser(id: number): User | undefined {
return this.users.find(u => u.id === id);
}
getAllUsers(): User[] {
return this.users;
}
}
// user.test.ts
import { expect } from 'chai';
import { UserService, User } from './user';
describe('UserService', () => {
let userService: UserService;
beforeEach(() => {
userService = new UserService();
});
it('should add a user', () => {
const user: User = { id: 1, name: 'John', email: '[email protected]' };
userService.addUser(user);
expect(userService.getAllUsers()).to.have.lengthOf(1);
});
it('should get user by id', () => {
const user: User = { id: 1, name: 'John', email: '[email protected]' };
userService.addUser(user);
const found = userService.getUser(1);
expect(found).to.deep.equal(user);
});
it('should return undefined for non-existent user', () => {
const found = userService.getUser(999);
expect(found).to.be.undefined;
});
});
๐น Common Jest Matchers
Useful assertions for testing:
// Equality
expect(value).toBe(5); // Strict equality
expect(obj).toEqual({ name: 'John' }); // Deep equality
// Truthiness
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();
// Numbers
expect(value).toBeGreaterThan(3);
expect(value).toBeLessThanOrEqual(10);
// Strings
expect(str).toMatch(/pattern/);
expect(str).toContain('substring');
// Arrays
expect(array).toContain('item');
expect(array).toHaveLength(3);
// Objects
expect(obj).toHaveProperty('key');
expect(obj).toMatchObject({ name: 'John' });
๐น Async Testing
Test asynchronous code:
// Async function to test
async function fetchUser(id: number): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
// Jest async test
test('fetches user data', async () => {
const user = await fetchUser(1);
expect(user.id).toBe(1);
expect(user.name).toBeDefined();
});
// Mocha async test
it('fetches user data', async () => {
const user = await fetchUser(1);
expect(user.id).to.equal(1);
expect(user.name).to.exist;
});
๐น Mocking with Jest
Mock functions and modules:
// Mock a function
const mockCallback = jest.fn((x: number) => x * 2);
test('mock function', () => {
mockCallback(2);
mockCallback(4);
expect(mockCallback).toHaveBeenCalledTimes(2);
expect(mockCallback).toHaveBeenCalledWith(2);
expect(mockCallback(3)).toBe(6);
});
// Mock a module
jest.mock('./api');
import { fetchData } from './api';
test('mocked API call', async () => {
(fetchData as jest.Mock).mockResolvedValue({ data: 'test' });
const result = await fetchData();
expect(result.data).toBe('test');
});
๐น Running Tests
Add test scripts to package.json :
{
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"test:mocha": "mocha"
}
}
Run tests:
# Run all tests
npm test
# Watch mode (re-run on changes)
npm run test:watch
# Generate coverage report
npm run test:coverage