Jest
01 / 03

Test Basics & Matchers

Test Basics & Matchers

Structure

// Organizing tests
describe('UserService', () => {
  describe('create', () => {
    it('should create a user with valid data', () => { ... });
    it('should throw when email is invalid', () => { ... });
  });

  describe('delete', () => {
    test('removes the user from db', () => { ... });
  });
});

// Setup and teardown
beforeAll(async () => {
  await db.connect();       // runs once before all tests in file
});

afterAll(async () => {
  await db.disconnect();    // runs once after all tests in file
});

beforeEach(() => {
  jest.clearAllMocks();     // before each test in the block
});

afterEach(async () => {
  await db.rollback();      // after each test in the block
});

Matchers

// Equality
expect(value).toBe(42);             // strict equality (Object.is)
expect(obj).toEqual({ a: 1 });      // deep equality
expect(obj).toStrictEqual({ a: 1 }); // deep equality + type check (undefined vs missing)
expect(obj).not.toBe(other);

// Truthiness
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();
expect(value).toBeDefined();

// Numbers
expect(n).toBeGreaterThan(5);
expect(n).toBeGreaterThanOrEqual(5);
expect(n).toBeLessThan(10);
expect(0.1 + 0.2).toBeCloseTo(0.3, 5);  // floating point

// Strings
expect(str).toContain('substring');
expect(str).toMatch(/regex/);
expect(str).toMatch('substring');
expect(str).toHaveLength(5);

// Arrays
expect(arr).toContain(42);
expect(arr).toContainEqual({ id: 1 });  // deep
expect(arr).toHaveLength(3);
expect(arr).toEqual(expect.arrayContaining([1, 2]));  // subset

// Objects
expect(obj).toHaveProperty('user.name');
expect(obj).toHaveProperty('count', 5);
expect(obj).toMatchObject({ status: 'ok' });  // partial match

// Errors
expect(() => fn()).toThrow();
expect(() => fn()).toThrow('error message');
expect(() => fn()).toThrow(TypeError);
await expect(asyncFn()).rejects.toThrow('error');
await expect(asyncFn()).rejects.toMatchObject({ statusCode: 404 });

// Asymmetric matchers
expect(user).toEqual({
  id: expect.any(Number),
  email: expect.stringContaining('@'),
  roles: expect.arrayContaining(['user']),
  createdAt: expect.any(Date),
});

Async Tests

// Async/await — preferred
it('should fetch user', async () => {
  const user = await getUser(1);
  expect(user.name).toBe('Alice');
});

// Promises
it('should fetch user', () => {
  return getUser(1).then(user => {
    expect(user.name).toBe('Alice');
  });
});

// resolves/rejects matchers
it('should resolve', async () => {
  await expect(getUser(1)).resolves.toMatchObject({ name: 'Alice' });
});

it('should reject', async () => {
  await expect(getUser(-1)).rejects.toThrow('Not found');
});

// Timeout override
it('slow test', async () => {
  await slowOperation();
}, 10000);  // 10 second timeout

Test Configuration

// jest.config.ts
export default {
  preset: 'ts-jest',
  testEnvironment: 'node',           // or 'jsdom' for browser
  setupFilesAfterFramework: ['<rootDir>/jest.setup.ts'],
  collectCoverage: true,
  coverageThreshold: {
    global: { branches: 70, functions: 80, lines: 80, statements: 80 }
  },
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',  // path aliases
  },
  testPathIgnorePatterns: ['/node_modules/', '/dist/'],
  testMatch: ['**/__tests__/**/*.ts', '**/*.test.ts', '**/*.spec.ts'],
};

// package.json scripts
{
  "test": "jest",
  "test:watch": "jest --watch",
  "test:coverage": "jest --coverage",
  "test:ci": "jest --ci --coverage --reporters=default --reporters=jest-junit"
}

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free