Тестирование кода — это как проверка домашнего задания перед сдачей. Если не проверить, можно получить двойку. В мире JavaScript без тестов ваш код может «упасть» в самый неподходящий момент. Эта статья поможет разобраться в современных подходах к тестированию JS, чтобы ваш код был надёжным, как швейцарские часы.

Digital-студия WNDER

Зачем вообще тестировать JavaScript?

JavaScript — язык динамический и местами непредсказуемый. Одна опечатка может привести к багу, который проявится только у пользователя. Тесты помогают ловить ошибки на ранней стадии, упрощают рефакторинг и служат документацией. Если вы пишете код без тестов, вы играете в рулетку.

Основные виды тестов: юнит-тесты (проверяют отдельные функции), интеграционные (взаимодействие модулей), end-to-end (E2E) — проверяют весь сценарий в браузере. Каждый уровень решает свою задачу.

Правило: Не гонитесь за 100% покрытием. Стремитесь к покрытию критических участков кода. Тесты должны приносить пользу, а не создавать иллюзию безопасности.

Юнит-тестирование с Jest

Jest — самый популярный фреймворк для юнит-тестов в JS. Он прост, быстр и идёт из коробки с моками и ассертами. Допустим, у нас есть функция сложения:

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

Напишем тест:

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

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

Запускаем npx jest — и видим результат. Jest также умеет тестировать асинхронный код, работать с таймерами и моками.

Для React-компонентов часто используют React Testing Library вместе с Jest. Она позволяет тестировать поведение, а не реализацию.

import { render, screen } from '@testing-library/react';
import Button from './Button';

test('renders button with text', () => {
  render(<Button>Click me</Button>);
  expect(screen.getByText('Click me')).toBeInTheDocument();
});

Интеграционное тестирование и моки

Интеграционные тесты проверяют, как модули работают вместе. Например, функция, которая делает запрос к API, и компонент, который её вызывает. Здесь часто используют моки (mocks) для подмены внешних зависимостей.

В Jest можно мокать модули целиком:

jest.mock('./api');

import { fetchData } from './api';
import { getData } from './service';

test('getData returns data from api', async () => {
  fetchData.mockResolvedValue({ id: 1 });
  const data = await getData();
  expect(data).toEqual({ id: 1 });
});

Для HTTP-запросов удобно использовать библиотеку nock или msw (Mock Service Worker). MSW перехватывает запросы на уровне сети и позволяет эмулировать ответы сервера.

E2E-тестирование с Cypress и Playwright

E2E-тесты имитируют действия реального пользователя: клики, ввод текста, переходы. Это самый надёжный способ убедиться, что приложение работает целиком.

Cypress — популярный инструмент с удобным API. Пример теста:

describe('Login', () => {
  it('successfully logs in', () => {
    cy.visit('/login');
    cy.get('input[name=email]').type('user@example.com');
    cy.get('input[name=password]').type('password123');
    cy.get('button[type=submit]').click();
    cy.url().should('include', '/dashboard');
  });
});

Playwright — более новый инструмент от Microsoft. Он поддерживает кросс-браузерность и параллельный запуск. Пример:

const { test, expect } = require('@playwright/test');

test('login test', async ({ page }) => {
  await page.goto('/login');
  await page.fill('input[name=email]', 'user@example.com');
  await page.fill('input[name=password]', 'password123');
  await page.click('button[type=submit]');
  await expect(page).toHaveURL('/dashboard');
});

Оба инструмента хороши, но Cypress проще для новичков, а Playwright мощнее для сложных сценариев.

Мутационное тестирование и покрытие

Мутационное тестирование — это когда в код вносят небольшие изменения (мутации) и смотрят, поймают ли их тесты. Если тесты не замечают мутацию, значит, они бесполезны. Инструмент Stryker помогает автоматизировать этот процесс.

Покрытие кода (coverage) показывает, какой процент кода выполняется во время тестов. Но высокое покрытие не гарантирует качество. Лучше сочетать покрытие с мутационным тестированием.

Инструмент Назначение Особенности
Jest Юнит-тесты Быстрый, встроенные моки, снапшоты
Cypress E2E Автоожидание, отладка в браузере
Playwright E2E Кросс-браузерность, параллельность
Stryker Мутационное тестирование Оценка качества тестов
Лайфхак: Запускайте тесты в watch-режиме во время разработки. Это экономит время и сразу показывает ошибки.

Что в итоге?

Современное тестирование JavaScript — это комбинация разных техник. Юнит-тесты с Jest для быстрой проверки логики, интеграционные тесты с моками для взаимодействия модулей, E2E с Cypress или Playwright для уверенности в работе приложения. Не забывайте про мутационное тестирование, чтобы ваши тесты были действительно полезными. И помните: тесты — это инвестиция в будущее вашего проекта.

Начните с малого: покройте тестами одну функцию. Затем ещё одну. Постепенно вы построите надёжную систему, которая будет ловить баги до того, как они доберутся до пользователей.

Студия WNDER