Что такое Jest и зачем он нужен?
Jest — это мощный и популярный фреймворк для тестирования JavaScript-кода, разработанный компанией Facebook (Meta). Он предоставляет всё необходимое для написания модульных, интеграционных и сквозных тестов «из коробки»: средства для создания утверждений (assertions), мокирования (mocking), шпионов (spies), таймеров, а также встроенный инструмент для измерения покрытия кода (code coverage).
Jest широко используется в экосистеме React, но отлично подходит для тестирования любого JavaScript-кода, включая приложения на Node.js, Angular, Vue.js и других фреймворках.
Зачем нужен Jest?
- Автоматизация проверок: Позволяет быстро и надежно проверять, что ваш код работает корректно после каждого изменения.
- Предотвращение регрессий: Тесты помогают убедиться, что новый код не сломал старую функциональность.
- Документация: Хорошо написанные тесты служат живой документацией, показывающей, как должна работать каждая функция или модуль.
- Уверенность в рефакторинге: Наличие тестов позволяет безопасно переписывать и улучшать код.
- Простота настройки: Jest работает «из коробки» без необходимости сложной конфигурации.
Установка Jest
Jest устанавливается через менеджер пакетов npm или yarn. Для Node.js-проекта это стандартный способ.
# Установка как dev-зависимость (рекомендуется)
npm install --save-dev jest
# Или с помощью yarn
yarn add --dev jest
После установки добавьте скрипт для запуска тестов в ваш package.json:
{
"scripts": {
"test": "jest",
"test:watch": "jest --watch", // Запуск в режиме наблюдения
"test:coverage": "jest --coverage" // Запуск с отчетом о покрытии
}
}
Теперь вы можете запускать тесты командой npm test.
Быстрый старт с примером кода
Предположим, у нас есть простой модуль для математических операций math.js:
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports = { add, subtract };
Создадим файл теста math.test.js (Jest по умолчанию ищет файлы с расширением .test.js или .spec.js):
// math.test.js
const { add, subtract } = require('./math');
test('adds 1 + 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});
test('subtracts 5 - 3 to equal 2', () => {
expect(subtract(5, 3)).toBe(2);
});
Запустите тесты:
npm test
Вы увидите в консоли отчет о прохождении тестов. Если всё верно, оба теста будут помечены зеленым ✓.
Основные методы и функции Jest
Jest предоставляет богатый API. Рассмотрим 10 ключевых методов, которые покроют 90% ваших задач.
1. test(name, fn, timeout) / it(name, fn, timeout)
Что делает: Определяет новый тест. test и it — это синонимы. Вы можете использовать любой.
Параметры:
name(string) — название теста, которое будет отображаться в отчете.fn(function) — функция, содержащая логику теста (утверждения).timeout(number, необязательный) — время ожидания теста в миллисекундах (по умолчанию 5000).
Пример:
test('два плюс два равно четыре', () => {
expect(2 + 2).toBe(4);
});
it('строка "hello" имеет длину 5', () => {
expect('hello').toHaveLength(5);
});
2. describe(name, fn)
Что делает: Группирует связанные тесты в один блок. Это помогает организовать тесты и делает отчеты более читаемыми.
Параметры:
name(string) — название группы тестов.fn(function) — функция, внутри которой определяются тесты или вложенныеdescribeблоки.
Пример:
describe('Функция add', () => {
test('складывает положительные числа', () => {
expect(add(1, 2)).toBe(3);
});
test('складывает отрицательные числа', () => {
expect(add(-1, -2)).toBe(-3);
});
});
3. expect(value)
Что делает: Это основная функция для создания утверждений (assertions). Она возвращает объект "matcher", который позволяет проверять значение различными способами.
Параметры:
value— любое значение, которое вы хотите проверить (число, строка, объект, функция и т.д.).
Пример:
const result = someFunction();
expect(result).toBeDefined(); // Проверяем, что результат не undefined
4. toBe(value)
Что делает: Проверяет точное равенство с помощью Object.is(). Идеально подходит для примитивных типов (числа, строки, булевы значения). Для объектов и массивов используйте toEqual.
Параметры:
value— ожидаемое значение.
Пример:
test('toBe для примитивов', () => {
expect(1 + 1).toBe(2);
expect('hello').toBe('hello');
expect(true).toBe(true);
});
5. toEqual(value)
Что делает: Проверяет глубокое равенство объектов и массивов. Рекурсивно сравнивает все поля и элементы.
Параметры:
value— ожидаемый объект, массив или примитив.
Пример:
test('toEqual для объектов', () => {
const data = { one: 1, two: 2 };
expect(data).toEqual({ one: 1, two: 2 });
});
test('toEqual для массивов', () => {
const arr = [1, 2, 3];
expect(arr).toEqual([1, 2, 3]);
});
6. toContain(item)
Что делает: Проверяет, содержит ли массив или итерируемый объект определенный элемент. Для строк проверяет, содержит ли строка подстроку.
Параметры:
item— элемент, который должен присутствовать.
Пример:
test('toContain для массивов', () => {
const shoppingList = ['milk', 'bread', 'eggs'];
expect(shoppingList).toContain('milk');
});
test('toContain для строк', () => {
expect('Hello World').toContain('World');
});
7. toThrow(error?)
Что делает: Проверяет, что функция выбрасывает (throws) исключение. Можно проверить конкретное сообщение об ошибке или класс ошибки.
Параметры:
error(string, RegExp, Error class, необязательный) — ожидаемая ошибка.
Пример:
function throwError() {
throw new Error('Something went wrong!');
}
test('toThrow без параметров', () => {
expect(() => throwError()).toThrow();
});
test('toThrow с сообщением', () => {
expect(() => throwError()).toThrow('Something went wrong!');
});
test('toThrow с регулярным выражением', () => {
expect(() => throwError()).toThrow(/wrong/);
});
8. not
Что делает: Инвертирует любой matcher. Позволяет проверить, что значение НЕ соответствует условию.
Параметры: Не принимает параметров. Используется как модификатор перед другим matcher'ом.
Пример:
test('not инвертирует проверку', () => {
expect(1 + 1).not.toBe(3); // Успех, так как 2 не равно 3
expect([1, 2]).not.toContain(3); // Успех
});
9. beforeEach(fn, timeout) / afterEach(fn, timeout)
Что делает: Выполняет функцию fn перед (beforeEach) или после (afterEach) каждого теста внутри блока describe. Используется для подготовки данных (setup) и очистки (teardown).
Параметры:
fn(function) — функция для выполнения.timeout(number, необязательный) — время ожидания.
Пример:
describe('Работа с базой данных', () => {
let db;
beforeEach(() => {
db = new Database(); // Создаем новый экземпляр перед каждым тестом
});
afterEach(() => {
db.close(); // Закрываем соединение после каждого теста
});
test('добавление записи', () => {
db.add('user1');
expect(db.count()).toBe(1);
});
test('удаление записи', () => {
db.add('user1');
db.remove('user1');
expect(db.count()).toBe(0);
});
});
10. jest.fn(implementation?)
Что делает: Создает "mock-функцию" (фиктивную функцию). Она записывает все вызовы, переданные аргументы, возвращаемые значения и экземпляры this. Это ключевой инструмент для изоляции тестируемого кода от внешних зависимостей.
Параметры:
implementation(function, необязательный) — функция, которая будет выполняться вместо оригинальной.
Пример:
// Функция, которая вызывает callback
function processUserInput(callback) {
const name = 'Alice';
callback(name);
}
test('jest.fn записывает вызовы', () => {
const mockCallback = jest.fn(x => `Hello, ${x}!`);
processUserInput(mockCallback);
// Проверяем, что mock был вызван 1 раз
expect(mockCallback).toHaveBeenCalledTimes(1);
// Проверяем, с какими аргументами он был вызван
expect(mockCallback).toHaveBeenCalledWith('Alice');
// Проверяем результат первого вызова
expect(mockCallback.mock.results[0].value).toBe('Hello, Alice!');
});
Реальный практический пример использования
Рассмотрим более сложный пример: тестирование функции, которая асинхронно получает данные о пользователе из API и форматирует их.
Код приложения (userService.js):
Также в библиотеке
Работа с CSV в Go (Golang): полное руководство по пакету encoding/csv
Hyper для Rust: полное руководство с примерами
Авторизация и аутентификация в Go (Golang): полное руководство
Dependency Injection контейнер для JavaScript (Node.js) — Awilix