E2E тестирование

E2E (End-to-End) тест проверяет полный пользовательский сценарий от начала до конца — через реальный браузер или HTTP-запросы к запущенному приложению со всеми его зависимостями.

Зачем нужно

E2E-тесты — единственный вид тестов, который гарантирует, что система работает так, как её видит конечный пользователь. Они обнаруживают ошибки интеграции между фронтендом и бэкендом, проблемы с конфигурацией и маршрутизацией, которые невидимы на уровне unit и integration тестов. При этом E2E-тесты дорогие — их должно быть мало, только для критических пользовательских сценариев.

Где используется

  • Регрессионное тестирование перед релизом: «авторизация → корзина → оплата» работает
  • Smoke-тесты после деплоя в production или staging-окружение
  • Тестирование критических путей SPA (Single Page Application)
  • API E2E-тесты: полный HTTP-цикл через запущенный Node.js-сервер

Основной контент

Виды E2E-тестирования

Подход Инструмент Скорость Уровень
Браузерный Playwright, Cypress Медленно Полный UI
HTTP API supertest + реальный сервер Быстрее Бэкенд
CLI child_process Быстро Консольные приложения

HTTP API E2E с реальным сервером

// server.js
const app = require('./app');
const server = app.listen(3001);
module.exports = server;
// e2e/auth.e2e.test.js
const request = require('supertest');
const server = require('../server');

afterAll( => server.close());

describe('Полный сценарий: регистрация и авторизация', () => {
  let authToken;

  test('1. Регистрирует нового пользователя', async () => {
    const res = await request(server)
      .post('/api/auth/register')
      .send({ name: 'Alice', email: 'alice@test.com', password: 'Passw0rd!' });

    expect(res.status).toBe(201);
    expect(res.body.id).toBeDefined();
  });

  test('2. Авторизует пользователя и получает JWT', async () => {
    const res = await request(server)
      .post('/api/auth/login')
      .send({ email: 'alice@test.com', password: 'Passw0rd!' });

    expect(res.status).toBe(200);
    expect(res.body.token).toBeDefined();
    authToken = res.body.token;
  });

  test('3. Получает профиль с токеном', async () => {
    const res = await request(server)
      .get('/api/profile')
      .set('Authorization', `Bearer ${authToken}`);

    expect(res.status).toBe(200);
    expect(res.body.email).toBe('alice@test.com');
  });

  test('4. Отклоняет запрос без токена', async () => {
    const res = await request(server).get('/api/profile');
    expect(res.status).toBe(401);
  });
});

Playwright — браузерный E2E

npm install --save-dev @playwright/test
npx playwright install chromium
// e2e/login.spec.js
const { test, expect } = require('@playwright/test');

test('пользователь входит и видит дашборд', async ({ page }) => {
  await page.goto('http://localhost:3000');

  // Заполняем форму
  await page.fill('[data-testid="email"]', 'user@test.com');
  await page.fill('[data-testid="password"]', 'secret');
  await page.click('[data-testid="submit"]');

  // Проверяем что перешли на дашборд
  await expect(page).toHaveURL(/\/dashboard/);
  await expect(page.locator('h1')).toContainText('Добро пожаловать');
});
npx playwright test          # запуск всех E2E-тестов
npx playwright test --ui     # интерактивный режим
npx playwright show-report   # HTML-отчёт

E2E в CI/CD

# .github/workflows/e2e.yml
name: E2E Tests
on: [push]
jobs:
  e2e:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: test
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm ci
      - run: npm run db:migrate
        env:
          DATABASE_URL: postgres://postgres:test@localhost/test
      - run: npm run test:e2e
        env:
          DATABASE_URL: postgres://postgres:test@localhost/test

Частые ошибки

  • Слишком много E2E-тестов — каждый E2E-тест в 10-100 раз дороже unit-теста; покрывай только критические сценарии
  • Флакающие тесты — асинхронные операции (анимации, задержки) без явного waitFor делают тест нестабильным
  • Запуск E2E на каждый коммит — E2E лучше запускать только при слиянии в main/master или перед релизом
  • Жёсткие селекторыdiv:nth-child(3) > span сломается при любом изменении разметки; используй data-testid атрибуты
  • Не изолированное состояние — E2E-тесты должны создавать собственные данные и не зависеть от порядка запуска

Связанные темы

Ресурсы