PurpleSchool — курсы программирования онлайн
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развития
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • Карьерные пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • PurpleSchool — курсы программирования онлайн
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Тестирование API: от unit-тестов до e2e с Playwright и Vitest

    Тестирование API: от unit-тестов до e2e с Playwright и Vitest

    Аватар автора Тестирование API: от unit-тестов до e2e с Playwright и Vitest

    Антон Ларичев

    Иконка календаря13 апреля 2026
    testingnodejstypescriptmiddleИконка уровня middle
    Картинка поста Тестирование API: от unit-тестов до e2e с Playwright и Vitest

    Введение

    Тестирование API — обязательная практика для любого проекта, который работает с серверной логикой. Без тестов вы узнаете о сломанном эндпоинте только от пользователей, а не на этапе разработки. Современный стек из Vitest и Playwright позволяет покрыть весь спектр: от быстрых unit-тестов отдельных функций до полноценных e2e-сценариев, проверяющих API от запроса до ответа.

    В этой статье разберём, как выстроить стратегию тестирования API на практике. Начнём с unit-тестов бизнес-логики в Vitest, перейдём к интеграционным тестам с моками через MSW и закончим e2e-тестами реального API с помощью Playwright. Каждый уровень — с примерами кода на TypeScript.

    Unit-тесты для API-логики в Vitest

    Unit-тесты проверяют отдельные функции в изоляции. Для API это валидаторы, трансформеры данных, middleware и бизнес-логика обработчиков.

    Настройка Vitest для проекта

    Установите Vitest и запустите первый тест:

    npm install -D vitest
    

    Добавьте скрипт в package.json:

    {
      "scripts": {
        "test": "vitest",
        "test:run": "vitest run"
      }
    }
    

    Как писать unit-тесты для валидации запросов

    Допустим, у вас есть функция валидации тела запроса:

    // src/validators/user.ts
    export function validateCreateUser(body: unknown): { valid: boolean; errors: string[] } {
      const errors: string[] = [];
      if (!body || typeof body !== 'object') {
        return { valid: false, errors: ['Тело запроса должно быть объектом'] };
      }
      const data = body as Record<string, unknown>;
      if (!data.email || typeof data.email !== 'string') {
        errors.push('Email обязателен');
      }
      if (!data.name || typeof data.name !== 'string' || (data.name as string).length < 2) {
        errors.push('Имя должно содержать минимум 2 символа');
      }
      return { valid: errors.length === 0, errors };
    }
    

    Тест для этой функции:

    // src/validators/user.test.ts
    import { describe, it, expect } from 'vitest';
    import { validateCreateUser } from './user';
    
    describe('validateCreateUser', () => {
      it('принимает корректные данные', () => {
        const result = validateCreateUser({ email: 'test@mail.com', name: 'Иван' });
        expect(result.valid).toBe(true);
        expect(result.errors).toHaveLength(0);
      });
    
      it('отклоняет пустое тело запроса', () => {
        const result = validateCreateUser(null);
        expect(result.valid).toBe(false);
        expect(result.errors).toContain('Тело запроса должно быть объектом');
      });
    
      it('требует email и имя', () => {
        const result = validateCreateUser({ email: '', name: 'A' });
        expect(result.valid).toBe(false);
        expect(result.errors.length).toBeGreaterThanOrEqual(1);
      });
    });
    

    Unit-тесты в Vitest запускаются за миллисекунды. Это ваша первая линия защиты от регрессий.

    Интеграционные тесты API с моками HTTP-запросов

    Интеграционные тесты проверяют взаимодействие нескольких модулей. Для тестирования API без реального сервера используют Mock Service Worker (MSW), который перехватывает HTTP-запросы на сетевом уровне.

    Настройка MSW с Vitest

    npm install -D msw
    

    Создайте обработчики моков:

    // src/mocks/handlers.ts
    import { http, HttpResponse } from 'msw';
    
    export const handlers = [
      http.get('/api/users/:id', ({ params }) => {
        const { id } = params;
        return HttpResponse.json({
          id: Number(id),
          name: 'Тестовый пользователь',
          email: 'test@example.com',
        });
      }),
    
      http.post('/api/users', async ({ request }) => {
        const body = await request.json();
        return HttpResponse.json({ id: 1, ...body }, { status: 201 });
      }),
    ];
    

    Подключите MSW в тестах:

    // src/services/api.test.ts
    import { describe, it, expect, beforeAll, afterAll } from 'vitest';
    import { setupServer } from 'msw/node';
    import { handlers } from '../mocks/handlers';
    
    const server = setupServer(...handlers);
    
    beforeAll(() => server.listen());
    afterAll(() => server.close());
    
    describe('API клиент', () => {
      it('получает пользователя по ID', async () => {
        const response = await fetch('/api/users/1');
        const data = await response.json();
    
        expect(response.status).toBe(200);
        expect(data.name).toBe('Тестовый пользователь');
      });
    
      it('создаёт нового пользователя', async () => {
        const response = await fetch('/api/users', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ name: 'Новый', email: 'new@test.com' }),
        });
        const data = await response.json();
    
        expect(response.status).toBe(201);
        expect(data.name).toBe('Новый');
      });
    });
    

    MSW работает на уровне сетевого стека, поэтому ваш код использует настоящий fetch — моки прозрачны для тестируемого кода.

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

    E2E-тесты проверяют реальный API на работающем сервере. Playwright предоставляет встроенный APIRequestContext для отправки HTTP-запросов без браузера.

    Настройка Playwright для тестирования API

    npm install -D @playwright/test
    

    Создайте конфигурацию:

    // playwright.config.ts
    import { defineConfig } from '@playwright/test';
    
    export default defineConfig({
      use: {
        baseURL: 'http://localhost:3000',
      },
      projects: [
        {
          name: 'api-tests',
          testDir: './tests/api',
        },
      ],
    });
    

    Как тестировать REST API эндпоинты в Playwright

    // tests/api/users.spec.ts
    import { test, expect } from '@playwright/test';
    
    test.describe('Users API', () => {
      let createdUserId: number;
    
      test('POST /api/users — создание пользователя', async ({ request }) => {
        const response = await request.post('/api/users', {
          data: {
            name: 'Playwright User',
            email: 'playwright@test.com',
          },
        });
    
        expect(response.status()).toBe(201);
        const body = await response.json();
        expect(body.id).toBeDefined();
        expect(body.name).toBe('Playwright User');
        createdUserId = body.id;
      });
    
      test('GET /api/users/:id — получение пользователя', async ({ request }) => {
        const response = await request.get(`/api/users/${createdUserId}`);
    
        expect(response.status()).toBe(200);
        const body = await response.json();
        expect(body.email).toBe('playwright@test.com');
      });
    
      test('DELETE /api/users/:id — удаление пользователя', async ({ request }) => {
        const response = await request.delete(`/api/users/${createdUserId}`);
        expect(response.status()).toBe(200);
    
        // Проверяем, что пользователь действительно удалён
        const check = await request.get(`/api/users/${createdUserId}`);
        expect(check.status()).toBe(404);
      });
    });
    

    Playwright выполняет реальные HTTP-запросы к серверу, проверяя полный цикл обработки: роутинг, middleware, базу данных и ответ.

    Тестирование авторизации и заголовков

    test('защищённый эндпоинт без токена возвращает 401', async ({ request }) => {
      const response = await request.get('/api/admin/stats');
      expect(response.status()).toBe(401);
    });
    
    test('защищённый эндпоинт с токеном возвращает данные', async ({ request }) => {
      const response = await request.get('/api/admin/stats', {
        headers: {
          Authorization: 'Bearer test-jwt-token',
        },
      });
      expect(response.status()).toBe(200);
    });
    

    Частые ошибки при тестировании API

    Тестирование только happy path. Проверяйте не только успешные сценарии, но и ошибки: невалидные данные, отсутствующие ресурсы, таймауты. E2e-тесты без негативных сценариев дают ложную уверенность.

    Зависимость между тестами. Каждый тест должен работать независимо. Если один тест создаёт данные для другого, используйте beforeEach для подготовки состояния.

    Отсутствие тестов на контракт. Проверяйте структуру ответа, а не только статус-код. Если API возвращает 200, но с неправильным форматом — это баг.

    Игнорирование таймаутов. В e2e-тестах всегда задавайте разумные таймауты. Playwright позволяет настроить их глобально и для отдельных запросов.

    Стратегия: какие тесты писать для API

    Оптимальная пирамида тестирования API:

    • Unit-тесты (70%) — Vitest: валидаторы, трансформеры, утилиты, бизнес-логика. Быстрые, дешёвые, запускаются на каждый коммит.
    • Интеграционные (20%) — Vitest + MSW: взаимодействие модулей, API-клиенты, обработка ответов. Средняя скорость, проверяют контракты.
    • E2E (10%) — Playwright: критические пользовательские сценарии, авторизация, CRUD-операции. Медленные, но проверяют реальную систему.

    Такое распределение обеспечивает быструю обратную связь от unit-тестов и надёжность от e2e, не замедляя CI/CD пайплайн.

    Заключение

    Тестирование API не требует одного инструмента на все случаи. Vitest отлично справляется с unit-тестами и интеграционными проверками благодаря скорости и поддержке ESM. Playwright закрывает e2e-уровень, отправляя реальные запросы к серверу. Вместе они покрывают весь спектр — от проверки одной функции до полного сценария с авторизацией, CRUD и обработкой ошибок. Начните с unit-тестов критичной логики, добавьте интеграционные тесты с MSW и завершите e2e-проверками ключевых эндпоинтов.

    Иконка глаза7

    Комментарии

    0

    Постройте личный план изучения TypeScript с нуля - полный курс и паттерны проектирования до уровня Middle — бесплатно!

    TypeScript с нуля - полный курс и паттерны проектирования — часть карты развития Frontend, Backend, Mobile

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    React и Redux Toolkit

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    React Native и Expo Router

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.7
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Основы Swift и iOS

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста Монорепозиторий на Turborepo: как организовать фронт и бэк в одном репо
    Иконка аватараАнтон
    Иконка календаря10 апреля 2026
    typescriptreactnodejsmiddleИконка уровня middle

    Монорепозиторий на Turborepo: как организовать фронт и бэк в одном репо

    Разбираем, как настроить монорепозиторий на Turborepo для React и NestJS: структура проекта, общие типы, pipeline задач и кэширование сборки.

    Иконка чипа0
    Иконка глаза98
    Иконка комментариев0
    Картинка поста CQRS и Event Sourcing на практике: когда это оправдано, а когда — оверинжиниринг
    Иконка аватараАнтон
    Иконка календаря09 апреля 2026
    architecturetypescriptnodejsseniorИконка уровня senior

    CQRS и Event Sourcing на практике: когда это оправдано, а когда — оверинжиниринг

    CQRS и Event Sourcing — архитектурные паттерны для сложных доменов. Разбираем реальные примеры на TypeScript и NestJS, критерии выбора и типичные ошибки внедрения.

    Иконка чипа0
    Иконка глаза124
    Иконка комментариев0
    Картинка поста Мониторинг приложения: Prometheus + Grafana для Node.js за час
    Иконка аватараАнтон
    Иконка календаря08 апреля 2026
    devopsnodejsmiddleИконка уровня middle

    Мониторинг приложения: Prometheus + Grafana для Node.js за час

    Настраиваем мониторинг Node.js приложения с Prometheus и Grafana за час: подключаем prom-client, собираем метрики, создаём дашборд и поднимаем всё через Docker Compose.

    Иконка чипа0
    Иконка глаза158
    Иконка комментариев0
    Иконка чипа0