Introduction
Modern JavaScript testing has evolved significantly. Vitest has emerged as a popular alternative to Jest, offering better performance and Vite integration. See Javascript Guide for more context. See Javascript Guide for more context.
This guide covers JavaScript testing in 2026.
Testing Tools Overview
Popular Options
| Tool | Type | Performance | Ecosystem |
|---|---|---|---|
| Vitest | Test Runner | Fast ⚡ | Large |
| Jest | Test Runner | Medium | Largest |
| Mocha | Test Runner | Medium | Large |
| AVA | Test Runner | Fast | Medium |
Vitest
Setup
npm create vitest@latest my-app
cd my-app
npm install
Configuration
// vitest.config.js
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'node',
globals: true,
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
},
},
});
Writing Tests
import { describe, it, expect, beforeEach } from 'vitest';
describe('Math utilities', () => {
beforeEach(() => {
// Setup
});
it('adds two numbers', () => {
expect(2 + 2).toBe(4);
});
it('handles arrays', () => {
const arr = [1, 2, 3];
expect(arr).toHaveLength(3);
expect(arr).toContain(2);
});
it('async operation', async () => {
const data = await fetchData();
expect(data).toBeDefined();
});
});
Mocking
import { vi, expect, it } from 'vitest';
vi.mock('./api', () => ({
fetchUser: () => Promise.resolve({ id: 1, name: 'John' }),
}));
it('mocks API', async () => {
const user = await fetchUser();
expect(user.name).toBe('John');
});
Jest
Setup
npm install --save-dev jest
Configuration
// jest.config.js
module.exports = {
testEnvironment: 'node',
coverageDirectory: 'coverage',
collectCoverageFrom: [
'src/**/*.js',
'!src/**/*.test.js',
],
};
Writing Tests
describe('String utilities', () => {
test('reverses string', () => {
expect(reverse('hello')).toBe('olleh');
});
test('capitalizes', () => {
expect(capitalize('hello')).toBe('Hello');
});
});
Testing Library
Installation
npm install --save-dev @testing-library/react @testing-library/dom
Query Methods
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from './Button';
test('button click', () => {
const handleClick = vi.fn();
render(<Button onClick={handleClick}>Click me</Button>);
fireEvent.click(screen.getByText('Click me'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
Common Queries
// Get by text
screen.getByText('Submit');
// Get by role
screen.getByRole('button', { name: /submit/i });
// Get by testid
screen.getByTestId('submit-button');
// Query vs Get (throw vs return null)
screen.getByText('Submit'); // Throws if not found
screen.queryByText('Submit'); // Returns null if not found
Best Practices
Test Structure
describe('Component', () => {
// Setup
beforeEach(() => { ... });
// Tests
it('should do something', () => { ... });
// Teardown
afterEach(() => { ... });
});
Naming Conventions
// Good naming
it('should return 404 when user not found');
it('should throw error for invalid input');
// Bad naming
it('test1');
it('works');
AAA Pattern
it('calculates total correctly', () => {
// Arrange
const cart = [{ price: 10 }, { price: 20 }];
// Act
const total = calculateTotal(cart);
// Assert
expect(total).toBe(30);
});
Conclusion
Modern JavaScript testing is powerful and fast. Use Vitest for new projects, Testing Library for component tests, and follow AAA pattern.
Comments