← Back to Blog
console.log()

Testing JavaScript Applications - A Practical Guide

Learn to test JavaScript apps effectively with Jest, Testing Library, and proven testing strategies.

testingjavascriptquality

Testing JavaScript Applications

Testing gives you confidence in your code. Here's how to do it right.

Why Test?

  • Catch bugs early - Fix issues before production
  • Enable refactoring - Change code safely
  • Document behavior - Tests show how code works
  • Improve design - Testable code is better code

Unit Testing with Jest

Test individual functions:

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

// math.test.js
import { add } from './math';

describe('add', () => {
 it('adds two positive numbers', () => {
 expect(add(2, 3)).toBe(5);
 });

 it('handles negative numbers', () => {
 expect(add(-1, 5)).toBe(4);
 });
});

Testing React Components

Use React Testing Library:

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

describe('Counter', () => {
 it('renders initial count', () => {
 render(<Counter initialCount={0} />);
 expect(screen.getByText('Count: 0')).toBeInTheDocument();
 });

 it('increments when clicked', () => {
 render(<Counter initialCount={0} />);
 fireEvent.click(screen.getByRole('button'));
 expect(screen.getByText('Count: 1')).toBeInTheDocument();
 });
});

Mocking

Isolate units by mocking dependencies:

// Mock a module
jest.mock('./api');

import { fetchUser } from './api';

fetchUser.mockResolvedValue({ name: 'John' });

// Mock a function
const mockCallback = jest.fn();
mockCallback.mockReturnValue(42);

Async Testing

Test asynchronous code:

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

// With Testing Library
it('displays loaded data', async () => {
 render(<UserProfile userId={1} />);
 expect(await screen.findByText('John')).toBeInTheDocument();
});

Test Coverage

Aim for meaningful coverage:

// jest.config.js
{
 "collectCoverage": true,
 "coverageThreshold": {
 "global": {
 "branches": 80,
 "functions": 80,
 "lines": 80
 }
 }
}

Integration Testing

Test how parts work together:

describe('Checkout flow', () => {
 it('completes purchase', async () => {
 render(<App />);

 // Add item to cart
 fireEvent.click(screen.getByText('Add to Cart'));

 // Go to checkout
 fireEvent.click(screen.getByText('Checkout'));

 // Fill form and submit
 fireEvent.change(screen.getByLabelText('Email'), {
 target: { value: 'test@example.com' }
 });
 fireEvent.click(screen.getByText('Place Order'));

 // Verify success
 expect(await screen.findByText('Order Confirmed')).toBeInTheDocument();
 });
});

Conclusion

Start with unit tests, add integration tests for critical flows, and maintain good coverage. Your future self will thank you.