Если вы когда-нибудь ловили себя на мысли «оно вроде работает, но я не уверен» — эта статья для вас. Тестирование кода — это как страховка: пока ничего не случилось, кажется, что она не нужна, но когда случается беда, вы пожалеете, что не оформили её раньше. Jest — это инструмент, который поможет вам спать спокойно и не бояться, что очередное изменение сломает всё на продакшене. Здесь я расскажу, как быстро освоить Jest и начать писать тесты, которые действительно помогают.

Digital-студия WNDER

Что такое Jest и почему он так популярен?

Jest — это фреймворк для тестирования JavaScript-кода, разработанный в Facebook. Он стал стандартом де-факто для тестирования React-приложений, но отлично работает и с обычным JavaScript, TypeScript, Node.js и другими средами. Его главные фишки — простота настройки, встроенные функции для проверки утверждений (expect), мок-функции и снапшот-тестирование. Вы просто устанавливаете пакет, и он готов к работе — никаких сложных конфигов.

Почему именно Jest? Во-первых, он не требует сложной настройки. Во-вторых, Jest работает быстро благодаря параллельному выполнению тестов. В-третьих, у него отличное сообщество и документация. Если вы новичок, то Jest — это самый дружелюбный способ начать тестировать свой код.

Установка и первое знакомство

Для начала вам понадобится установить Jest в ваш проект. Если у вас уже есть package.json, то всё просто. Откройте терминал и выполните:

npm install --save-dev jest

Если вы используете Yarn, то команда будет такой:

yarn add --dev jest

После установки добавьте в package.json скрипт для запуска тестов:

"scripts": {
  "test": "jest"
}

Теперь создайте файл с тестом. Jest автоматически найдёт файлы, которые заканчиваются на .test.js или .spec.js, а также файлы в папке __tests__. Давайте напишем простой тест для функции сложения.

// sum.js
function sum(a, b) {
  return a + b;
}
module.exports = sum;

// sum.test.js
const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

Запустите npm test и увидите, как тест проходит. Поздравляю, вы только что написали свой первый тест на Jest. Это было просто, правда?

Основные функции Jest: describe, test, expect

Jest предоставляет три ключевые функции, которые вы будете использовать постоянно:

  • describe — группирует тесты по смыслу. Например, «функция sum».
  • test (или it) — описывает конкретный тестовый сценарий.
  • expect — проверяет утверждения. Например, «ожидаю, что результат будет равен 3».

Вот так выглядит структура типичного теста:

describe('sum function', () => {
  test('adds positive numbers correctly', () => {
    expect(sum(2, 3)).toBe(5);
  });

  test('adds negative numbers correctly', () => {
    expect(sum(-1, -1)).toBe(-2);
  });
});

Вы можете использовать разные матчеры (проверки): toBe, toEqual, toBeNull, toBeTruthy, toContain и многие другие. Они помогают проверять разные типы данных и условий.

Лайфхак: используйте toEqual для сравнения объектов и массивов, потому что toBe сравнивает по ссылке, а не по содержимому. Пример: expect({a: 1}).toEqual({a: 1}) — пройдёт, а toBe — нет.

Тестирование асинхронного кода

В современном JavaScript почти всё асинхронно: запросы к API, чтение файлов, таймеры. Jest умеет тестировать и это. Есть несколько способов:

  • Использовать колбэки (но это старый стиль).
  • Возвращать Promise из теста.
  • Использовать async/await.

Самый простой и читаемый способ — async/await. Вот пример:

// fetchData.js
function fetchData() {
  return new Promise((resolve) => {
    setTimeout(() => resolve('data'), 1000);
  });
}

// fetchData.test.js
const fetchData = require('./fetchData');

test('fetches data successfully', async () => {
  const data = await fetchData();
  expect(data).toBe('data');
});

Jest также позволяет проверять ошибки. Если ваш код должен выбрасывать исключение, используйте rejects или toThrow:

