Skip to content
intermediatePhase 40 · Testing

Unit Testing

Write unit tests for JavaScript functions and utilities.

45m
0 problems
Topic Progress0%

Unit Testing Basics

Unit Testing Basics

Test individual functions and components in isolation.

What is a Unit Test?

  • Tests a single function or component
  • Isolated from dependencies
  • Fast execution
  • Easy to debug

Testing Pyramid

        /
       / E2E \
      /---------\
     / Integration \
    /---------------\
   /    Unit Tests    \
  /---------------------\

Test Structure

// AAA Pattern
describe('FunctionName', () => {
  it('should do something when condition', () => {
    // Arrange
    const input = 'test';
    
    // Act
    const result = functionUnderTest(input);
    
    // Assert
    expect(result).toBe('expected');
  });
});

Pure Function Tests

// utils.js
export function add(a, b) {
  return a + b;
}

export function formatCurrency(amount) {
  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD',
  }).format(amount);
}

// utils.test.js
import { add, formatCurrency } from './utils';

describe('add', () => {
  it('should add two numbers', () => {
    expect(add(1, 2)).toBe(3);
  });

  it('should handle negative numbers', () => {
    expect(add(-1, -2)).toBe(-3);
  });

  it('should handle zero', () => {
    expect(add(0, 5)).toBe(5);
  });
});

describe('formatCurrency', () => {
  it('should format number as currency', () => {
    expect(formatCurrency(1234.56)).toBe('$1,234.56');
  });

  it('should handle zero', () => {
    expect(formatCurrency(0)).toBe('$0.00');
  });
});

Jest Setup

Jest Setup

Configure Jest for React projects.

Installation

# Create React App
npx create-react-app my-app

# Vite
npm create vite@latest my-app
npm install -D vitest @testing-library/react

Configuration

// jest.config.js (CRA)
module.exports = {
  // Coverage settings
  collectCoverageFrom: [
    'src/**/*.{js,jsx,ts,tsx}',
    '!src/**/*.d.ts',
    '!src/index.js',
    '!src/reportWebVitals.js',
  ],
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80,
    },
  },
};
// vitest.config.js (Vite)
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/test/setup.ts',
    css: true,
  },
});

Setup File

// src/test/setup.js
import '@testing-library/jest-dom';

// Mock window.matchMedia
Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: jest.fn().mockImplementation(query => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: jest.fn(),
    removeListener: jest.fn(),
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    dispatchEvent: jest.fn(),
  })),
});

// Mock IntersectionObserver
class MockIntersectionObserver {
  constructor() {}
  observe() { return null; }
  unobserve() { return null; }
  disconnect() { return null; }
}

window.IntersectionObserver = MockIntersectionObserver;

Running Tests

# Run all tests
npm test

# Run with coverage
npm test -- --coverage

# Run specific file
npm test -- Button.test.js

# Run in watch mode
npm test -- --watch

Writing Unit Tests

Writing Unit Tests

Common Matchers

// Equality
expect(value).toBe(42); // Strict equality
expect(value).toEqual({ a: 1 }); // Deep equality

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

// Numbers
expect(value).toBeGreaterThan(3);
expect(value).toBeCloseTo(0.1, 2);

// Strings
expect(value).toMatch(/regex/);

// Arrays
expect(array).toContain(42);
expect(array).toHaveLength(3);

// Exceptions
expect(() => fn()).toThrow(Error);
expect(() => fn()).toThrow('error message');

Async Tests

// Async function
async function fetchUser(id) {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
}

describe('fetchUser', () => {
  it('should fetch user data', async () => {
    // Mock fetch
    global.fetch = jest.fn(() =>
      Promise.resolve({
        json: () => Promise.resolve({ id: 1, name: 'John' }),
      })
    );

    const user = await fetchUser(1);

    expect(user).toEqual({ id: 1, name: 'John' });
    expect(fetch).toHaveBeenCalledWith('/api/users/1');
  });
});

Mocking

// Mock function
const mockFn = jest.fn();
mockFn('arg');

expect(mockFn).toHaveBeenCalledWith('arg');
expect(mockFn).toHaveBeenCalledTimes(1);

// Mock module
jest.mock('./api');
import { fetchUser } from './api';

// Mock return value
fetchUser.mockResolvedValue({ id: 1, name: 'John' });

Testing React Components

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

describe('Button', () => {
  it('should render with text', () => {
    render(<Button>Click me</Button>);
    expect(screen.getByText('Click me')).toBeInTheDocument();
  });

  it('should call onClick when clicked', () => {
    const handleClick = jest.fn();
    render(<Button onClick={handleClick}>Click me</Button>);
    
    fireEvent.click(screen.getByText('Click me'));
    
    expect(handleClick).toHaveBeenCalledTimes(1);
  });

  it('should be disabled when disabled prop is true', () => {
    render(<Button disabled>Click me</Button>);
    expect(screen.getByText('Click me')).toBeDisabled();
  });
});

Practice Problems

0/3solved
Build Unit Testing Component

Create a reusable React component implementing Unit Testing. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
Unit Testing Testing

Write unit and integration tests for Unit Testing using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
Unit Testing Performance

Optimize Unit Testing for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What is a unit test?

Question 1 options

2. What does Jest use for assertions?

Question 2 options

3. What is the primary purpose of Unit Testing?

Question 3 options

4. What is a common mistake when implementing Unit Testing?

Question 4 options

Flashcards

Question

What is a unit test?

Answer

A test that verifies a single function or component works correctly in isolation.

Question

What is the AAA pattern?

Answer

Arrange (setup), Act (execute), Assert (verify) - test structure.

Question

Why mock dependencies?

Answer

To isolate the unit being tested and control external behavior.

Question

What is test coverage?

Answer

The percentage of code covered by tests, indicating how thoroughly code is tested.

Question

What is Unit Testing?

Answer

Unit Testing is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.Unit tests verify individual functions in isolation
  • 2.Use AAA pattern for test structure
  • 3.Mock dependencies to isolate tests
  • 4.Aim for 80%+ code coverage
  • 5.Keep tests fast and focused

Interview Tips

  • Explain the AAA pattern in testing
  • Discuss when to mock vs when to use real implementations
  • Know common Jest matchers and testing patterns

Cheat Sheet

Unit Testing Cheat Sheet

AAA Pattern

  • Arrange: Set up test data
  • Act: Execute the function
  • Assert: Verify the result

Common Matchers

  • toBe: Strict equality
  • toEqual: Deep equality
  • toContain: Array/string contains
  • toThrow: Exception thrown

Mocking

  • jest.fn(): Mock function
  • jest.mock(): Mock module
  • mockResolvedValue(): Async mock

React Testing

  • render(): Render component
  • screen.getByText(): Find element
  • fireEvent.click(): Simulate event