Jest для JavaScript (Node.js): полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое 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):

Рекомендаций