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
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 neededWrite 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 testsOptimize 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 analysisQuiz
1. What is a unit test?
2. What does Jest use for assertions?
3. What is the primary purpose of Unit Testing?
4. What is a common mistake when implementing Unit Testing?
Flashcards
Question
What is a unit test?
Click to reveal answer
Answer
A test that verifies a single function or component works correctly in isolation.
Question
What is the AAA pattern?
Click to reveal answer
Answer
Arrange (setup), Act (execute), Assert (verify) - test structure.
Question
Why mock dependencies?
Click to reveal answer
Answer
To isolate the unit being tested and control external behavior.
Question
What is test coverage?
Click to reveal answer
Answer
The percentage of code covered by tests, indicating how thoroughly code is tested.
Question
What is Unit Testing?
Click to reveal answer
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