LearnThatStack Ace your next interview
Testing · Free

Jest Frontend Development.
Interview cheat sheet.

Quick reference for Jest Frontend Development - sectioned for fast scanning. Skim the part you're shaky on, walk in confident.

Testing 14-section reference ~7 min read

Summary

Jest is a delightful JavaScript testing framework developed by Meta (Facebook) that focuses on simplicity and developer experience. It provides everything needed for testing JavaScript applications out of the box, including a test runner, assertion library, mocking capabilities, and code coverage reports. Jest is particularly popular for testing React applications but works seamlessly with any JavaScript framework or vanilla JavaScript. Its zero-configuration setup, powerful matchers, snapshot testing, and built-in mocking make it the go-to choice for modern frontend testing. This cheatsheet covers Jest fundamentals, testing patterns, React component testing, and best practices for technical interviews.

Jest Fundamentals

What is Jest?

  • JavaScript testing framework by Facebook
  • Zero configuration
  • Built-in mocking, assertions, and coverage
  • Works with React, Vue, Angular, Node.js

Basic Setup

// package.json
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  }
}

Basic Test Structure

// math.test.js
describe('Math operations', () => {
  test('adds 1 + 2 to equal 3', () => {
    expect(1 + 2).toBe(3);
  });
});

Common Matchers

Equality Matchers

test('equality matchers', () => {
  expect(2 + 2).toBe(4);              // Strict equality (===)
  expect({name: 'jest'}).toEqual({name: 'jest'}); // Deep equality
  expect(null).toBeNull();            // Only matches null
  expect(undefined).toBeUndefined();  // Only matches undefined
  expect('Jest').toBeDefined();       // Opposite of toBeUndefined
});

Truthiness Matchers

test('truthiness', () => {
  expect(true).toBeTruthy();
  expect(false).toBeFalsy();
  expect('').toBeFalsy();
  expect('Jest').toBeTruthy();
});

Number Matchers

test('numbers', () => {
  expect(2 + 2).toBeGreaterThan(3);
  expect(2 + 2).toBeGreaterThanOrEqual(4);
  expect(2 + 2).toBeLessThan(5);
  expect(2 + 2).toBeLessThanOrEqual(4);
  expect(0.1 + 0.2).toBeCloseTo(0.3); // For floating points
});

String Matchers

test('strings', () => {
  expect('team').not.toMatch(/I/);
  expect('Christoph').toMatch(/stop/);
  expect('Hello Jest').toMatch('Jest');
});

Array and Iterable Matchers

test('arrays', () => {
  const list = ['React', 'Vue', 'Angular'];
  expect(list).toContain('React');
  expect(new Set(list)).toContain('Vue');
  expect(list).toHaveLength(3);
});

Exception Matchers

test('exceptions', () => {
  const throwError = () => {
    throw new Error('Wrong!');
  };
  expect(throwError).toThrow();
  expect(throwError).toThrow('Wrong!');
  expect(throwError).toThrow(/Wrong/);
});

Test Structure & Lifecycle

Setup and Teardown

// Run before each test
beforeEach(() => {
  initializeDatabase();
});

// Run after each test
afterEach(() => {
  clearDatabase();
});

// Run once before all tests
beforeAll(() => {
  return initializeCity();
});

// Run once after all tests
afterAll(() => {
  return clearCity();
});

Scoping

describe('User module', () => {
  beforeEach(() => {
    // Runs before each test in this describe block
  });

  describe('Login', () => {
    test('should login with valid credentials', () => {
      // Test implementation
    });
  });
});

Skip and Only

test.skip('this test will be skipped', () => {
  // This won't run
});

test.only('only this test will run', () => {
  // Only this runs in the file
});

Asynchronous Testing

Promises

// Return a promise
test('fetches user data', () => {
  return fetchUser().then(data => {
    expect(data.name).toBe('John');
  });
});

// Using async/await
test('fetches user data', async () => {
  const data = await fetchUser();
  expect(data.name).toBe('John');
});

Callbacks

test('callback test', done => {
  function callback(data) {
    try {
      expect(data).toBe('data');
      done();
    } catch (error) {
      done(error);
    }
  }
  fetchData(callback);
});

Testing Rejected Promises

test('rejects with error', async () => {
  await expect(fetchUser()).rejects.toThrow('User not found');
});

Mocking

Mock Functions

test('mock implementation', () => {
  const mockFn = jest.fn();
  mockFn.mockReturnValue(42);
  
  expect(mockFn()).toBe(42);
  expect(mockFn).toHaveBeenCalled();
  expect(mockFn).toHaveBeenCalledTimes(1);
});

Mock Return Values

const mockFn = jest.fn();
mockFn
  .mockReturnValueOnce(10)
  .mockReturnValueOnce('x')
  .mockReturnValue(true);

console.log(mockFn(), mockFn(), mockFn()); // 10, 'x', true

Mock Modules

// Mock an entire module
jest.mock('./api');

