
- Jest - Getting Started
- Jest - Core Concepts
- Jest - Mocking
- Jest - Advanced Testing
- Jest - React Testing
- Jest - Configuration
- Jest - Special Testing Scenarios
- Jest - Performance & Advanced Topics
- Jest - Integrations
- Jest - Best Practices
- Jest - Deployment and CI/CD
- Jest Resources
- Jest - Useful Resources
- Jest - Discussion
Jest - Performance and Advanced Topics
In this chapter, we'll cover advanced Jest features to help you write faster and more efficient tests. The topics we will cover include:
Jest - Performance Optimization
Optimizing Jest's performance is important for larger projects or when dealing with many test cases. Here are several strategies you can use to speed up Jest tests:
Run Tests in Parallel
By default, Jest runs tests in parallel, which speeds up test execution. It divides tests into multiple workers(processes) based on the number of CPU cores, helping to reduce test run time.
You can adjust the number of workers in the Jest configuration file(jest.config.js) using the maxWorkers option.
module.exports = { maxWorkers: "50%", // Use 50% of available CPU cores };
Avoid Large Test Suites
For large test suites, split them into smaller chunks by organizing tests into separate files or using the testPathPattern option to run specific tests.
jest --testPathPattern="specificTestFile"
Avoiding Slow Setup/Teardown
To optimize slow setup or teardown (like database connections), use beforeAll and afterAll to avoid repeating operations in beforeEach and afterEach.
Use jest.runAllTimers() and jest.clearAllMocks()
To improve test performance, clear unused mocks and timers to prevent unnecessary code from running. For example:
beforeEach(() => { jest.clearAllMocks(); // Clears any mocks that are no longer needed jest.runAllTimers(); // Runs all pending timers immediately });
Use --silent Flag for CI Environments
In a continuous integration (CI) environment, use the --silent flag to prevent unnecessary output in the console, which helps reduce the load during test execution.
jest --silent
Optimize Test Setup and Teardown
Avoid heavy operations in beforeAll or afterAll. Keep setup and teardown minimal for faster execution. If your tests interact with a database, consider mocking the database to improve performance.
Jest - Custom Matchers
Custom matchers in Jest allow you to create your own expectations, making your tests clearer and more suited to your needs. They are especially useful for testing specific behaviors or custom data structures.
Creating a Custom Matcher
To create a custom matcher, use expect.extend(). Here's how you can define one that checks if a number is divisible by another number:
expect.extend({ toBeDivisibleBy(received, argument) { const pass = received % argument === 0; if (pass) { return { message: () => `expected ${received} not to be divisible by ${argument}`, pass: true, }; } else { return { message: () => `expected ${received} to be divisible by ${argument}`, pass: false, }; } }, });
Using the Custom Matcher
Once you've defined a custom matcher, you can use it in your tests like this:
test('is divisible by 3', () => { expect(6).toBeDivisibleBy(3); // passes expect(7).toBeDivisibleBy(3); // fails });
Async Custom Matchers
You can also create asynchronous custom matchers for tests involving promises or async operations. Here's an example of an async matcher that checks if data fetched from a URL contains a specific value:
expect.extend({ async toFetchData(received) { const response = await fetch(received); const data = await response.json(); return { message: () => `expected ${received} to fetch data`, pass: data.someProperty === 'expectedValue', }; }, });
Jest - Timer Mocks
Timers like setTimeout and setInterval are common in JavaScript. Jest provides tools to mock and control them in tests, allowing you to test time-dependent functions without waiting for actual time to pass.
Mocking Timers Using Jest
To mock timers in Jest, use jest.useFakeTimers() at the beginning of your tests. This replaces the default timers with mock timers that you can control.
beforeEach(() => { jest.useFakeTimers(); // Enable fake timers }); afterEach(() => { jest.useRealTimers(); // Restore real timers after each test });
Advancing Timers
Once timers are mocked, you can manually advance them using jest.advanceTimersByTime() or jest.runAllTimers()
- jest.advanceTimersByTime(ms): Advances the timer by the specified number of milliseconds.
test('calls the callback after timeout', () => { const callback = jest.fn(); setTimeout(callback, 1000); jest.advanceTimersByTime(1000); // Fast-forward 1000ms expect(callback).toHaveBeenCalled(); });
test('executes all timers', () => { const callback = jest.fn(); setTimeout(callback, 500); setTimeout(callback, 1000); jest.runAllTimers(); // Executes both timeouts expect(callback).toHaveBeenCalledTimes(2); });
Clearing Mock Timers
To prevent tests from affecting each other, clear mock timers using jest.clearAllTimers() or restore the original timers with jest.useRealTimers() between tests.
afterEach(() => { jest.clearAllTimers(); });
Jest - DOM Testing
Jest works well for DOM testing when used with libraries like React Testing Library or Enzyme. These libraries use jsdom to simulate the DOM environment in Node.js.
Setting Up DOM Testing with Jest
Jest uses jsdom by default, so no extra setup is needed. To interact with the DOM, install React Testing Library or Enzyme.
To install React Testing Library:
npm install @testing-library/react @testing-library/jest-dom
Writing DOM Tests
Once your setup is ready, you can write tests for your components. Here's an example of how to test a button click in a React component.
import { render, screen, fireEvent } from '@testing-library/react'; import MyComponent from './MyComponent'; test('button click changes text', () => { render(<MyComponent />); const button = screen.getByRole('button'); fireEvent.click(button); const text = screen.getByText(/button clicked/i); expect(text).toBeInTheDocument(); });
Assertions with Jest DOM
jest-dom adds extra matchers to Jest for testing DOM elements. Some useful matchers are:
- .toBeInTheDocument(): Checks if an element is in the DOM.
- .toHaveTextContent(): Verifies if an element contains the given text.
- .toBeVisible(): Ensures the element is visible on the screen.
Example
import '@testing-library/jest-dom'; // Provides extra matchers test('button displays correct text', () => { render(<MyComponent />); const button = screen.getByRole('button'); expect(button).toHaveTextContent('Click me'); expect(button).toBeVisible(); });
Cleaning Up After Tests
Jest automatically cleans up the DOM after each test. However, you can also manually clear the DOM if needed using the cleanup() function from React Testing Library.
Example
import { cleanup } from '@testing-library/react'; afterEach(() => { jest.clearAllMocks(); cleanup(); });
This clears the DOM after each test, preventing interference between tests.