Jest logoJestINTERMEDIATE

Jest

Jest cheat sheet with matchers, mock functions, async testing, snapshot tests, and TypeScript testing patterns with code examples.

12 min read
jesttestingunit-testingmockingtddjavascripttypescriptreact

Sign in to mark items as known and track your progress.

Sign in

Setup & Configuration

Installing and configuring Jest for your project

Installation & Basic Setup

Setting up Jest in your JavaScript/TypeScript project

javascript
# Install Jest
npm install --save-dev jest
# For TypeScript support
npm install --save-dev @types/jest ts-jest

# package.json scripts
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  }
}
💡 Use test:watch for TDD workflow with automatic re-runs
⚡ Add coverage thresholds to enforce code quality standards
📌 Configure testMatch to find your test files correctly
🟢 Start with node environment, switch to jsdom for DOM testing
setupconfiguration

Basic Testing

Writing your first tests with Jest

Test Structure & Basics

Organizing tests with describe, it, and test blocks

javascript
// Basic test structure
describe('Calculator', () => {
  test('adds 1 + 2 to equal 3', () => {
    expect(1 + 2).toBe(3)
  })

  it('subtracts 5 - 2 to equal 3', () => {
    expect(5 - 2).toBe(3)
  })
})

// Setup and teardown
describe('User Service', () => {
  let service

  beforeEach(() => {
    service = new UserService()
  })

  afterEach(() => {
    service.cleanup()
  })

  beforeAll(async () => {
    await database.connect()
  })

  afterAll(async () => {
    await database.disconnect()
  })
})
💡 Use describe blocks to group related tests logically
⚡ beforeEach/afterEach run for every test, beforeAll/afterAll run once
📌 test and it are aliases - use whichever reads better
🟢 Use test.only to focus on a single test during development
basicsstructure

Matchers

Jest matchers for different types of assertions

Common Matchers

Most frequently used Jest matchers for assertions

javascript
// Equality
expect(2 + 2).toBe(4)              // Exact equality ===
expect({name: 'jest'}).toEqual({name: 'jest'}) // Deep equality

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

// Numbers
expect(2 + 2).toBeGreaterThan(3)
expect(2 + 2).toBeGreaterThanOrEqual(4)
expect(2 + 2).toBeLessThan(5)
expect(0.1 + 0.2).toBeCloseTo(0.3) // For floating point

// Strings
expect('team').toMatch(/I/)
expect('Christoph').toMatch('stop')

// Arrays and Iterables
expect(['Alice', 'Bob']).toContain('Alice')
expect(new Set(['Alice', 'Bob'])).toContain('Alice')
expect(['Alice', 'Bob']).toHaveLength(2)
💡 Use toEqual for objects/arrays, toBe for primitives
⚡ toBeCloseTo is essential for floating point comparisons
📌 toStrictEqual checks undefined properties and array holes
🟢 Combine matchers with .not for negative assertions
matchersassertions

Custom Matchers

Creating your own Jest matchers for domain-specific assertions

