Jest основы
Jest — фреймворк для тестирования JavaScript и TypeScript с встроенными assertion-матчерами, mock-системой и генератором coverage-отчётов.
Зачем нужно
Jest — стандарт де-факто в экосистеме JavaScript: он работает «из коробки» без сложной конфигурации, поддерживает CJS и ESM, умеет параллельно запускать тесты и измерять покрытие кода. Его mock-система позволяет полностью контролировать зависимости, а watch-режим ускоряет цикл разработки.
Где используется
- Unit-тесты функций, классов и сервисов в Node.js и браузерных проектах
- Integration-тесты API с mock-зависимостями
- Тестирование React-компонентов совместно с Testing Library
- В CI/CD:
jest --ciдля детерминированного запуска без интерактивного режима
Основной контент
Установка и настройка
npm install --save-dev jest
# Для TypeScript
npm install --save-dev jest @types/jest ts-jest
// package.json
{
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage --coverageReporters=text"
},
"jest": {
"testEnvironment": "node",
"testMatch": ["**/__tests__/**/*.js", "**/*.test.js"],
"collectCoverageFrom": ["src/**/*.js", "!src/**/*.d.ts"]
}
}
Базовые API
// describe — группировка тестов
describe('Название группы', () => {
// test / it — один тест (взаимозаменяемы)
test('что именно проверяем', () => {
expect(2 + 2).toBe(4);
});
it('альтернативный синтаксис', () => {
expect([1, 2, 3]).toHaveLength(3);
});
});
Хуки жизненного цикла
describe('UserService', () => {
let service;
beforeAll(() => {
// Один раз перед всей группой (например, подключение к БД)
});
afterAll(() => {
// Один раз после всей группы (закрытие соединений)
});
beforeEach(() => {
service = new UserService(); // перед каждым тестом
});
afterEach(() => {
jest.clearAllMocks; // после каждого теста
});
test('...', () => { /* ... */ });
});
Асинхронные тесты
// async/await — рекомендуемый подход
test('получает пользователя по ID', async () => {
const user = await fetchUser(1);
expect(user.name).toBe('Alice');
});
// Промис — возвращай промис из теста
test('отклоняет невалидный ID', () => {
return expect(fetchUser(-1)).rejects.toThrow('Invalid ID');
});
Полезные матчеры
// Значения
expect(x).toBe(42); // строгое ===
expect(obj).toEqual({ a: 1 }); // глубокое равенство
expect(x).toBeTruthy();
expect(x).toBeFalsy();
expect(x).toBeNull();
expect(x).toBeUndefined();
expect(x).toBeDefined();
// Числа
expect(n).toBeGreaterThan(0);
expect(n).toBeLessThanOrEqual(100);
expect(n).toBeCloseTo(3.14, 2); // ≈ с точностью 2 знака
// Строки и массивы
expect(str).toContain('hello');
expect(arr).toContain(42);
expect(arr).toHaveLength(3);
expect(arr).toEqual(expect.arrayContaining([1, 2]));
// Ошибки
expect( => fn).toThrow('message');
expect( => fn).toThrow(TypeError);
Запуск тестов
npx jest # все тесты
npx jest math.test.js # конкретный файл
npx jest --testNamePattern="add" # по имени теста
npx jest --watch # режим наблюдения
npx jest --coverage # с отчётом покрытия
npx jest --ci # для CI (без интерактива)
npx jest --verbose # подробный вывод
Частые ошибки
- Забыть
returnилиawaitв асинхронном тесте — тест пройдёт зелёным, даже если промис отклонён toBeдля объектов — сравнивает ссылки, а не содержимое; используйtoEqual- Глобальное состояние между тестами — всегда используй
beforeEachдля создания свежего экземпляра - Слишком общее имя теста —
test('works')ничего не говорит; пишиtest('возвращает null для несуществующего ID') - Игнорировать ошибки покрытия — 100% coverage не гарантирует правильность, но ниже 70% — сигнал о проблемах