Автоматизация тестирования API на Playwright и TypeScript: от первого запроса до архитектуры фреймворка

Практический курс для начинающих тестировщиков, направленный на освоение автоматизации API. Ученики пройдут путь от настройки среды и базовых CRUD-операций до создания масштабируемой архитектуры с использованием паттернов проектирования.

1. Введение в Playwright и настройка рабочего окружения на TypeScript

Введение в Playwright и настройка рабочего окружения на TypeScript

Почему сегодня, когда рынок переполнен инструментами вроде Postman, RestAssured или Axios, инженеры по автоматизации всё чаще выбирают Playwright для тестирования API? Ответ кроется в парадоксе: инструмент, созданный для автоматизации браузеров, оказался идеальной средой для проверки серверной логики. Представьте себе экосистему, где тесты интерфейса (UI) и логики (API) живут в одном проекте, используют один язык программирования, общие конфигурации и единый механизм генерации отчетов. Это не просто удобно — это радикально сокращает время на поддержку тестового фреймворка.

В этой главе мы заложим фундамент вашего мастерства. Мы не просто установим программы, а разберемся, как взаимодействуют компоненты Node.js, TypeScript и Playwright, чтобы создать надежную среду для разработки автотестов.

Философия Playwright в контексте API

Традиционно Playwright воспринимается как конкурент Selenium или Cypress. Однако его архитектура построена на концепции контекстов. Внутри одного тестового запуска Playwright может создавать изолированные «личности» (BrowserContext), и точно так же он умеет создавать APIRequestContext.