// Partial mocking
jest.mock('./config', () => ({
  ...jest.requireActual('./config'),
  apiUrl: 'http://localhost'
}));

Spy on Existing Functions

const video = {
  play() {
    return true;
  }
};

test('spies on video play', () => {
  const spy = jest.spyOn(video, 'play');
  video.play();
  
  expect(spy).toHaveBeenCalled();
  spy.mockRestore(); // Restore original implementation
});

Testing React Components

Basic Component Test

import { render, screen } 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 User Interactions

import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';

test('increments counter', () => {
  render(<Counter />);
  const button = screen.getByText('Increment');
  
  fireEvent.click(button);
  
  expect(screen.getByText('Count: 1')).toBeInTheDocument();
});

Testing with React Testing Library

import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

test('user can type in input', async () => {
  const user = userEvent.setup();
  render(<Input />);
  
  const input = screen.getByRole('textbox');
  await user.type(input, 'Hello');
  
  expect(input).toHaveValue('Hello');
});

Testing Hooks

import { renderHook, act } from '@testing-library/react';
import useCounter from './useCounter';

test('should increment counter', () => {
  const { result } = renderHook(() => useCounter());
  
  act(() => {
    result.current.increment();
  });
  
  expect(result.current.count).toBe(1);
});

Snapshot Testing

Basic Snapshot

test('component snapshot', () => {
  const tree = renderer
    .create(<Button>Click me</Button>)
    .toJSON();
  expect(tree).toMatchSnapshot();
});

Inline Snapshots

test('inline snapshot', () => {
  expect({name: 'jest'}).toMatchInlineSnapshot(`
    Object {
      "name": "jest",
    }
  `);
});

Updating Snapshots

jest --updateSnapshot
# or
jest -u

Coverage

Coverage Configuration

// jest.config.js
module.exports = {
  collectCoverage: true,
  coverageDirectory: 'coverage',
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80
    }
  }
};

Coverage Report Types

jest --coverage --coverageReporters=text-lcov
jest --coverage --coverageReporters=html

Advanced Patterns

Custom Matchers

expect.extend({
  toBeWithinRange(received, floor, ceiling) {
    const pass = received >= floor && received <= ceiling;
    return {
      pass,
      message: () => `expected ${received} to be within range ${floor} - ${ceiling}`
    };
  }
});

test('custom matcher', () => {
  expect(100).toBeWithinRange(90, 110);
});

Timer Mocks

jest.useFakeTimers();

test('waits 1 second', () => {
  const timerFn = jest.fn();
  setTimeout(timerFn, 1000);
  
  expect(timerFn).not.toBeCalled();
  jest.advanceTimersByTime(1000);
  expect(timerFn).toBeCalled();
});

Manual Mocks

// __mocks__/fs.js
module.exports = {
  readFileSync: jest.fn(() => 'mocked content')
};

// In test file
jest.mock('fs');

Testing Error Boundaries

test('error boundary', () => {
  const ThrowError = () => {
    throw new Error('Test error');
  };
  
  // Suppress console.error for this test
  const spy = jest.spyOn(console, 'error').mockImplementation();
  
  const { getByText } = render(
    <ErrorBoundary>
      <ThrowError />
    </ErrorBoundary>
  );
  
  expect(getByText(/something went wrong/i)).toBeInTheDocument();
  spy.mockRestore();
});

Best Practices

1. Test Structure

  • Use descriptive test names
  • Follow AAA pattern: Arrange, Act, Assert
  • One assertion per test when possible

2. Isolation

  • Tests should be independent
  • Clean up after tests
  • Don't rely on test order

3. Mocking

  • Mock external dependencies
  • Don't mock everything
  • Prefer dependency injection

4. Performance

  • Use beforeAll for expensive setup
  • Parallelize tests when possible
  • Mock heavy operations

5. Maintainability

  • Keep tests simple and readable
  • Use helper functions for common operations
  • Update tests when code changes

Key Interview Concepts

Matcher Comparison

Matcher Use Case Example Comparison Type
toBe Primitives, exact reference expect(1).toBe(1) Object.is() (===)
toEqual Objects, arrays, deep equality expect({a:1}).toEqual({a:1}) Deep/recursive
toStrictEqual Like toEqual but checks undefined expect({a:1}).toStrictEqual({a:1}) Strict deep
toMatchObject Partial object matching expect(obj).toMatchObject({a:1}) Subset matching

Asynchronous Testing Patterns

// Pattern 1: Return Promise
test('async with promise', () => {
  return fetchData().then(data => {
    expect(data).toBe('data');
  });
});

// Pattern 2: Async/Await (Recommended)
test('async with await', async () => {
  const data = await fetchData();
  expect(data).toBe('data');
});

// Pattern 3: Done Callback (Legacy)
test('async with done', (done) => {
  fetchData((data) => {
    expect(data).toBe('data');
    done();
  });
});

Mocking Strategies

