Introduction
Modern JavaScript testing has evolved significantly. Vitest has emerged as a popular alternative to Jest, offering better performance and Vite integration.
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