Главное преимущество здесь — скорость и встроенные механизмы ожидания. Когда мы тестируем API через Playwright, мы получаем:

  • Единый конфиг: Настройки базового URL, таймаутов и заголовков прописываются один раз.
  • Встроенный прокси-слой: Возможность легко перехватывать запросы.
  • Типизация: Благодаря TypeScript, мы видим структуру запроса и ответа еще до запуска теста.
  • Для тестировщика, переходящего от ручного тестирования к автоматизации, связка TypeScript + Playwright является наиболее «дружелюбной». TypeScript не дает совершить глупых ошибок в синтаксисе, а Playwright берет на себя всю грязную работу по обработке сетевых соединений.

    Подготовка фундамента: Node.js и управление версиями

    Прежде чем написать первую строчку кода, необходимо подготовить операционную систему. Playwright — это библиотека для Node.js, поэтому Node.js является нашим «двигателем».

    Почему версия имеет значение

    Node.js развивается стремительно. Существуют LTS-версии (Long Term Support) и текущие (Current). Для автоматизации тестирования критически важно использовать LTS-версию. Это гарантирует стабильность библиотек и отсутствие неожиданных багов в самом движке выполнения кода.

    Для управления версиями Node.js профессионалы используют NVM (Node Version Manager). Это позволяет переключаться между проектами, которые могут требовать разные версии Node.js, без переустановки всей системы.

    > NVM (Node Version Manager) — это утилита командной строки, позволяющая устанавливать несколько версий Node.js на один компьютер и переключаться между ними одной командой. > > Официальный репозиторий NVM

    Если вы работаете на Windows, существует аналогичный инструмент — nvm-windows. Установка Node.js напрямую с официального сайта — это допустимый путь для новичка, но он лишает вас гибкости в будущем.

    Проверка окружения

    После установки Node.js в вашей системе появляются две ключевые команды: node и npm.

  • node: исполняемая среда, которая читает ваш JavaScript/TypeScript код и выполняет его.
  • npm (Node Package Manager): менеджер пакетов, гигантская библиотека готовых решений, откуда мы и будем скачивать Playwright.
  • Проверьте корректность установки, введя в терминале:

    Если вы видите номера версий (например, v20.11.0 и 10.2.4), значит, фундамент заложен.

    Выбор и настройка IDE: Visual Studio Code

    Код можно писать и в блокноте, но для эффективной работы нам нужен инструмент, который будет подсказывать ошибки. Visual Studio Code (VS Code) де-факто является стандартом в индустрии автоматизации на TypeScript.

    Необходимые расширения

    Чтобы превратить VS Code в мощную станцию для тестировщика, установите следующие расширения:

  • Playwright Test for VSCode: официальный плагин от Microsoft. Он позволяет запускать тесты нажатием одной кнопки «Play» рядом со строкой кода и визуализировать прохождение тестов.
  • ESLint: помогает поддерживать чистоту кода и указывает на стилистические ошибки.
  • Prettier: автоматически форматирует код при сохранении. Это важно, когда над проектом работает команда — код у всех будет выглядеть одинаково.
  • Создание проекта и инициализация Playwright

    Перейдем к практике. Создайте пустую папку для вашего проекта, откройте её в VS Code и вызовите встроенный терминал (Ctrl+ или через меню).

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

    В процессе выполнения команда задаст вам несколько уточняющих вопросов. Для нашего курса по API выберите следующие параметры:

  • TypeScript: Да (это наш основной язык).
  • Folder for tests: tests (стандартное название).
  • Add a GitHub Actions workflow: Да (понадобится в будущем для настройки CI/CD).
  • Install Playwright browsers: Можно выбрать «Нет», если вы планируете тестировать только API, но лучше оставить «Да», так как браузеры могут понадобиться для визуальной проверки результатов или сложных сценариев авторизации.
  • Разбор структуры проекта

    После завершения команды структура вашего проекта будет выглядеть так:

  • node_modules/: папка с «тяжелыми» зависимостями. Мы никогда не правим там код вручную.
  • tests/: здесь будут лежать ваши файлы с тестами (например, example.spec.ts).
  • playwright.config.ts: «мозг» вашего фреймворка. Здесь настраиваются URL сервера, таймауты, отчеты и ретраи (повторные запуски).
  • package.json: паспорт вашего проекта. Здесь указаны версии библиотек и скрипты для запуска.
  • tsconfig.json: настройки компилятора TypeScript.
  • TypeScript: зачем он тестировщику?

    Многие новички боятся TypeScript, считая его избыточным. «Зачем мне сложности с типами, если я просто хочу отправить запрос?» — частый вопрос.

    Давайте сравним. В обычном JavaScript вы можете отправить в поле age строку "двадцать", и программа поймет это только в момент падения теста на сервере. TypeScript подсветит это поле красным еще в момент написания кода, указав, что ожидается .

    Для API-тестирования TypeScript незаменим при работе с JSON-ответами. Мы можем описать интерфейс ответа:

    Теперь, когда вы наберете user., IDE сама предложит вам варианты id, name или email. Это исключает опечатки и ускоряет написание тестов в разы.

    Глубокая настройка playwright.config.ts для API

    Стандартный конфиг Playwright сильно ориентирован на UI-тесты. Для эффективного тестирования API нам нужно его немного подправить. Откройте playwright.config.ts.

    Базовые параметры

    В объекте defineConfig обратите внимание на следующие поля:

  • use: здесь мы задаем глобальные настройки для всех запросов.
  • Установка baseURL позволяет в самих тестах писать относительные пути, например, просто /login вместо полного URL.

  • reporter: Playwright предлагает отличные HTML-отчеты «из коробки».
  • Параметр open: 'never' предотвращает автоматическое открытие браузера с отчетом после каждого прогона тестов, что удобно при частой разработке.

  • testDir: указывает, где искать файлы тестов. По умолчанию это ./tests.
  • Игнорирование браузеров для API-тестов

    В секции projects по умолчанию указаны Chromium, Firefox и Webkit. Для чистого API-тестирования они не обязательны. Вы можете создать отдельный проект в конфиге специально для API:

    Первый контакт: проверка работоспособности

    Чтобы убедиться, что окружение настроено верно, создадим простой файл tests/healthcheck.spec.ts. Мы не будем пока глубоко погружаться в методы, наша задача — проверить, что Playwright видит сервер и может обработать ответ.

    Разбор кода

  • import { test, expect }: мы импортируем базовые функции Playwright. test определяет сам тест, а expect — это библиотека утверждений (assertions).
  • async ({ request }): тесты в Playwright асинхронны. Фикстура request — это встроенный объект Playwright для выполнения HTTP-запросов.
  • await: мы ждем, пока сервер ответит, прежде чем переходить к следующей строке.
  • response.ok(): удобный метод, который возвращает true, если статус-код находится в диапазоне .
  • Запустите тест командой в терминале:

    Если всё настроено верно, вы увидите зеленое сообщение о прохождении теста.

    Работа с переменными окружения (.env)

    В профессиональной разработке никогда не хранят пароли, токены или секретные URL прямо в коде. Для этого используются файлы окружения.

  • Установите пакет dotenv:
  • Создайте в корне проекта файл .env:
  • Подключите его в начале playwright.config.ts:
  • Теперь в конфиге или тестах вы можете обращаться к этим данным через process.env.API_TOKEN.
  • Это критически важный аспект безопасности. Файл .env обычно добавляют в .gitignore, чтобы секретные данные не попали в публичный репозиторий.

    Тонкости работы с npm и package.json

    Ваш файл package.json — это не только список библиотек. В секции "scripts" вы можете создавать короткие команды для запуска тестов.

    Пример полезных скриптов:

    Теперь вместо длинной команды в терминале можно писать npm run test:api.

    Семантическое версионирование (SemVer)

    Обратите внимание на символы перед версиями библиотек в package.json:

  • ^1.42.0: означает, что при обновлении (npm update) может установиться любая минорная версия (например, 1.45.0), но не мажорная (2.0.0).
  • ~1.42.0: разрешает только патч-обновления (например, 1.42.1).
  • Для стабильности фреймворка рекомендуется фиксировать версии или использовать package-lock.json, который создается автоматически и гарантирует, что у всех членов команды установлены идентичные зависимости.

    Распространенные ошибки при настройке

    Даже опытные инженеры иногда сталкиваются с проблемами при первой настройке. Вот чек-лист для самопроверки:

  • Конфликт версий Node.js: Если проект требует Node.js 18, а у вас стоит 14, Playwright может просто не запуститься с невнятной ошибкой синтаксиса. Всегда проверяйте node -v.
  • Прокси и корпоративные сети: Если вы настраиваете окружение в офисе, npm install может блокироваться корпоративным файрволом. В этом случае нужно настроить прокси для npm через npm config set proxy.
  • Отсутствие типов: Если VS Code не подсказывает методы объекта request, убедитесь, что в начале файла есть импорт из @playwright/test.
  • Проблемы с путями: В Windows и Linux пути пишутся по-разному. Playwright сглаживает эти углы, но при ручной настройке testDir всегда используйте относительные пути от корня проекта.
  • Изоляция тестов и глобальные настройки

    Playwright по умолчанию запускает тесты в несколько потоков (параллельно). Это значительно ускоряет выполнение, но накладывает ограничения: тесты не должны зависеть друг от друга.

    В контексте API это означает, что если один тест создает пользователя, а второй его удаляет, они могут столкнуться, если запустятся одновременно. На этапе настройки окружения важно понимать, что каждый файл теста в Playwright запускается в своем собственном процессе.

    Если вам нужно выполнить какое-то действие один раз перед всеми тестами (например, получить глобальный токен доступа), Playwright предоставляет хуки test.beforeAll и globalSetup. Однако для новичков рекомендуется начинать с простых независимых тестов, чтобы не усложнять отладку.

    Оптимизация рабочего пространства

    Для комфортной работы настройте «автосохранение» в VS Code (File -> Auto Save). В мире TypeScript это избавляет от досадных ситуаций, когда вы исправили ошибку, запустили тест, а он упал, потому что файл не был сохранен.

    Также полезно освоить горячие клавиши терминала:

  • Ctrl + C: остановить выполнение тестов.
  • Стрелка вверх: повторить предыдущую команду.
  • clear`: очистить экран терминала.
  • Настройка окружения — это не разовое действие, а процесс эволюции вашего проекта. По мере роста количества тестов вы будете добавлять новые библиотеки для логирования, генерации данных (например, Faker) или работы с базами данных. Но сейчас, имея установленный Node.js, настроенный TypeScript и инициализированный Playwright, вы готовы к тому, чтобы совершить свой первый настоящий HTTP-запрос.

    В следующей части мы разберем анатомию протокола HTTP и научимся не просто отправлять запросы, а понимать, что именно происходит «под капотом» между вашим тестом и сервером.

    2. Основы протокола HTTP и выполнение первых запросов в Playwright

    Основы протокола HTTP и выполнение первых запросов в Playwright

    Представьте, что вы приходите в ресторан. Вы не идете на кухню, чтобы пожарить себе стейк — вы взаимодействуете с официантом. Вы передаете ему заказ (запрос), он уносит его повару, а через некоторое время возвращается с блюдом или сообщением о том, что продукты закончились (ответ). В мире веб-сервисов роль такого официанта играет протокол HTTP. Без понимания того, как именно «официант» передает ваши пожелания серверу, невозможно построить качественную автоматизацию тестирования. Даже самый мощный инструмент вроде Playwright — это лишь удобный блокнот для записи заказов, если вы не понимаете правил коммуникации.

    Анатомия HTTP-взаимодействия

    HTTP (HyperText Transfer Protocol) — это фундамент обмена данными в сети, работающий по модели «клиент-сервер». Важно понимать, что HTTP является протоколом без сохранения состояния (stateless). Это означает, что каждый запрос для сервера — как первый. Сервер не обязан помнить, что вы спрашивали секунду назад, если вы не передадите ему специальные опознавательные знаки (например, токены или куки).

    Любая транзакция в API состоит из двух фаз: Request (Запрос) и Response (Ответ). Для тестировщика это критическая точка: мы проверяем, соответствует ли то, что мы отправили, тому, что мы ожидали получить.

    Структура HTTP-запроса

    Когда мы используем Playwright для отправки запроса, под капотом формируется текстовое сообщение определенного формата. Оно состоит из четырех ключевых частей:

  • Стартовая строка (Start Line): Содержит метод (что сделать?), путь к ресурсу (где сделать?) и версию протокола. Например: GET /api/users HTTP/1.1.
  • Заголовки (Headers): Метаданные запроса. Здесь мы указываем, в каком формате передаем данные (Content-Type), какие данные готовы принять (Accept), а также передаем ключи авторизации.
  • Пустая строка: Обязательный разделитель между заголовками и телом.
  • Тело (Body): Сами данные. В методах вроде GET тело обычно отсутствует, а в POST или PUT здесь передается JSON-объект с информацией о новом пользователе или заказе.
  • Структура HTTP-ответа

    Получив запрос, сервер обрабатывает его и возвращает ответ, который также структурирован:

  • Статус-строка (Status Line): Содержит версию протокола и код состояния. Например, HTTP/1.1 200 OK.
  • Заголовки ответа: Информация о сервере, типе контента, кодировке и времени ответа.
  • Тело ответа: Данные, которые мы запрашивали (обычно в формате JSON).
  • Методы как глаголы автоматизации

    В тестировании API мы оперируем понятием CRUD (Create, Read, Update, Delete). Каждому действию соответствует свой HTTP-метод. В Playwright выбор метода определяет, какой функцией объекта request мы воспользуемся.

    * GET: Используется для получения данных. Это «безопасный» метод, так как он не должен изменять состояние сервера. Если вы 100 раз вызовете GET /users/1, данные на сервере останутся прежними. * POST: Создание нового ресурса. В отличие от GET, этот метод идемпотентным не является: два одинаковых POST-запроса создадут двух одинаковых пользователей (если на сервере нет валидации уникальности). * PUT: Полное обновление ресурса. Мы отправляем объект целиком, заменяя старую версию новой. * PATCH: Частичное обновление. Если нужно изменить только фамилию пользователя, не затрагивая остальные поля, используется PATCH. * DELETE: Удаление ресурса.

    Понимание этой семантики помогает тестировщику правильно проектировать проверки. Например, после выполнения DELETE логично ожидать, что последующий GET вернет ошибку 404 (Not Found).

    Коды состояния: язык сервера

    Коды состояния (Status Codes) — это первый эшелон проверки в автоматизированных тестах. Они делятся на пять групп, и знание их границ — обязательный навык.

    | Диапазон | Категория | Значение для тестировщика | | :--- | :--- | :--- | | 1xx | Информационные | Встречаются редко, сообщают о продолжении процесса. | | 2xx | Успех | Запрос выполнен успешно. Самый частый гость — 200 OK и 201 Created. | | 3xx | Перенаправление | Ресурс переехал. Playwright часто обрабатывает их автоматически. | | 4xx | Ошибка клиента | Вы отправили что-то не то: неверный URL (404), нет прав (401/403) или плохой JSON (400). | | 5xx | Ошибка сервера | Проблема на стороне бэкенда. Тест должен падать, а баг — заводиться. |

    Работа с APIRequestContext в Playwright

    В первой статье мы упоминали, что Playwright предоставляет объект request через фикстуры. Этот объект является экземпляром класса APIRequestContext. В отличие от браузерного тестирования, где мы управляем страницей (page), в API-тестах мы работаем напрямую с контекстом запросов.

    Почему не использовать стандартный fetch или axios?

    Playwright предоставляет ряд преимуществ для тестирования:

  • Интеграция с конфигом: Он автоматически подхватывает baseURL и заголовки из playwright.config.ts.
  • Управление контекстом: Легко изолировать куки и токены между разными тестами.
  • Встроенная отчетность: Запросы, сделанные через APIRequestContext, отображаются в стандартных отчетах Playwright (Trace Viewer).
  • Автоматическая обработка JSON: Вам не нужно вручную вызывать JSON.stringify() при отправке данных.
  • Первый GET-запрос: получение данных

    Разберем практический пример. Допустим, у нас есть эндпоинт /api/posts/1, который возвращает данные о статье.

    В этом примере request.get возвращает объект типа APIResponse. Важно помнить, что методы response.json() или response.text() являются асинхронными, поэтому использование await обязательно.

    Отправка данных: метод POST

    При создании ресурса нам нужно передать данные. Playwright позволяет передавать объект напрямую в поле data.

    Обратите внимание: Playwright по умолчанию устанавливает заголовок Content-Type: application/json, если вы передаете объект в data. Однако явное указание заголовков считается хорошим тоном в тестах, так как это делает намерения тестировщика прозрачными.

    Нюансы URL и параметров запроса

    Часто нам нужно передать параметры фильтрации или поиска. В HTTP это делается через Query Parameters — часть URL после знака вопроса. Пример: /api/users?role=admin&status=active.

    В Playwright есть два способа работы с ними:

  • Прямая запись в строке: request.get('/users?role=admin').
  • Использование объекта params:
  • Второй способ предпочтительнее для автоматизации, так как он позволяет динамически формировать набор параметров из переменных или генераторов данных (например, Faker), избегая ошибок с конкатенацией строк и спецсимволами.

    Работа с заголовками (Headers)

    Заголовки — это способ общения с сервером на уровне протокола. В тестировании API мы чаще всего сталкиваемся со следующими:

    * Authorization: Передача токенов (Bearer, Basic). Без него большинство защищенных API вернут 401 Unauthorized. * Accept: Мы говорим серверу: «Я жду ответ в формате JSON». Если сервер умеет отдавать и XML, и JSON, этот заголовок критичен. * User-Agent: Иногда серверы блокируют запросы, если в заголовке не указан «человеческий» браузер. Playwright позволяет легко имитировать любое устройство.

    Заголовки можно задавать на трех уровнях:

  • Глобально в конфиге: Для всех тестов сразу.
  • В контексте: При создании отдельного APIRequestContext.
  • В конкретном запросе: Как показано в примере с POST выше.
  • Если заголовок определен и в конфиге, и в запросе, значение из запроса будет иметь приоритет (переопределит глобальное).

    Обработка ответов и отладка

    При написании первых тестов новички часто сталкиваются с тем, что тест падает, а причина неясна. В Playwright есть несколько инструментов для «проявки» того, что происходит внутри HTTP-сессии.

    Метод response.ok()

    Вместо того чтобы всегда проверять toBe(200), можно использовать метод ok(). Он возвращает true, если статус-код находится в диапазоне .

    Это делает тесты более устойчивыми к изменениям API (например, если сервер сменил 200 OK на 201 Created).

    Логирование для отладки

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

    Для глубокого анализа лучше использовать Playwright Trace Viewer. Он покажет полную цепочку: какой именно запрос ушел (со всеми заголовками и телом) и что именно пришло в ответ.

    Типизация запросов и ответов в TypeScript

    Поскольку мы используем TypeScript, мы можем (и должны) извлекать выгоду из типизации. Вместо работы с типом any, который возвращает response.json() по умолчанию, стоит описывать интерфейсы.

    Использование as Post — это «утверждение типа» (type assertion). Это говорит компилятору: «Я уверен, что здесь придет объект такой структуры». Это не гарантирует, что данные придут именно такие (для этого нужна валидация схем, которую мы разберем позже), но значительно упрощает написание кода теста и снижает количество опечаток в названиях полей.

    Граничные случаи и ошибки

    При тестировании API важно проверять не только «счастливый путь» (Happy Path), но и то, как система реагирует на некорректные действия.

  • Несуществующий ресурс: Запрос GET /posts/999999 должен возвращать 404.
  • Неверный формат данных: Отправка строки вместо числа в поле userId в POST-запросе должна приводить к 400 Bad Request.
  • Отсутствие авторизации: Если эндпоинт защищен, запрос без заголовка Authorization должен завершиться с кодом 401.
  • В Playwright проверка негативных сценариев выглядит так же просто, как и позитивных:

    Важный нюанс: по умолчанию Playwright не бросает исключение, если сервер вернул ошибку (4xx или 5xx). Тест продолжится, пока не встретит expect, который не выполнится. Это удобно, так как позволяет нам проверять сами ошибки. Однако, если вы хотите, чтобы запрос «взрывался» при любом статусе, отличном от успешного, можно использовать опцию failOnStatusCode: true в конфиге или запросе.

    Синхронность и асинхронность в API-тестах

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

    Если вы напишете:

    Вы получите ошибку, так как response в данном случае — это Promise (обещание), а не сам объект ответа. Метод status() у промиса отсутствует. Всегда следите за тем, чтобы операции с request и извлечение данных из response были «ожидаемыми» через await.

    Идемпотентность и состояние окружения

    При выполнении первых запросов важно помнить о состоянии тестовой среды. Если ваш тест создает пользователя, а затем проверяет общий список пользователей, то при повторном запуске в списке будет уже два пользователя.

    Хороший API-тест должен быть:

  • Автономным: Не зависеть от результатов работы других тестов.
  • Повторяемым: Выдавать один и тот же результат при неизменном коде.
  • Для этого часто используют подход с «подчисткой» данных: если тест создал пост через POST, в конце теста (или в специальном блоке afterEach) этот пост должен быть удален через DELETE. В Playwright это реализуется через хуки жизненного цикла, которые мы подробно изучим в следующих модулях.

    Понимание основ HTTP и умение пользоваться APIRequestContext — это 50% успеха в автоматизации API. Остальные 50% — это умение правильно организовывать проверки и выстраивать архитектуру, которая не превратится в «спагетти-код» при росте количества тестов. Теперь, когда мы умеем отправлять базовые запросы и понимать ответы сервера, мы готовы к более глубокому погружению в каждый из методов и сложную валидацию данных.

    3. Работа с методами GET, POST, PUT и DELETE: практическая реализация

    Работа с методами GET, POST, PUT и DELETE: практическая реализация

    Представьте, что вы строите систему управления складом. Чтобы узнать, сколько товара осталось, вы открываете отчет (GET). Чтобы добавить новую партию, вы заполняете накладную (POST). Если в накладной нашли ошибку, вы исправляете её (PUT), а если товар списан в утиль — удаляете запись (DELETE). В автоматизации API всё происходит точно так же, но вместо бумаги и ручки мы используем HTTP-методы. Ошибка в выборе метода или неправильная обработка его специфики — это прямой путь к «хрупким» тестам, которые падают от любого изменения на сервере.

    Жизненный цикл данных и CRUD-операции

    В основе большинства API лежит концепция CRUD (Create, Read, Update, Delete). Каждому из этих действий соответствует свой HTTP-метод. Однако на практике граница между ними иногда размывается, что приводит к ошибкам в тестах.

    | Операция | HTTP-метод | Идемпотентность | Наличие тела (Body) | | :--- | :--- | :--- | :--- | | Create | POST | Нет | Да | | Read | GET | Да | Нет | | Update | PUT / PATCH | Да / Нет | Да | | Delete | DELETE | Да | Редко |

    Идемпотентность — это критически важное понятие для автоматизатора. Если метод идемпотентен (как GET или PUT), вы можете вызвать его десять раз подряд и состояние сервера после первого и десятого вызова будет идентичным. Если же вы десять раз вызовете POST, вы создадите десять дублирующих записей. В тестах это означает, что после падения теста на этапе POST нам нужно вручную или программно очищать данные, иначе следующий запуск провалится из-за конфликта уникальных ID.

    Глубокое погружение в GET: получение данных и фильтрация

    Метод GET кажется самым простым, но именно здесь начинающие часто совершают ошибки при работе с динамическими параметрами. Основная задача GET — получить ресурс или коллекцию ресурсов.

    Работа с Query Parameters

    Часто нам нужно не просто получить список всех пользователей, а отфильтровать их по статусу или дате регистрации. В Playwright для этого используется объект params.

    Почему мы используем объект params, а не пишем строку /users?status=active&page=2?

  • Читаемость: Код становится чище.
  • Экранирование: Playwright автоматически обработает спецсимволы (пробелы, амперсанды) в значениях параметров.
  • Типизация: В TypeScript проще манипулировать объектом, если параметры генерируются динамически.
  • Нюансы кэширования и заголовков

    Серверы часто кэшируют GET-запросы. В автоматизации это может привести к «ложноположительным» результатам: тест проходит, потому что получает старые данные из кэша, хотя на сервере данные уже изменились. Чтобы избежать этого, можно добавлять в заголовки Cache-Control: no-cache или использовать динамический параметр, например _t: Date.now().

    Создание ресурсов через POST: работа с Payload

    Метод POST используется для создания новых сущностей. Главное отличие от GET — наличие тела запроса (Payload). В Playwright мы передаем данные через свойство data.

    Отправка JSON и автоматическая сериализация

    Playwright по умолчанию предполагает, что вы отправляете JSON, если передаете объект в поле data. Он автоматически устанавливает заголовок Content-Type: application/json.

    Проблема «грязных данных»

    Каждый запуск теста POST создает новую запись. Если ваш API не имеет тестовой песочницы, база данных быстро заполнится мусором. Стратегия решения:

  • Уникальность: Используйте динамические данные (например, библиотеку Faker, которую мы разберем позже) для имен и email.
  • Атомарность: Тест на создание должен возвращать ID созданного ресурса, чтобы последующий шаг или хук afterEach мог его удалить.
  • Обновление данных: PUT vs PATCH

    Многие путают эти два метода.

  • PUT — это полная замена ресурса. Вы должны отправить объект целиком. Если вы пропустите поле price, сервер может либо выдать ошибку, либо (что хуже) обнулить цену в базе.
  • PATCH — это частичное обновление. Вы отправляете только те поля, которые хотите изменить.
  • Реализация PUT-запроса

    При тестировании PUT важно убедиться, что данные не просто «приняты» сервером, а действительно обновились.

    Обработка мягкого удаления (Soft Delete)

    В современных системах данные редко удаляются физически. Чаще им присваивается флаг is_deleted: true. Если ваш API работает именно так, то после DELETE запрос GET может по-прежнему возвращать 200 OK, но с измененным телом. Это нужно учитывать при написании ассертов.

    Обработка сложных типов данных: FormData и параметры

    Иногда API ожидает данные не в формате JSON, а в виде application/x-www-form-urlencoded или multipart/form-data (например, при загрузке файлов или отправке простых форм).

    Playwright предоставляет для этого поле form:

    Если же вам нужно отправить файл вместе с метаданными, используется поле multipart:

    Типизация в TypeScript для CRUD-операций

    Чтобы ваши тесты были надежными, избегайте использования типа any для ответов API. Создавайте интерфейсы для каждой сущности. Это позволит IDE подсказывать вам доступные поля и предотвратит ошибки в названиях свойств (например, user.email вместо user.e_mail).

    Работа с заголовками на уровне запроса

    Хотя базовые заголовки (например, Authorization) часто выносятся в конфиг, иногда конкретный метод требует специфического заголовка. Например, X-Idempotency-Key для предотвращения дублей при POST-запросах или Accept-Language для проверки локализации.

    Граничные случаи и обработка ошибок

    Автоматизация — это не только проверка «счастливого пути» (Happy Path). Настоящая сила тестов проявляется при проверке того, как система реагирует на некорректные методы.

    Метод не разрешен (405 Method Not Allowed)

    Попробуйте отправить POST на эндпоинт, который предназначен только для чтения. Сервер должен вернуть 405. Это важная проверка безопасности и архитектурной чистоты API.

    Несоответствие типов данных

    Что произойдет, если в методе PUT вы передадите в поле price строку вместо числа?

  • Вернет ли сервер 400 Bad Request?
  • Попытается ли он привести тип (coercion)?
  • Или упадет с 500 Internal Server Error?
  • Автоматизация таких сценариев помогает разработчикам вовремя заметить отсутствие валидации на бэкенде.

    Для эффективной работы с методами в Playwright важно помнить: каждый вызов — это не просто строка кода, а взаимодействие с состоянием системы. Правильный выбор между PUT и PATCH, корректное использование Query-параметров в GET и обязательная верификация удаления в DELETE составляют фундамент стабильного тестового набора. По мере усложнения логики мы будем переходить от простых вызовов к архитектурным оберткам, но понимание механики HTTP-методов останется неизменным базисом.

    4. Валидация ответов: проверка статус-кодов и структуры тела JSON

    Валидация ответов: проверка статус-кодов и структуры тела JSON

    Почему тест, который просто получает ответ от сервера, нельзя считать завершенным? Представьте ситуацию: вы отправляете запрос на создание пользователя, сервер возвращает код 200 OK, но в теле ответа вместо данных нового аккаунта приходит пустой объект или сообщение об ошибке базы данных, «завернутое» в успешный статус-код. Без глубокой валидации такой тест пройдет успешно, пропустив критический баг. Качественный автотест API — это не просто вызов эндпоинта, а тщательная сверка ожиданий с реальностью на трех уровнях: метаданных (статусы), структуры (формат JSON) и содержания (конкретные значения).

    Анатомия проверки: от статуса к данным

    В Playwright работа с ответом строится вокруг объекта APIResponse. Когда мы выполняем await request.get(...), управление возвращается только после того, как сервер прислал заголовки и начал передачу тела. Однако само наличие объекта ответа не гарантирует, что бизнес-логика отработала верно.

    Процесс валидации в профессиональной автоматизации принято разделять на этапы, двигаясь от общего к частному. Это позволяет тесту упасть с понятной ошибкой на раннем этапе, не пытаясь парсить тело запроса, если сервер вернул ошибку авторизации или «пятисотку».

  • Проверка HTTP-статуса. Это первый эшелон обороны. Если мы ждем 201 Created, а получаем 403 Forbidden, дальнейшая проверка полей JSON бессмысленна.
  • Проверка заголовков (Headers). Важно убедиться, что сервер вернул правильный Content-Type: application/json, иначе попытка вызвать метод .json() у ответа приведет к исключению в коде теста.
  • Проверка структуры тела. Мы проверяем наличие обязательных ключей (например, id, token, createdAt), не всегда привязываясь к их конкретным значениям.
  • Проверка бизнес-данных. Сверка значений: совпадает ли имя созданного пользователя с тем, что мы отправляли в POST запросе.
  • Инструментарий Playwright и встроенные ассерты

    Playwright предоставляет встроенный метод expect(response).toBeOK(), который проверяет, находится ли статус-код в диапазоне . Однако в строгой автоматизации этого часто недостаточно. Нам нужно проверять конкретный код.

    Здесь ` — это ожидаемый результат для метода POST, создающего ресурс. Использование response.status() возвращает числовое значение, которое мы сравниваем с эталоном.

    Обработка JSON-данных

    Метод response.json() является асинхронным и возвращает объект, с которым TypeScript может работать как с типом any по умолчанию. Чтобы сохранить преимущества типизации, мы используем интерфейсы, внедренные в предыдущих модулях.

    Глубокая валидация структуры тела

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

    Проверка вложенных объектов и массивов

    Если API возвращает список объектов, нам важно убедиться не только в том, что пришел массив, но и в том, что каждый элемент этого массива соответствует схеме.

    Использование expect.any(Type) — мощный инструмент Playwright. Он позволяет игнорировать конкретное динамическое значение (например, id, который всегда разный), но жестко фиксировать тип данных. Если сервер вместо id: 10 пришлет id: "10", тест упадет, указав на несоответствие типов.

    Метод toMatchObject vs toEqual

    Разница между этими методами критична для стабильности тестов:

  • toEqual требует полного совпадения объектов. Если в ответе API появится новое поле, которое вы не описали в тесте, toEqual выдаст ошибку. Это делает тесты "хрупкими".
  • toMatchObject проверяет, что в ответе содержатся как минимум те поля, которые вы указали. Лишние поля игнорируются.
  • В большинстве случаев для интеграционных тестов API предпочтительнее toMatchObject, так как добавление новых полей в API обычно считается обратно совместимым изменением, которое не должно ломать существующие тесты.

    Нюансы работы с типами данных в TypeScript

    TypeScript помогает нам на этапе написания кода, но он исчезает во время выполнения (runtime). Это создает иллюзию безопасности. Если вы написали const data = await response.json() as User, вы просто "заставили" компилятор поверить вам. Если сервер пришлет не User, а что-то другое, ошибка возникнет только в момент обращения к полю, а не в момент присваивания типа.

    Для решения этой проблемы в профессиональной разработке применяются два подхода:

  • Runtime-валидация (через библиотеки вроде Zod или JSON-схемы, что будет рассмотрено в следующем модуле).
  • Защитное программирование в ассертах.
  • Рассмотрим пример, где мы проверяем необязательные поля (optional fields):

    Работа с заголовками и метаданными

    Иногда логика приложения завязана на заголовках ответа. Например, пагинация может передаваться в заголовках X-Total-Count, а время жизни токена — в Cache-Control.

    Важно помнить, что в HTTP заголовки нечувствительны к регистру, но Playwright при вызове response.headers() нормализует их, приводя ключи к нижнему регистру. Это упрощает проверку: вам не нужно гадать, придет Content-Type или content-type.

    Валидация негативных сценариев

    Тестирование API — это на 50% проверка того, как система обрабатывает ошибки. Мы должны убедиться, что при некорректных данных сервер возвращает не только правильный код ошибки (4xx или 5xx), но и информативное тело ответа.

    Здесь мы используем expect.stringContaining(). Это позволяет не привязываться к точной формулировке сообщения об ошибке, если она может незначительно меняться, но проверять наличие ключевого слова.

    Граничные случаи и распространенные проблемы

    Пустые ответы (204 No Content)

    При выполнении метода DELETE или успешном PATCH сервер часто возвращает статус 204. Попытка вызвать await response.json() для такого ответа приведет к ошибке парсинга, так как тела нет.

    Большие JSON-массивы

    Если API возвращает тысячи объектов, проверка каждого через
    toMatchObject в цикле может замедлить тесты. В таких случаях стоит проверять:
  • Общее количество элементов.
  • Случайный элемент из массива (Sampling).
  • Первый и последний элементы.
  • Динамические типы данных

    Иногда одно и то же поле может возвращать разные типы данных (например,
    null или string). В TypeScript и Playwright это обрабатывается через логические условия или специальные матчеры.

    Организация проверок: DRY и масштабируемость

    Когда тестов становится много, дублирование интерфейсов и базовых проверок в каждом файле превращается в проблему. Рекомендуется выносить общие интерфейсы в отдельные файлы (например, types/api.ts).

    Также полезно создавать кастомные функции-помощники для типичных проверок. Например, если каждый ваш успешный ответ должен содержать requestId, можно написать обертку:

    Это первый шаг к архитектуре, которую мы будем строить в конце курса. Подобные хелперы уменьшают количество шаблонного кода (boilerplate) и делают тесты более читаемыми.

    Сравнение подходов: Ручная проверка vs Автоматическая

    | Критерий | Ручная проверка полей | Использование toMatchObject | JSON-схемы (след. модуль) | | :--- | :--- | :--- | :--- | | Скорость написания | Низкая | Высокая | Средняя | | Точность | Высокая | Средняя | Очень высокая | | Поддержка | Сложная | Легкая | Средняя | | Читаемость | Плохая (много строк) | Отличная | Хорошая |

    Ручная проверка каждого поля через expect(body.name).toBe('Ivan') оправдана только для критически важных бизнес-данных. Для проверки того, что API в принципе работает корректно и отдает нужные поля, toMatchObject и expect.any()` являются золотым стандартом.

    Завершая работу с базовой валидацией, важно помнить: тест силен настолько, насколько строги его проверки. Проверка только статус-кода дает ложное чувство безопасности. Всегда стремитесь заглянуть внутрь JSON-пакета, проверяя не только наличие данных, но и их соответствие типам. Это превращает ваши тесты из простых "пингов" в мощный инструмент контроля качества контрактов между фронтендом и бэкендом.

    5. Продвинутая валидация данных с использованием JSON-схем

    Продвинутая валидация данных с использованием JSON-схем

    Представьте ситуацию: ваш тест успешно проверил статус-код 200 и даже убедился, что в поле email пришла строка. Однако на фронтенде приложение падает, потому что вместо ожидаемого массива roles: ["admin", "editor"] сервер прислал строку roles: "admin", или в поле price вместо числа пришло строковое значение "100.00". Обычные проверки через expect часто пропускают такие нюансы, особенно если структура ответа сложная и содержит десятки вложенных полей. Здесь на сцену выходит валидация по JSON-схеме — контрактный подход, который гарантирует, что сервер соблюдает договоренности о формате данных.

    Почему интерфейсов TypeScript недостаточно для тестов

    Начинающие автоматизаторы часто полагают, что использования интерфейсов TypeScript (interface) достаточно для проверки ответов. Это опасное заблуждение. TypeScript выполняет проверку типов только на этапе компиляции (транспиляции в JavaScript). Как только ваш код запускается в среде Node.js, вся информация о типах исчезает.

    Если вы напишете:

    TypeScript «поверит» вам, что body соответствует интерфейсу User. Но если сервер пришлет { "id": "1", "username": "admin" }, код выполнится без ошибок, а typeof body.id вернет string. В реальном тесте это может привести к ложноположительному результату: тест пройдет, хотя данные некорректны. Валидация JSON-схем работает в runtime (во время выполнения), проверяя реальные данные, пришедшие по сети, на соответствие жестко заданному эталону.

    Стандарт JSON Schema и библиотека Ajv

    JSON Schema — это декларативный язык описания структуры JSON-документа. Он позволяет описать не только типы полей, но и ограничения: минимальную длину строки, формат email, допустимые значения в перечислениях и обязательность полей.

    Для работы с этими схемами в экосистеме Node.js стандартом де-факто является библиотека Ajv (Another JSON Schema Validator). Она отличается высокой скоростью работы и поддержкой последних черновиков стандарта (Draft 7, 2019-09, 2020-12).

    Для начала работы необходимо установить библиотеку и плагин для работы с форматами (например, датами и email):

    Создание первой схемы

    Схема сама по себе является JSON-объектом. Рассмотрим пример для эндпоинта /posts/1.

    Разберем ключевые ключевые слова:

  • type: определяет базовый тип (object, array, string, number, integer, boolean, null).
  • properties: словарь, где ключи — это названия полей, а значения — схемы для этих полей.
  • required: массив строк с именами обязательных полей. Если сервер не пришлет хотя бы одно из них, валидация провалится.
  • additionalProperties: false: критически важная настройка. Она запрещает серверу присылать любые поля, не описанные в properties. Это позволяет ловить «мусорные» данные или несанкционированные изменения в API.
  • Интеграция Ajv в тесты Playwright

    Чтобы использовать Ajv внутри тестов Playwright, нам нужно создать экземпляр валидатора, скомпилировать схему и проверить данные.

    Использование as const в TypeScript помогает сохранить литеральные значения типов, что полезно для некоторых инструментов статического анализа.

    Переиспользование схем через id: "common", definitions: { address: { type: "object", properties: { city: { type: "string" }, zip: { type: "string", pattern: "^[0-9]{5}ref: "common#/definitions/address" }, workAddress: { ".
  • type: просто проверка типа, если значение непредсказуемо.
  • Если поле может быть null (например, дата удаления deletedAt), в JSON Schema Draft 7 это описывается так:

    Глубокая валидация vs Поверхностная

    Стоит ли проверять каждое поле в каждом тесте? Существует два подхода:

  • Strict Contract Testing: Вы проверяете всё, включая additionalProperties: false. Это гарантирует полную стабильность, но делает тесты хрупкими. Любое добавление нового поля в API (даже не ломающее логику) заставит тесты упасть.
  • Partial Validation: Вы проверяете только те поля, которые критичны для текущего бизнес-сценария.
  • В автоматизации API-тестирования рекомендуется придерживаться «золотой середины»: иметь один «Smoke-тест» на каждый эндпоинт с полной валидацией схемы, а в остальных функциональных тестах проверять только конкретные значения данных, важные для логики теста.

    Отладка ошибок валидации

    Когда Ajv находит несоответствие, объект validate.errors содержит массив ошибок. Каждая ошибка включает:

  • instancePath: путь к полю в JSON (например, /address/geo/lat).
  • message: описание проблемы (например, must be string).
  • params: дополнительные данные (например, какое именно поле отсутствует).
  • Для удобства чтения в логах Playwright ошибки стоит форматировать:

    Такой подход гарантирует, что каждая схема будет скомпилирована ровно один раз за весь прогон тестов.

    Замыкание логики валидации

    Внедрение JSON-схем переводит ваше тестирование API с уровня «проверим пару полей» на уровень гарантированного соблюдения контракта. Это фундамент, на котором строится доверие между командами бэкенда и фронтенда (или потребителями вашего API). В сочетании с мощными инструментами Playwright, такими как APIRequestContext`, и строгой типизацией TypeScript, Ajv или Zod превращают тесты в надежный инструмент контроля качества, способный обнаруживать тончайшие регрессии в структуре данных, которые невозможно поймать вручную или простыми проверками на равенство.

    6. Автоматизация процессов авторизации и эффективное управление токенами доступа

    Автоматизация процессов авторизации и эффективное управление токенами доступа

    Представьте, что в вашем тестовом наборе пятьсот сценариев, и каждый из них требует предварительной авторизации. Если выполнять вход в систему перед каждым тестом классическим способом (отправка логина и пароля), общее время прогона увеличится на десятки минут. Более того, при возникновении проблем на стороне сервиса авторизации «упадут» абсолютно все тесты, даже те, что проверяют логику корзины или профиля. В автоматизации API работа с доступом — это не просто отправка токена, а стратегия минимизации лишних запросов и обеспечения стабильности среды.

    Механизмы контроля доступа в современных API

    Прежде чем переходить к коду, необходимо разграничить два фундаментальных понятия, которые часто путают: аутентификацию и авторизацию. Аутентификация — это процесс проверки личности пользователя (кто вы?), а авторизация — проверка прав доступа к конкретному ресурсу (что вам разрешено делать?).

    В большинстве современных систем используется протокол OAuth 2.0 или OpenID Connect, где результатом успешного входа является токен. Существует три основных способа передачи данных о сессии:

  • Bearer Token (JWT): Самый распространенный метод. Токен передается в заголовке Authorization: Bearer <token>. Сервер проверяет подпись токена и извлекает из него данные о пользователе.
  • Cookie-based Session: Сервер устанавливает куки в браузере клиента. При API-тестировании нам приходится вручную извлекать заголовок Set-Cookie и передавать его в последующих запросах как Cookie.
  • API Keys: Статические ключи, которые редко меняются и передаются либо в заголовках (например, x-api-key), либо в параметрах запроса.
  • Для автоматизатора наиболее критичным является управление жизненным циклом JWT (JSON Web Token). Он имеет ограниченный срок действия (), и если тест длится дольше, чем живет токен, сценарий завершится ошибкой.

    Стратегия глобальной авторизации в Playwright

    Playwright предоставляет мощный механизм хранения состояния (Storage State), который изначально был разработан для браузерных тестов, но идеально подходит и для API. Идея заключается в том, чтобы один раз выполнить вход, сохранить полученные куки или токены в файл, а затем подставлять этот файл во все последующие тесты.

    В контексте API-тестирования мы можем реализовать это через специальный «Setup-тест», который выполняется перед всеми остальными.

    Реализация через глобальный setup

    В файле playwright.config.ts можно определить проект, который будет отвечать только за авторизацию. Все остальные проекты будут зависеть от него.

    Теперь создадим сам файл авторизации auth.setup.ts. Его задача — отправить POST-запрос с учетными данными, получить токен и сохранить состояние.

    Однако здесь есть нюанс. Метод request.storageState() отлично сохраняет куки и localStorage, но если ваш API использует заголовок Authorization: Bearer, Playwright автоматически не подставит его из сохраненного JSON-файла в каждый запрос APIRequestContext. Нам потребуется кастомная логика.

    Работа с JWT и динамическая подстановка заголовков

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

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

  • Header: Алгоритм шифрования.
  • Payload: Данные (id пользователя, роли, время истечения).
  • Signature: Проверка целостности.
  • Для тестов важно уметь декодировать Payload без проверки подписи, чтобы заранее узнать, не истек ли токен. Для этого в TypeScript можно использовать библиотеку jwt-decode.

    Автоматизация Refresh Token

    Многие API используют пару accessToken (короткоживущий) и refreshToken (долгоживущий). В тестах это создает проблему: если accessToken протух в середине прогона, тест упадет.

    Правильная архитектура обработки токенов в тестах должна выглядеть так:

  • Проверка наличия токена в кэше (файле или переменной).
  • Если токена нет или он истек — запрос на обновление через refreshToken.
  • Если refreshToken тоже истек — полная авторизация по логину/паролю.
  • Это реализуется через создание обертки над request. В Playwright это удобнее всего сделать через fixtures, которые мы подробно разберем в следующей главе, но сейчас важно понять принцип: мы не вызываем request.post напрямую в тестах, если нам нужна гарантированная авторизация.

    Управление несколькими уровнями доступа

    В реальных проектах тесты должны запускаться от лиц с разными ролями: Admin, Editor, Viewer. Хранить один user.json недостаточно.

    Стратегия управления ролями подразумевает создание нескольких файлов состояния. В конфигурации Playwright это выглядит как матрица проектов:

    Внутри auth.setup.ts вы просто запускаете цикл или несколько setup блоков для каждой учетной записи. Это позволяет избежать «загрязнения» тестов логикой переключения пользователей. Тест просто «знает», что он запущен в контексте администратора.

    Безопасность и переменные окружения

    Никогда не храните токены или пароли в коде или в репозитории. Даже если это тестовый стенд. Используйте файл .env и библиотеку dotenv.

    Пример безопасного получения токена:

    В CI/CD системах (GitHub Actions, GitLab CI) эти переменные пробрасываются через Secrets. Это критически важно, так как логи тестов часто бывают публичными или доступными широкому кругу лиц. Если токен попадет в лог, злоумышленник сможет использовать его для доступа к вашему тестовому (а иногда и пре-продакшн) окружению.

    Обработка ошибок авторизации (401 и 403)

    Тестирование авторизации — это не только успешные входы. Хороший тестовый набор включает проверку негативных сценариев.

    Кейс 1: Истекший токен (401 Unauthorized)

    Для проверки этого сценария вам не нужно ждать реального истечения токена. Вы можете:
  • Использовать «протухший» статический токен, зашитый в моки.
  • Если сервер позволяет, передать в запросе на генерацию токена параметр expiresIn: '1s'.
  • Кейс 2: Недостаточно прав (403 Forbidden)

    Это проверка RBAC (Role-Based Access Control). Мы должны убедиться, что пользователь с ролью Viewer не может удалить ресурс методом DELETE.

    Оптимизация: авторизация «на лету» vs Setup

    Хотя глобальный setup удобен, у него есть минус: он запускается всегда. Если вы хотите запустить один маленький тест, который вообще не требует авторизации (например, проверку доступности API), вам все равно придется ждать выполнения setup-проекта.

    Альтернативный подход — Lazy Authentication. Токен запрашивается только тогда, когда он впервые потребовался в тестах.

    Этот метод экономит время при локальной разработке и отладке отдельных тестов. Однако в CI/CD глобальный setup предпочтительнее, так как он обеспечивает изоляцию и предсказуемость.

    Нюансы работы с куками в API-запросах

    Если ваш API использует HttpOnly куки, вы не сможете прочитать их через JavaScript в браузере, но Playwright в API-контексте видит их в заголовках ответа.

    При получении ответа с куками:

  • Извлеките заголовок set-cookie.
  • Сохраните его.
  • При следующем запросе передайте в объекте headers поле Cookie.
  • Важно помнить, что set-cookie может содержать массив кук. Playwright объединяет их в одну строку, разделенную запятыми или точкой с запятой, что иногда требует дополнительного парсинга перед повторным использованием.

    Использование сессий для ускорения тестов

    В сложных корпоративных системах процесс авторизации может включать MFA (многофакторную аутентификацию) или редиректы через SSO (Single Sign-On). В таких случаях автоматизация «чистого» API-запроса на логин может быть невозможна.

    Решение:

  • Использовать Playwright Browser для прохождения SSO один раз.
  • Извлечь токены из контекста браузера.
  • Передать эти токены в APIRequestContext.
  • Это гибридный подход, который позволяет обходить сложные механизмы защиты, сохраняя при этом скорость API-тестов для основной бизнес-логики.

    Проверка безопасности токенов

    Автоматизация API — это отличный шанс проверить безопасность самих токенов. Включите в ваш фреймворк тесты на:

  • Алгоритм none: Попытка отправить JWT с заголовком {"alg": "none"}. Сервер должен отклонить такой запрос.
  • Манипуляция Payload: Изменение userId в теле токена без переподписи. Сервер должен вернуть 401.
  • Длинные токены: Проверка того, как сервер обрабатывает аномально большие заголовки (защита от Buffer Overflow или DoS).
  • Управление доступом — это фундамент, на котором строится доверие к результатам тестов. Если ваша система авторизации во фреймворке работает нестабильно, вы будете тратить время на разбор «ложноположительных» падений, связанных с протухшими сессиями, вместо поиска реальных багов в бизнес-логике.

    7. Использование фикстур и расширенная конфигурация тестовой среды

    Использование фикстур и расширенная конфигурация тестовой среды

    Представьте, что вы пишете сотню тестов для интернет-магазина. В каждом тесте вам нужно создать уникального пользователя, авторизоваться, получить токен и в конце — удалить созданные данные, чтобы не засорять базу. Если вы будете прописывать эти шаги в каждом файле, ваш код превратится в трудночитаемый лабиринт из повторяющихся beforeEach и afterEach. В Playwright существует элегантное решение этой проблемы — фикстуры. Они позволяют не просто подготовить окружение, а превратить зависимости теста в инъекции, которые работают «под капотом», делая сам тест чистым и сфокусированным на бизнес-логике.

    Механика фикстур: от изоляции к переиспользованию

    Фикстура в Playwright — это инкапсулированная среда или объект, который автоматически подготавливается перед запуском теста и, при необходимости, уничтожается после него. Главное отличие фикстур Playwright от классических хуков before/after в Jest или Mocha заключается в их ленивой инициализации и иерархичности.

    Когда вы передаете фикстуру в аргументы теста, Playwright анализирует дерево зависимостей. Если тест не запрашивает конкретную фикстуру, она не будет создана, что экономит ресурсы. Более того, фикстуры могут зависеть друг от друга, создавая цепочки подготовки данных.

    Анатомия кастомной фикстуры

    Чтобы создать свою фикстуру, необходимо расширить базовый тестовый объект. Рассмотрим пример, где нам нужен преднастроенный клиент для работы с API, который уже содержит необходимые заголовки и базовый URL, но при этом изолирован от глобального конфига для специфических задач.

    Ключевое слово use() здесь работает как точка переключения. Весь код до use() — это фаза Setup. Код после use() — фаза Teardown. Это избавляет от необходимости писать симметричные afterEach блоки, так как логика создания и удаления ресурса находится в одном месте.

    Глобальная конфигурация и динамические окружения

    Playwright позволяет гибко управлять параметрами запуска через файл playwright.config.ts. Однако в реальных проектах одной конфигурации недостаточно. Нам часто нужно переключаться между dev, staging и production средами.

    Управление проектами (Projects)

    Секция projects в конфиге — это не только способ запустить тесты в разных браузерах. Для API-тестирования это мощный инструмент разделения логики. Мы можем создать проекты для разных уровней доступа или разных микросервисов.

    Использование process.env в связке с проектами позволяет динамически менять baseURL. Если в вашей компании используется несколько стендов, вы можете запускать тесты командой: BASE_URL=https://api.prod.com npx playwright test --project=regression

    Глубокая настройка HTTP-клиента

    В API-тестах критично управлять таймаутами и проверками SSL. В playwright.config.ts параметр ignoreHTTPSErrors: true спасает при работе с самоподписанными сертификатами на внутренних стендах. Также стоит обратить внимание на maxRetries. Для API-тестов количество ретраев (повторных запусков при падении) обычно ставят минимальным ( или ), так как нестабильность API (flakiness) чаще указывает на реальную проблему с производительностью или блокировками в БД, чем на проблемы рендеринга в браузере.

    Создание фикстур для генерации данных

    Одной из самых частых задач является создание сущностей «на лету». Использование статических данных (например, пользователя с фиксированным ID) ведет к конфликтам при параллельном запуске тестов. Здесь на помощь приходят фикстуры в связке с библиотекой Faker.

    Кейс: Изолированный пользователь для каждого теста

    Представьте, что тест должен создать статью. Для этого нужен автор. Если мы создадим автора в beforeAll, то при параллельном запуске 10 тестов все они будут использовать одного автора, что может привести к ошибкам уникальности или неожиданным результатам при удалении.

    Это позволяет писать тесты максимально лаконично: test('delete user', async ({ adminRequest }) => { ... }) — здесь нам не нужно беспокоиться об авторизации, она уже «встроена» в объект запроса.

    Масштабирование: Worker-scoped vs Test-scoped фикстуры

    По умолчанию фикстуры создаются для каждого теста заново (scope: 'test'). Это гарантирует идеальную изоляцию, но может замедлять тесты, если подготовка данных занимает много времени (например, миграция базы или тяжелый запрос).

    Playwright позволяет создавать фикстуры на уровне воркера (scope: 'worker'). Такая фикстура создается один раз для процесса (воркера) и переиспользуется всеми тестами, которые в нем запущены.

    > Важно: воркер-фикстуры не могут зависеть от тест-фикстур, так как у них более длительный жизненный цикл.

    Пример использования воркер-фикстуры для создания глобального кэша или подключения к БД:

    Если вы запускаете тесты в 4 потока, будет создано всего 4 подключения к БД, а не по одному на каждый из 100 тестов. Это критически важно для производительности инфраструктуры.

    Обработка граничных случаев в конфигурации

    При расширенной конфигурации часто возникают ситуации, когда тесты должны вести себя по-разному в зависимости от того, запущены они локально или в CI (Continuous Integration).

  • Таймауты: В CI серверы обычно медленнее. Используйте process.env.CI для динамической настройки.
  • timeout: process.env.CI ? 60000 : 30000
  • Логирование: На локальной машине нам важны консольные логи, в CI — артефакты (отчеты, трейсы).
  • reporter: process.env.CI ? [['github'], ['html']] : 'list'
  • Параллелизм: API-тесты часто упираются в пропускную способность базы данных. Параметр fullyParallel: true ускоряет выполнение, но если ваши тесты изменяют одни и те же данные, это приведет к конфликтам. В таких случаях лучше использовать workers: 1 для определенных папок или тегов.
  • Тегирование тестов

    Playwright поддерживает теги прямо в названии или через объект конфигурации. Это позволяет гибко настраивать запуск: test('check profile @fast @smoke', async ({ request }) => { ... }) Запуск только быстрых тестов: npx playwright test --grep @fast. Исключение медленных: npx playwright test --grep-invert @slow.

    Организация кода: выносим фикстуры в отдельные файлы

    Когда фикстур становится много, файл test.ts (или fixtures.ts) становится перегруженным. Рекомендуется группировать фикстуры по смыслу:

  • auth.fixtures.ts — всё, что связано с токенами и сессиями.
  • db.fixtures.ts — работа с базой данных и очисткой.
  • api.fixtures.ts — кастомные клиенты и обертки над запросами.
  • Затем вы можете объединить их в одном месте, создав единую точку входа для ваших тестов. Это подготавливает почву для перехода к архитектурным паттернам, таким как Контроллеры, где фикстуры будут возвращать уже готовые объекты бизнес-логики.

    Использование фикстур — это переход от линейного написания скриптов к созданию тестовой платформы. Вместо того чтобы каждый раз объяснять программе, «как именно» получить доступ или создать данные, вы описываете «что» вам нужно для теста, делегируя реализацию механизму фикстур. Это снижает когнитивную нагрузку на разработчика тестов и делает фреймворк устойчивым к изменениям в API. Если завтра изменится способ авторизации, вы поправите код в одной фикстуре, и сотни тестов продолжат работать без единого изменения в их теле.

    8. Применение архитектурного паттерна Контроллер для структурирования API тестов

    Применение архитектурного паттерна Контроллер для структурирования API тестов

    Почему в крупных проектах тесты превращаются в «спагетти-код», который боятся трогать даже авторы? Представьте ситуацию: у вас 200 тестов, и в каждом из них жестко прописан путь к эндпоинту /api/v1/orders. Внезапно разработчики меняют версию API на v2. Вам придется вручную исправлять 200 файлов. Проблема здесь не в Playwright, а в отсутствии архитектурного слоя, который отделяет логику тестов от специфики реализации API. Паттерн «Контроллер» — это именно то решение, которое превращает хаотичные запросы в стройную, поддерживаемую систему.

    От процедурного подхода к объектно-ориентированному

    До этого момента мы писали тесты, используя request напрямую внутри тела теста. Такой подход называется процедурным. Он хорош для обучения или написания быстрых скриптов, но он нарушает принцип единственной ответственности (Single Responsibility Principle). Тест вынужден знать слишком много: точный URL, структуру заголовков, способы сериализации данных и логику обработки ошибок.

    Паттерн Контроллер (в контексте тестирования API его часто называют API-клиентом или сервисным слоем) предлагает создать объект-посредник. Этот объект инкапсулирует в себе все знания о конкретном ресурсе (например, пользователях, заказах или корзине). Тест же просто вызывает методы этого объекта, не заботясь о том, как именно отправляется запрос.

    Зачем это нужно на практике

  • Централизация изменений: Если путь к ресурсу меняется, вы правите его в одном месте — в классе контроллера.
  • Типизация «из коробки»: Контроллеры позволяют один раз описать интерфейсы ответов и использовать их во всех тестах, получая подсказки от IDE.
  • Повторное использование: Логика подготовки данных (например, создание пользователя перед тестом) выносится в метод контроллера и вызывается одной строкой.
  • Читаемость: Тест начинает выглядеть как описание бизнес-логики: userController.create(userData), а не как набор технических параметров HTTP.
  • Анатомия базового контроллера

    Прежде чем создавать контроллеры для конкретных сущностей, нам нужен базовый класс. Он будет содержать общую логику: работу с APIRequestContext, логирование и, возможно, базовые проверки.

    В TypeScript это реализуется через абстрактный класс.

    Здесь protected позволяет дочерним классам (нашим будущим контроллерам) иметь доступ к объекту request, но скрывает его от внешнего кода. Это важный аспект инкапсуляции: мы не хотим, чтобы тест случайно полез «под капот» контроллера и начал менять настройки запроса напрямую.

    Реализация контроллера сущности

    Возьмем для примера ресурс «Пользователи». Нам нужно реализовать стандартные операции CRUD. Вместо того чтобы каждый раз прописывать this.request.post('/users', { data: ... }), мы создаем метод create.

    Проектирование методов контроллера

    При проектировании методов важно решить, что именно должен возвращать контроллер. Есть два основных подхода:

  • Возвращать APIResponse: Тест сам проверяет статус-коды и парсит JSON. Это дает гибкость.
  • Возвращать типизированные данные: Контроллер сам проверяет, что запрос успешен, и возвращает уже готовый объект. Это делает тесты чище, но сложнее тестировать негативные сценарии.
  • Для большинства фреймворков оптимален первый вариант или их комбинация. Рассмотрим реализацию UserController:

    Преимущества использования моделей

    Обратите внимание на использование CreateUserPayload и User. В архитектуре контроллеров мы активно используем интерфейсы TypeScript для описания контрактов API. Это предотвращает ошибки передачи неверных полей еще на этапе написания кода. Если в CreateUserPayload поле email является обязательным, компилятор не даст вам запустить тест, где это поле пропущено.

    Интеграция контроллеров в фикстуры Playwright

    Просто создать классы недостаточно. Если в каждом тесте мы будем писать const userController = new UserController(request), мы породим много дублирующего кода (Boilerplate). Правильный путь — внедрить контроллеры в фикстуры Playwright.

    Это позволяет тесту получать готовый экземпляр контроллера автоматически.

    Теперь ваш тест выглядит максимально лаконично:

    Обработка граничных случаев и расширенная логика

    Контроллеры — это не просто прокси для методов get и post. В них можно и нужно зашивать логику, специфичную для вашего API.

    Динамические заголовки и контекст

    Иногда определенные эндпоинты требуют специфических заголовков, например, X-Request-ID для трассировки или Content-Type: multipart/form-data для загрузки файлов. Вместо того чтобы заставлять тест знать об этих тонкостях, контроллер может добавлять их автоматически.

    Синхронизация состояний

    В сложных системах создание ресурса может быть асинхронным (сервер возвращает 202 Accepted, и ресурс создается через пару секунд). Контроллер может содержать логику ожидания (polling), чтобы тест не упал, пытаясь сразу запросить еще не созданный объект.

    Использование таких «умных» методов в контроллере избавляет тесты от хрупких wait и делает их более стабильными к задержкам сети или базы данных.

    Валидация внутри контроллера vs Валидация в тесте

    Существует два подхода к проверке ответов при использовании контроллеров.

    Подход А: Тест-ориентированный. Контроллер возвращает сырой APIResponse. Тест делает все проверки. Плюсы: Максимальная гибкость, легко тестировать ошибки (400, 401, 500). Минусы: Дублирование кода проверок в разных тестах.

    Подход Б: Контроллер-валидатор. Контроллер сам проверяет успешность (например, через expect(response).toBeOK()) и возвращает данные. Плюсы: Тесты становятся очень короткими. Минусы: Трудно проверить негативные сценарии, так как контроллер «падает» на ошибке раньше, чем тест успеет ее обработать.

    Рекомендуемый компромисс: Создавать в контроллере базовые методы, возвращающие APIResponse, и «высокоуровневые» методы для подготовки данных. Например, метод createPredefinedUser() может сам вызвать createUser, проверить статус 201 и вернуть ID нового пользователя. Это идеально подходит для использования в beforeEach.

    Организация структуры папок

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

    * src/api/controllers/ — классы контроллеров (BaseController.ts, UserController.ts). * src/api/models/ — интерфейсы TypeScript для запросов и ответов (User.ts, Auth.ts). * src/fixtures/ — расширение test из Playwright, где инициализируются контроллеры. * tests/ — сами файлы тестов, использующие фикстуры.

    Такое разделение позволяет команде работать параллельно: один человек может обновлять модели под новую версию API, другой — писать тесты, используя уже готовые методы контроллеров.

    Работа с вложенными ресурсами

    Часто API имеет иерархическую структуру, например: /users/{userId}/orders/{orderId}. Как это отразить в контроллерах?

    Есть два пути:

  • Плоский список: Все методы, связанные с заказами, живут в OrderController. Метод получения заказа принимает два параметра: userId и orderId.
  • Вложенные контроллеры: UserController может иметь метод или свойство, возвращающее экземпляр UserOrderController, привязанный к конкретному userId.
  • Для большинства задач автоматизации первый путь (плоский список) оказывается проще в поддержке. Лишняя вложенность объектов в тестах часто только запутывает.

    Типизация и Generic-методы в базовом контроллере

    Чтобы еще больше сократить количество кода, в BaseController можно вынести типизированные обертки над стандартными методами Playwright. Это позволит автоматически парсить JSON и применять к нему интерфейс.

    ``typescript protected async getAs<T>(url: string): Promise<T> { const response = await this.request.get(url); if (!response.ok()) { throw new Error(Request failed with status {this.endpoint}/${id});

    Однако будьте осторожны: такая абстракция скрывает объект APIResponse. Если вам нужно проверить заголовки ответа или время отклика, такие методы вам не помогут. Используйте их только для вспомогательных задач подготовки данных.

    Контроллеры и безопасность

    В предыдущих модулях мы разбирали авторизацию. Контроллер — идеальное место для управления токенами. Если ваше приложение использует разные типы токенов для разных сервисов, контроллер может сам решать, какой токен подставить в заголовок Authorization.

    Например, AdminController может автоматически брать токен администратора из переменных окружения или файла состояния, в то время как PublicController будет отправлять запросы без заголовков. Это избавляет автора теста от необходимости помнить, какой уровень доступа нужен для конкретного эндпоинта.

    Влияние на отчетность и отладку

    Использование контроллеров значительно упрощает чтение отчетов (например, Allure или стандартного HTML-репорта Playwright). Когда тест падает, в стектрейсе вы видите не анонимный вызов request.post, а осмысленный метод UserController.createUser. Это сразу дает контекст: на каком этапе и с какой сущностью возникла проблема.

    Кроме того, в базовый контроллер можно встроить кастомное логирование. Например, выводить в консоль (или прикреплять к отчету) CURL-команду для каждого запроса, который прошел через контроллер. Это бесценно для разработчиков, которым вы будете приносить баги: они смогут воспроизвести проблему одной командой в терминале.

    Переход на паттерн в существующем проекте

    Если у вас уже есть массив тестов, написанных без контроллеров, не пытайтесь переписать всё сразу. Начните с создания контроллера для самой часто используемой сущности.

  • Создайте BaseController.
  • Создайте первый контроллер и реализуйте в нем один метод (например, GET).
  • Замените прямые вызовы request.get в паре тестов на вызов метода контроллера.
  • Убедитесь, что тесты проходят и стали читаемее.
  • Постепенно расширяйте библиотеку контроллеров по мере написания новых тестов или рефакторинга старых.
  • Паттерн Контроллер — это фундамент профессиональной автоматизации. Он превращает набор скриптов в программный продукт, который легко масштабировать. В следующей главе мы сделаем еще один шаг к совершенству и разберем паттерн «Фасад», который позволит объединять действия нескольких контроллеров в сложные бизнес-сценарии.

    9. Паттерн Фасад и финальная организация структуры проекта

    Паттерн Фасад и финальная организация структуры проекта

    Когда количество тестов в проекте переваливает за сотню, а бизнес-логика API становится сложнее, чем простое создание одного ресурса, мы сталкиваемся с проблемой «оркестрации». Представьте сценарий: чтобы протестировать покупку товара, вам нужно авторизоваться, создать профиль пользователя, пополнить его баланс, добавить товар в корзину и только потом вызвать метод оформления заказа. Если писать этот код в каждом тесте, используя отдельные контроллеры, тест превратится в нагромождение технических вызовов, за которыми потеряется суть проверки.

    Проблема избыточной детализации в тестах

    На предыдущих этапах мы внедрили паттерн Контроллер. Это позволило нам изолировать работу с конкретными эндпоинтами (например, /users или /orders). Однако тесты всё ещё остаются перегруженными. Рассмотрим типичную ситуацию:

    Здесь тест знает слишком много: он знает, что сначала нужно пополнить баланс, потом добавить товар, и какие именно контроллеры для этого нужны. Если завтра процесс покупки изменится (например, добавится шаг подтверждения по SMS), вам придется обновлять десятки тестов. Именно здесь на помощь приходит паттерн Фасад.

    Концепция паттерна Фасад в автоматизации

    Паттерн Фасад предоставляет унифицированный интерфейс к набору интерфейсов в подсистеме. В контексте тестирования API Фасад — это высокоуровневый класс, который объединяет несколько контроллеров для выполнения комплексных бизнес-цепочек.

    Если Контроллер отвечает за вопрос «Как отправить запрос к сущности?», то Фасад отвечает на вопрос «Как выполнить бизнес-задачу?».

    Основные отличия Контроллера от Фасада

    | Характеристика | Контроллер (Controller) | Фасад (Facade) | | :--- | :--- | :--- | | Уровень абстракции | Низкий (технический) | Высокий (бизнес-логика) | | Связь с API | 1 контроллер 1 ресурс/микросервис | 1 фасад 1 пользовательский сценарий | | Зависимости | Зависит от APIRequestContext | Зависит от других контроллеров | | Цель | Инкапсуляция HTTP-методов и эндпоинтов | Инкапсуляция последовательности действий | | Возвращаемое значение | Обычно APIResponse или модель данных | Обычно готовый объект результата сценария |

    Техническая реализация Фасада на TypeScript

    Для реализации Фасада нам необходимо передать в него экземпляры контроллеров. Мы можем сделать это через конструктор. Важно, чтобы Фасад не дублировал логику контроллеров, а лишь вызывал их методы в нужном порядке.

    Создание класса APIFacade

    Допустим, у нас есть интернет-магазин. Создадим ShopFacade, который будет скрывать сложность подготовки данных.

    Теперь наш тест превращается в декларативное описание того, что мы хотим получить, а не как это технически реализовано:

    Интеграция Фасада в фикстуры Playwright

    Чтобы Фасад был доступен в тестах так же удобно, как и контроллеры, его нужно добавить в файл с фикстурами. Поскольку Фасад зависит от контроллеров, Playwright автоматически разрешит эти зависимости благодаря механизму внедрения (Dependency Injection).

    Благодаря «ленивой инициализации» Playwright, если тест использует только shopFacade, контроллеры будут созданы автоматически, так как они указаны в аргументах фикстуры фасада.

    Финальная структура проекта (Project Layout)

    Когда мы внедрили контроллеры, фасады, модели данных (интерфейсы) и фикстуры, проект должен иметь четкую иерархию. Хаотичное расположение файлов ведет к дублированию кода и трудностям при онбординге новых участников команды.

    Рекомендуемая структура промышленного уровня для Playwright API Framework:

    Назначение директорий

  • lib/controllers/: Здесь живут «рабочие лошадки». Каждый класс соответствует логическому разделу API. Если у вас микросервисная архитектура, контроллеры могут группироваться по сервисам.
  • lib/facades/: Слой «умной» логики. Если вы видите, что в трех разных тестах повторяется одна и та же последовательность из 5 вызовов контроллеров — это кандидат на вынос в Фасад.
  • lib/models/: Здесь мы храним контракты. Важно разделять Request модели и Response модели. Например, CreateUserRequest может не содержать поля id, а UserResponse — обязательно.
  • tests/: В этой папке не должно быть никакой логики формирования запросов. Только вызов методов контроллеров/фасадов и проверки (expect).
  • Применение принципов SOLID в архитектуре фасадов

    При создании фасадов легко совершить ошибку и превратить их в «Божественные объекты» (God Objects), которые знают обо всём в системе. Чтобы этого избежать, следуйте принципам:

    * Single Responsibility (Принцип единственной ответственности): Не создавайте один BigFacade. Разделите их по смыслу: BillingFacade для денег, InventoryFacade для склада, OnboardingFacade для регистрации и настройки профиля. * Dependency Inversion (Инверсия зависимостей): Фасады должны зависеть от абстракций или стабильных контроллеров. В TypeScript мы используем внедрение зависимостей через фикстуры, что позволяет легко подменять контроллеры (например, на моки), если это потребуется.

    Работа с состоянием и данными в Фасадах

    Одной из самых сложных задач в автоматизации API является управление состоянием. Фасад может брать на себя задачу очистки данных (Teardown).

    > Если Фасад создает сущности, он должен предоставлять механизм для их удаления, чтобы не засорять базу данных. > > Clean Code in Automation

    Пример метода с автоматической регистрацией созданных сущностей для удаления:

    Однако в Playwright более элегантным способом будет использование фикстур с автоматическим тирдауном, как мы разбирали в предыдущем модуле. Фасад в этом случае остается «чистым» от состояния, а за удаление отвечает фикстура, которая вызовет метод контроллера после use().

    Граничные случаи и антипаттерны

    Антипаттерн: Фасад-прослойка. Если метод фасада просто вызывает один метод контроллера без какой-либо дополнительной логики, такой метод бесполезен. ❌ Плохо: async getUser(id) { return this.userController.get(id); } ✅ Хорошо: Вызывать контроллер напрямую в тесте, если не требуется сложная цепочка действий.

    Антипаттерн: Логика проверок внутри Фасада. Фасад не должен содержать expect. Его задача — выполнить действие и вернуть результат. Если вы добавите проверки внутрь фасада, вы сделаете его менее гибким: вы не сможете использовать его в негативных тестах, где ожидается ошибка. ❌ Плохо: if (response.status !== 200) throw new Error(...) внутри фасада. ✅ Хорошо: Вернуть объект ответа или данные, и позволить тесту решить, корректны ли они.

    Масштабирование на несколько сред (Environments)

    В финальной архитектуре важно учитывать, что тесты будут запускаться на dev, staging и, возможно, production. Все URL и секреты должны быть вынесены из кода контроллеров и фасадов.

    Используйте playwright.config.ts для управления конфигурациями:

    Внутри контроллеров всегда используйте относительные пути: await this.request.post('/v1/orders', ...). Это сделает ваш фреймворк переносимым.

    Замыкание архитектурного цикла

    Мы прошли путь от простых скриптов, где каждый запрос писался вручную, до многослойной архитектуры.

  • Слой запросов (Playwright request): Базовый HTTP-клиент.
  • Слой контроллеров: Инкапсуляция эндпоинтов и типизация.
  • Слой фасадов: Сборка бизнес-сценариев из атомарных действий контроллеров.
  • Слой фикстур: Управление жизненным циклом объектов и их внедрение в тесты.
  • Слой тестов: Чистая бизнес-логика и проверки.
  • Такая структура обеспечивает максимальную поддерживаемость (Maintainability). Если разработчики изменят формат даты в API, вы поправите это в одном месте — в интерфейсе модели. Если изменится URL эндпоинта — вы поправите это в контроллере. Если изменится процесс регистрации — вы обновите Фасад. Тесты при этом останутся нетронутыми, что является признаком качественной архитектуры автоматизации.