Type Purpose Use Case Example
Mock Function Replace function behavior Unit tests jest.fn()
Module Mock Replace entire module External dependencies jest.mock('./api')
Spy Watch existing function Verify calls jest.spyOn(obj, 'method')
Manual Mock Custom implementation Complex mocks __mocks__/module.js
Auto Mock Automatic module mocking Quick isolation jest.createMockFromModule()

Testing Component Patterns

// Pattern 1: Testing Library (Recommended)
import { render, screen } from '@testing-library/react';
render(<Component />);
expect(screen.getByRole('button')).toBeInTheDocument();

// Pattern 2: Enzyme (Legacy)
import { shallow, mount } from 'enzyme';
const wrapper = shallow(<Component />);
expect(wrapper.find('button').length).toBe(1);

// Pattern 3: Snapshot Testing
const tree = renderer.create(<Component />).toJSON();
expect(tree).toMatchSnapshot();

Snapshot Testing Best Practices

Aspect Good Practice Bad Practice
Scope Small, focused components Large component trees
Content Stable UI structure Dynamic/random content
Review Always review changes Blindly updating
Combination Use with other tests Rely only on snapshots

Code Coverage Metrics

Metric Description Target
Statement % of statements executed 80-90%
Branch % of branches (if/else) tested 75-85%
Function % of functions called 80-90%
Line % of lines executed 80-90%

Testing Pyramid & Jest's Role

        /\      E2E Tests (Cypress/Playwright)
       /  \     - User journeys
      /    \    
     /------\   Integration Tests (Jest + RTL)
    / Jest   \  - Component integration
   /          \ - API integration
  /------------\ 
 / Unit Tests   \ (Jest)
/________________\ - Functions, hooks, utilities

Redux Testing Strategies

// 1. Test Actions
expect(actions.addTodo('Buy milk')).toEqual({
  type: 'ADD_TODO',
  payload: 'Buy milk'
});

// 2. Test Reducers
expect(reducer(undefined, { type: 'ADD_TODO' })).toEqual(expectedState);

// 3. Test Connected Components
const store = mockStore({ todos: [] });
render(
  <Provider store={store}>
    <ConnectedComponent />
  </Provider>
);

Test File Organization

Src Structure          Test Structure
├── components/       ├── components/
│   ├── Button.jsx    │   ├── Button.test.jsx
│   └── Card.jsx      │   └── Card.test.jsx
├── utils/            ├── utils/
│   └── helpers.js    │   └── helpers.test.js
└── services/         └── services/
    └── api.js            └── api.test.js

Debugging Techniques

Method When to Use How
console.log Quick inspection Add in test or component
debugger Step through code Add breakpoint, run with node --inspect
.only Isolate test test.only('...')
--watch Continuous testing jest --watch
VSCode Debugger Full debugging Launch configuration
--bail Stop on first failure jest --bail

Quick Reference

Common Commands

jest                    # Run all tests
jest --watch           # Watch mode
jest --coverage        # With coverage
jest path/to/test      # Run specific test
jest --updateSnapshot  # Update snapshots
jest --maxWorkers=4    # Parallel execution

Jest Configuration

// jest.config.js
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],
  moduleNameMapper: {
    '\\.(css|less|scss)$': 'identity-obj-proxy',
  },
  transform: {
    '^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
  },
};

Must-Know Concepts for Interviews

  1. Test Doubles: Dummy, Stub, Spy, Mock, Fake
  2. Test Pyramid: Unit → Integration → E2E
  3. TDD: Red → Green → Refactor
  4. Coverage Types: Statement, Branch, Function, Line
  5. Assertion Libraries: Jest assertions, expect, chai
  6. React Testing: RTL queries, user interactions, async updates
  7. Performance: Parallel execution, test.concurrent
  8. Debugging: VSCode Jest extension, Chrome DevTools

Interview Preparation Checklist

  • ✅ Matchers: toBe vs toEqual, custom matchers
  • ✅ Async Testing: Promises, async/await, timers
  • ✅ Mocking: Functions, modules, spies
  • ✅ React Testing: RTL, user events, hooks
  • ✅ Snapshots: When to use, updating, best practices
  • ✅ Coverage: Metrics, thresholds, reports
  • ✅ Test Organization: Structure, naming, AAA pattern
  • ✅ Performance: Parallel testing, focused tests
  • ✅ Debugging: Tools and techniques
  • ✅ Best Practices: FIRST principles, isolation

Key Takeaway: Jest excels at making testing enjoyable and productive. Focus on writing tests that are Fast, Independent, Repeatable, Self-validating, and Timely (FIRST). Remember that good tests document behavior, catch regressions, and enable confident refactoring.

Found this useful? Pass it on.
Pro · $10/mo

The sheet is free. Pro goes deeper.

Pro opens the full question library behind every sheet, every refresher and a monthly AI allowance. One subscription, all formats.

Full question library All refreshers Cancel anytime