test('throws error if invalid input', async () => {
  await expect(fetchData('invalid')).rejects.toThrow('Invalid input');
});

Мок-функции и тестирование зависимостей

В реальном мире функции часто зависят от внешних модулей: баз данных, API, других функций. Чтобы тестировать изолированно, мы используем моки (заглушки). Jest позволяет создавать мок-функции с помощью jest.fn() или мокировать целые модули с помощью jest.mock().

Представьте, что у вас есть функция, которая отправляет запрос на сервер. В тесте мы не хотим делать реальный запрос — это медленно и ненадёжно. Вместо этого мы создаём мок:

// api.js
const api = {
  getUser: (id) => fetch(`/users/${id}`).then(res => res.json()),
};
module.exports = api;

// userService.js
const api = require('./api');

function getUserName(id) {
  return api.getUser(id).then(user => user.name);
}
module.exports = getUserName;

// userService.test.js
jest.mock('./api');
const api = require('./api');
const getUserName = require('./userService');

api.getUser.mockResolvedValue({ name: 'John' });

test('returns user name', async () => {
  const name = await getUserName(1);
  expect(name).toBe('John');
  expect(api.getUser).toHaveBeenCalledWith(1);
});

Обратите внимание: мы замокали модуль api, чтобы его функция getUser возвращала заранее известное значение. Это позволяет тестировать только логику userService, не завися от сети.

Правило: всегда мокайте внешние зависимости — это делает ваши тесты быстрыми и детерминированными. Никогда не полагайтесь на реальные API в тестах.

Снапшот-тестирование: когда оно полезно

Снапшоты — это снимки вывода вашего кода. Jest сохраняет их в файл, и при следующем запуске сравнивает с текущим выводом. Если вывод изменился, тест падает — и вы решаете, было ли это ожидаемо.

Это очень удобно для тестирования UI-компонентов, когда вы хотите убедиться, что интерфейс не изменился неожиданно. Пример для React:

import renderer from 'react-test-renderer';
import MyComponent from './MyComponent';

test('renders correctly', () => {
  const tree = renderer.create().toJSON();
  expect(tree).toMatchSnapshot();
});

При первом запуске Jest создаст файл .snap. При последующих — будет сравнивать. Если вы осознанно меняете компонент, обновите снапшот командой jest -u.

Но не злоупотребляйте снапшотами. Они хороши для проверки структуры, но не заменяют проверки поведения. Используйте их как дополнение.

Практические советы и типичные ошибки

Вот несколько советов, которые помогут вам писать качественные тесты:

  • Тестируйте поведение, а не реализацию. Не проверяйте внутренние функции, если они не являются частью публичного API.
  • Держите тесты изолированными. Каждый тест должен быть независимым — не полагайтесь на порядок выполнения.
  • Используйте beforeEach и afterEach для подготовки и очистки данных.
  • Не пренебрегайте покрытием кода. Хотя 100% покрытие — не самоцель, стремитесь к 80% и выше для важных модулей.

Типичные ошибки новичков:

  • Писать слишком много тестов на простые функции — достаточно одного-двух.
  • Тестировать только счастливый путь — не забывайте про ошибки и граничные случаи.
  • Игнорировать асинхронность — забыли указать async/await, и тест проходит ложно.
Лайфхак: используйте флаг --watch при разработке. Запустите jest --watch, и тесты будут автоматически перезапускаться при изменении файлов. Это экономит кучу времени.

Заключение

Jest — это мощный и простой инструмент, который делает тестирование приятным. Вы можете начать с малого: написать пару тестов для своих функций, затем перейти к асинхронному коду и мокам. Со временем тесты станут вашей второй натурой, и вы заметите, как меньше переживаете перед деплоем.

Что в итоге: тестирование — не роскошь, а необходимость. Jest снижает порог входа, а его возможности покрывают почти все сценарии. Начните сегодня, и через неделю вы не сможете представить разработку без тестов.

Студия WNDER