typescript
// Define custom matcher
expect.extend({
  toBeWithinRange(received, floor, ceiling) {
    const pass = received >= floor && received <= ceiling
    if (pass) {
      return {
        message: () =>
          \`expected \${received} not to be within range \${floor} - \${ceiling}\`,
        pass: true,
      }
    } else {
      return {
        message: () =>
          \`expected \${received} to be within range \${floor} - \${ceiling}\`,
        pass: false,
      }
    }
  },
})

// Use custom matcher
test('numeric ranges', () => {
  expect(100).toBeWithinRange(90, 110)
  expect(101).not.toBeWithinRange(0, 100)
})
💡 Custom matchers improve test readability for domain logic
⚡ Add TypeScript definitions for autocomplete support
📌 Use setupFilesAfterEnv to load matchers globally
🟢 Asymmetric matchers allow flexible partial matching
matcherscustomadvanced

Mocking

Mocking functions, modules, and dependencies

Function Mocks

Creating and using mock functions (spies)

javascript
// Create a mock function
const mockFn = jest.fn()
mockFn('arg1', 'arg2')

// Mock with return value
const mockCallback = jest.fn(x => x * 2)
expect(mockCallback(5)).toBe(10)

// Mock implementation
const mockImplementation = jest.fn()
  .mockImplementation((x) => x + 1)
  .mockImplementationOnce((x) => x + 2)  // First call only

// Assertions on mocks
expect(mockFn).toHaveBeenCalled()
expect(mockFn).toHaveBeenCalledTimes(1)
expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2')
expect(mockFn).toHaveBeenLastCalledWith('arg1', 'arg2')
💡 Use mockImplementationOnce for different behavior per call
⚡ mockClear vs mockReset vs mockRestore have different scopes
📌 Access .mock property for detailed call information
🟢 jest.spyOn preserves original implementation by default
mockingfunctions

Module Mocks

Mocking entire modules and their exports

javascript
// Mock entire module
jest.mock('./api')
import * as api from './api'

// Mock with factory
jest.mock('./config', () => ({
  apiUrl: 'http://localhost',
  timeout: 1000
}))

// Partial mocks
jest.mock('./math', () => ({
  ...jest.requireActual('./math'),
  add: jest.fn(() => 5)
}))

// Mock ES6 classes
jest.mock('./UserService')
import UserService from './UserService'
const mockUserService = UserService as jest.MockedClass<typeof UserService>
💡 Place manual mocks in __mocks__ folder adjacent to module
⚡ Use requireActual for partial mocks to keep some real code
📌 Mock hoisting moves jest.mock to top of file automatically
🟢 TypeScript: cast mocked modules for proper types
mockingmodules

Async Testing

Testing asynchronous code with promises and callbacks

Testing Promises & Async/Await

Different patterns for testing asynchronous code

javascript
// Using async/await
test('async data fetch', async () => {
  const data = await fetchData()
  expect(data).toBe('data')
})

// Using promises
test('promise resolution', () => {
  return fetchData().then(data => {
    expect(data).toBe('data')
  })
})

// Expect promises
test('resolves/rejects', async () => {
  await expect(fetchData()).resolves.toBe('data')
  await expect(fetchError()).rejects.toThrow('error')
})

// Testing callbacks
test('callback test', (done) => {
  function callback(data) {
    try {
      expect(data).toBe('data')
      done()
    } catch (error) {
      done(error)
    }
  }
  fetchDataCallback(callback)
})
💡 Always return or await promises in tests to avoid false positives
⚡ Use expect.assertions(n) to ensure async assertions run
📌 resolves/rejects matchers make async tests cleaner
🟢 Set custom timeout as third parameter for slow operations
asyncpromises

Timers & Dates

Testing code that uses setTimeout, setInterval, and Date

Fake Timers

Controlling time in tests with Jest fake timers

javascript
// Enable fake timers
beforeEach(() => {
  jest.useFakeTimers()
})

afterEach(() => {
  jest.useRealTimers()
})

test('timer test', () => {
  const callback = jest.fn()

  setTimeout(callback, 1000)

  // Fast-forward time
  jest.advanceTimersByTime(1000)
  expect(callback).toHaveBeenCalledTimes(1)
})

// Run all timers
jest.runAllTimers()

// Run only pending timers
jest.runOnlyPendingTimers()
💡 Modern timers (default) also mock Date, legacy timers don't
⚡ Use runOnlyPendingTimers to avoid infinite timer loops
📌 Always restore real timers in afterEach to avoid test pollution
🟢 setSystemTime allows testing date-dependent logic easily
timersdatemocking

Testing React Components

Testing React components with Jest and React Testing Library

Component Testing Basics

Testing React components with React Testing Library

javascript
// Basic component test
import { render, screen, fireEvent } from '@testing-library/react'
import Button from './Button'

test('renders button with text', () => {
  render(<Button>Click me</Button>)
  const button = screen.getByText(/click me/i)
  expect(button).toBeInTheDocument()
})

// Testing events
test('calls onClick handler', () => {
  const handleClick = jest.fn()
  render(<Button onClick={handleClick}>Click</Button>)

  fireEvent.click(screen.getByText('Click'))
  expect(handleClick).toHaveBeenCalledTimes(1)
})

// Testing async components
test('loads user data', async () => {
  render(<UserProfile id={1} />)

  expect(screen.getByText(/loading/i)).toBeInTheDocument()

  const userName = await screen.findByText('John Doe')
  expect(userName).toBeInTheDocument()
})
💡 Use userEvent over fireEvent for more realistic interactions
⚡ Create custom render function to wrap providers
📌 MSW is excellent for mocking API calls in tests
🟢 Always await user interactions with userEvent.setup()
reactcomponentstesting-library

Code Coverage

Measuring and improving test coverage

Coverage Configuration

Setting up and interpreting code coverage reports

javascript
// jest.config.js
module.exports = {
  collectCoverage: true,
  collectCoverageFrom: [
    'src/**/*.{js,jsx,ts,tsx}',
    '!src/index.js',
    '!src/**/*.test.{js,jsx,ts,tsx}',
    '!src/**/*.stories.{js,jsx,ts,tsx}'
  ],
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80
    }
  },
  coverageReporters: ['text', 'lcov', 'html']
}

// Run with coverage
npm test -- --coverage
npm test -- --coverage --watchAll=false
💡 HTML coverage reports show line-by-line coverage visually
⚡ Set different thresholds for critical vs non-critical code
📌 Use istanbul ignore comments sparingly for untestable code
🟢 Coverage helps identify untested code, not test quality
coverageconfiguration

Best Practices

Testing best practices and common patterns

Testing Best Practices

Guidelines for writing maintainable and effective tests

javascript
// Good: Descriptive test names
test('should return user name when valid ID is provided', () => {})

// Good: Arrange-Act-Assert pattern
test('calculates total price with tax', () => {
  // Arrange
  const items = [{ price: 10 }, { price: 20 }]
  const taxRate = 0.1

  // Act
  const total = calculateTotal(items, taxRate)

  // Assert
  expect(total).toBe(33)
})

// Good: Test one thing at a time
test('validates email format', () => {
  expect(isValidEmail('test@example.com')).toBe(true)
})

test('rejects invalid email format', () => {
  expect(isValidEmail('invalid')).toBe(false)
})

// Good: Use beforeEach for setup
let service
beforeEach(() => {
  service = new UserService()
  jest.clearAllMocks()
})
💡 Follow AAA pattern: Arrange, Act, Assert for clarity
⚡ Test behavior and outputs, not implementation details
📌 Keep tests independent - each should run in isolation
🟢 Use descriptive test names that explain what and why
best-practicespatterns