functional repository with examples:
https://github.com/AngelVargasGutierrez/JavaScript_EJemplos
Introduction
Jest is a delightful JavaScript testing framework developed by Facebook (now Meta) that focuses on simplicity and developer experience. It's the go-to testing solution for React applications and works seamlessly with any JavaScript project. Jest provides zero-configuration setup, built-in assertion library, mocking capabilities, and code coverage reports out of the box.
Why Choose Jest?
Zero Configuration: Works immediately without complex setup
Snapshot Testing: Captures component output for regression testing
Built-in Mocking: Powerful mocking system for dependencies
Parallel Testing: Runs tests in parallel for faster execution
Code Coverage: Built-in coverage reports without additional tools
Watch Mode: Automatically runs tests when files change
Installation & Setup
Basic Installation
bash# Using npm
npm install --save-dev jest
Using yarn
yarn add --dev jest
For TypeScript support
npm install --save-dev jest @types/jest ts-jest
Package.json Configuration
json{
"name": "jest-testing-demo",
"version": "1.0.0",
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage"
},
"jest": {
"testEnvironment": "node",
"collectCoverageFrom": [
"src//*.{js,jsx}",
"!src/index.js"
]
}
}
Jest Configuration File (jest.config.js)
javascriptmodule.exports = {
testEnvironment: 'node',
roots: ['/src'],
testMatch: [
'/tests//*.+(ts|tsx|js)',
'/.(test|spec).+(ts|tsx|js)'
],
transform: {
'^.+\.(ts|tsx)$': 'ts-jest'
},
collectCoverageFrom: [
'src//.{js,ts}',
'!src/*/.d.ts'
],
coverageReporters: ['text', 'lcov', 'html']
};
Real-World Examples
Example 1: Basic Unit Testing
Let's create a calculator module and test it:
javascript// src/calculator.js
class Calculator {
add(a, b) {
return a + b;
}
subtract(a, b) {
return a - b;
}
multiply(a, b) {
return a * b;
}
divide(a, b) {
if (b === 0) {
throw new Error('Division by zero is not allowed');
}
return a / b;
}
power(base, exponent) {
return Math.pow(base, exponent);
}
}
module.exports = Calculator;
javascript// src/tests/calculator.test.js
const Calculator = require('../calculator');
describe('Calculator', () => {
let calculator;
beforeEach(() => {
calculator = new Calculator();
});
describe('Addition', () => {
test('should add two positive numbers', () => {
expect(calculator.add(2, 3)).toBe(5);
});
test('should add negative numbers', () => {
expect(calculator.add(-2, -3)).toBe(-5);
});
test('should add zero', () => {
expect(calculator.add(5, 0)).toBe(5);
});
});
describe('Division', () => {
test('should divide two numbers', () => {
expect(calculator.divide(10, 2)).toBe(5);
});
test('should throw error when dividing by zero', () => {
expect(() => calculator.divide(10, 0)).toThrow('Division by zero is not allowed');
});
});
describe('Power', () => {
test('should calculate power correctly', () => {
expect(calculator.power(2, 3)).toBe(8);
expect(calculator.power(5, 0)).toBe(1);
});
});
});
Example 2: Asynchronous Testing
javascript// src/userService.js
const axios = require('axios');
class UserService {
constructor(apiUrl = 'https://jsonplaceholder.typicode.com') {
this.apiUrl = apiUrl;
}
async getUser(id) {
try {
const response = await axios.get(${this.apiUrl}/users/${id});
return response.data;
} catch (error) {
throw new Error(Failed to fetch user: ${error.message});
}
}
async createUser(userData) {
try {
const response = await axios.post(${this.apiUrl}/users, userData);
return response.data;
} catch (error) {
throw new Error(Failed to create user: ${error.message});
}
}
validateEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+.[^\s@]+$/;
return emailRegex.test(email);
}
}
module.exports = UserService;
javascript// src/tests/userService.test.js
const axios = require('axios');
const UserService = require('../userService');
// Mock axios
jest.mock('axios');
const mockedAxios = axios;
describe('UserService', () => {
let userService;
beforeEach(() => {
userService = new UserService();
jest.clearAllMocks();
});
describe('getUser', () => {
test('should fetch user successfully', async () => {
const userData = { id: 1, name: 'John Doe', email: 'john@example.com' };
mockedAxios.get.mockResolvedValue({ data: userData });
const result = await userService.getUser(1);
expect(mockedAxios.get).toHaveBeenCalledWith('https://jsonplaceholder.typicode.com/users/1');
expect(result).toEqual(userData);
});
test('should handle fetch error', async () => {
mockedAxios.get.mockRejectedValue(new Error('Network error'));
await expect(userService.getUser(1)).rejects.toThrow('Failed to fetch user: Network error');
});
});
describe('createUser', () => {
test('should create user successfully', async () => {
const newUser = { name: 'Jane Doe', email: 'jane@example.com' };
const createdUser = { id: 2, ...newUser };
mockedAxios.post.mockResolvedValue({ data: createdUser });
const result = await userService.createUser(newUser);
expect(mockedAxios.post).toHaveBeenCalledWith('https://jsonplaceholder.typicode.com/users', newUser);
expect(result).toEqual(createdUser);
});
});
describe('validateEmail', () => {
test('should validate correct email addresses', () => {
expect(userService.validateEmail('test@example.com')).toBe(true);
expect(userService.validateEmail('user.name@domain.co.uk')).toBe(true);
});
test('should reject invalid email addresses', () => {
expect(userService.validateEmail('invalid-email')).toBe(false);
expect(userService.validateEmail('test@')).toBe(false);
expect(userService.validateEmail('@example.com')).toBe(false);
});
});
});
Example 3: React Component Testing
javascript// src/components/TodoItem.jsx
import React from 'react';
const TodoItem = ({ todo, onToggle, onDelete }) => {
return (
type="checkbox"
checked={todo.completed}
onChange={() => onToggle(todo.id)}
data-testid="todo-checkbox"
/>
{todo.text}
onClick={() => onDelete(todo.id)}
className="delete-btn"
data-testid="delete-button"
>
Delete
);
};
export default TodoItem;
javascript// src/components/tests/TodoItem.test.jsx
import React from 'react';
import { render, fireEvent, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import TodoItem from '../TodoItem';
describe('TodoItem', () => {
const mockTodo = {
id: 1,
text: 'Test todo item',
completed: false
};
const mockOnToggle = jest.fn();
const mockOnDelete = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
});
test('renders todo item correctly', () => {
render(
todo={mockTodo}
onToggle={mockOnToggle}
onDelete={mockOnDelete}
/>
);
expect(screen.getByTestId('todo-text')).toHaveTextContent('Test todo item');
expect(screen.getByTestId('todo-checkbox')).not.toBeChecked();
});
test('calls onToggle when checkbox is clicked', () => {
render(
todo={mockTodo}
onToggle={mockOnToggle}
onDelete={mockOnDelete}
/>
);
fireEvent.click(screen.getByTestId('todo-checkbox'));
expect(mockOnToggle).toHaveBeenCalledWith(1);
});
test('calls onDelete when delete button is clicked', () => {
render(
todo={mockTodo}
onToggle={mockOnToggle}
onDelete={mockOnDelete}
/>
);
fireEvent.click(screen.getByTestId('delete-button'));
expect(mockOnDelete).toHaveBeenCalledWith(1);
});
test('applies completed class when todo is completed', () => {
const completedTodo = { ...mockTodo, completed: true };
render(
<TodoItem
todo={completedTodo}
onToggle={mockOnToggle}
onDelete={mockOnDelete}
/>
);
expect(screen.getByTestId('todo-checkbox')).toBeChecked();
expect(screen.getByRole('checkbox').closest('.todo-item')).toHaveClass('completed');
});
});
Example 4: Snapshot Testing
javascript// src/components/tests/TodoItem.snapshot.test.jsx
import React from 'react';
import { render } from '@testing-library/react';
import TodoItem from '../TodoItem';
describe('TodoItem Snapshots', () => {
test('should match snapshot for incomplete todo', () => {
const todo = { id: 1, text: 'Buy groceries', completed: false };
const { container } = render(
);
expect(container.firstChild).toMatchSnapshot();
});
test('should match snapshot for completed todo', () => {
const todo = { id: 2, text: 'Walk the dog', completed: true };
const { container } = render(
);
expect(container.firstChild).toMatchSnapshot();
});
});
Comparative Analysis
Pros of Jest
✅ Zero Configuration: Works out of the box with minimal setup
✅ Built-in Assertions: No need for additional assertion libraries
✅ Powerful Mocking: Comprehensive mocking system for modules and functions
✅ Snapshot Testing: Excellent for UI regression testing
✅ Code Coverage: Built-in coverage reports
✅ Parallel Execution: Fast test execution
✅ Watch Mode: Great developer experience
✅ Large Community: Extensive documentation and community support
Cons of Jest
❌ Memory Usage: Can be memory-intensive for large test suites
❌ Slow Startup: Initial startup can be slow for large projects
❌ Limited Browser Testing: Primarily designed for Node.js environment
❌ Snapshot Brittleness: Snapshots can be fragile and require maintenance
When to Use Jest vs Alternatives
Use Jest When:
Building React applications
Need zero-configuration setup
Want built-in mocking and coverage
Working with Node.js projects
Team prefers all-in-one solution
Consider Alternatives When:
Vitest: For Vite-based projects (faster execution)
Mocha + Chai: Need more flexibility in assertion styles
Cypress/Playwright: For end-to-end testing
Jasmine: For simpler projects without advanced features
Repository Examples
🔗 Demo Repository: jest-testing-examples
Repository Structure:
jjest-testing-examples/
├── src/
│ ├── calculator.js
│ ├── userService.js
│ ├── components/
│ │ └── TodoItem.jsx
│ └── tests/
│ ├── calculator.test.js
│ ├── userService.test.js
│ └── components/
│ ├── TodoItem.test.jsx
│ └── TodoItem.snapshot.test.jsx
├── package.json
├── jest.config.js
├── babel.config.js
├── README.md
└── node_modules/
Key Features Demonstrated:
Unit testing with various assertion types
Asynchronous testing with mocks
React component testing with Testing Library
Snapshot testing for UI components
Code coverage configuration
Multiple test environments
Running the Examples:
bashgit clone https://github.com/AngelVargasGutierrez/JavaScript_EJemplos
cd jest-testing-examples
npm install
npm test # Run all tests
npm run test:watch # Run tests in watch mode
npm run test:coverage # Run tests with coverage report
Best Practices and Advanced Techniques
- Organize Tests with Describe Blocks javascriptdescribe('UserService', () => { describe('Authentication', () => { test('should login with valid credentials', () => { // test implementation }); });
describe('Data Fetching', () => {
test('should fetch user data', () => {
// test implementation
});
});
});
- Use Setup and Teardown Hooks javascriptdescribe('Database Operations', () => { beforeAll(async () => { // Setup database connection await connectToDatabase(); });
afterAll(async () => {
// Close database connection
await disconnectFromDatabase();
});
beforeEach(() => {
// Reset test data before each test
resetTestData();
});
afterEach(() => {
// Clean up after each test
clearTestData();
});
});
- Custom Matchers
javascript// 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, }; } }, });
// Usage
test('random number should be within range', () => {
expect(Math.random() * 100).toBeWithinRange(0, 100);
});
- Testing Error Boundaries (React) javascriptimport React from 'react'; import { render, screen } from '@testing-library/react'; import ErrorBoundary from '../ErrorBoundary';
const ThrowError = ({ shouldThrow }) => {
if (shouldThrow) {
throw new Error('Test error');
}
return
};
test('should catch and display error', () => {
const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
render(
);
expect(screen.getByText(/something went wrong/i)).toBeInTheDocument();
spy.mockRestore();
});
Performance Optimization Tips
- Use --maxWorkers for CI/CD json{ "scripts": { "test:ci": "jest --maxWorkers=2 --coverage" } }
- Selective Test Running bash# Run specific test file jest calculator.test.js
Run tests matching pattern
jest --testNamePattern="should add"
Run only changed files
jest --onlyChanged
- Mock Heavy Dependencies javascript// Mock expensive operations jest.mock('../heavyCalculation', () => ({ complexCalculation: jest.fn(() => 'mocked result') })); Conclusion Jest stands out as a comprehensive testing framework that balances simplicity with powerful features. Its zero-configuration approach makes it ideal for quick project setup, while its extensive feature set supports complex testing scenarios. The built-in mocking, snapshot testing, and code coverage capabilities make it particularly valuable for React applications and Node.js projects. Key Takeaways:
Start Simple: Begin with basic unit tests and gradually add complexity
Mock Wisely: Use mocks for external dependencies but avoid over-mocking
Test Behavior: Focus on testing what your code does, not how it does it
Maintain Snapshots: Regular review and update of snapshot tests
Leverage Watch Mode: Use watch mode during development for faster feedback
Recommendations:
For Beginners: Start with Jest due to its excellent documentation and community
For React Projects: Jest + Testing Library is the industry standard
For Performance-Critical Projects: Consider Vitest as a faster alternative
For Complex E2E Scenarios: Combine Jest with Cypress or Playwright
Jest continues to evolve with the JavaScript ecosystem, making it a reliable choice for modern testing needs. Whether you're building a simple utility library or a complex React application, Jest provides the tools necessary to ensure code quality and reliability.
Happy Testing! 🧪✨
For more examples and advanced techniques, check out the demo repository and feel free to contribute your own testing scenarios.
Top comments (2)
One of the strongest observations in your article is the practical breakdown of when to use Jest versus alternatives like Vitest, Mocha, or Cypress. This real-world comparison adds significant value for developers deciding on a testing strategy. I’d suggest emphasizing this section with a visual (like a decision table or comparison chart) to make it even more digestible.
This article offers a comprehensive and highly practical exploration of Jest as a modern JavaScript testing framework. The author not only explains Jest's features—such as zero-configuration setup, snapshot testing, mocking, and code coverage—but also demonstrates them through clear, real-world examples organized by category: unit tests, asynchronous testing, React component testing, and snapshot testing.
What makes this article particularly valuable is its structured approach: each section builds upon the previous one, helping readers understand both the fundamentals and advanced usage of Jest. The inclusion of a fully functional repository adds credibility and allows readers to interact with the examples directly. Moreover, performance optimization tips and testing best practices provide additional insights that are rarely covered in typical tutorials.
Overall, this is an excellent resource for both beginners seeking a smooth introduction to Jest and experienced developers looking to deepen their testing strategies. It clearly reflects a deep understanding of testing in modern JavaScript applications. Great job!