| name | does-it-work |
| description | Проверка, что продукт реально работает, и защита его качества автотестами. Аудит работающего (в т.ч. навайбкоженного) приложения: найти баги, оценить готовность к проду, выдать баг-репорт с severity. Генерация тестовых фреймворков: API-тесты на Python (pytest + httpx + Pydantic + Allure) и Java (JUnit 5 + REST Assured), WEB/UI-тесты (Playwright, Selenium, Selenide, Page Object); конвертация OpenAPI/Postman/curl/HAR в тесты, негативные кейсы, контракты. Также стабилизация флакающих тестов и ревью качества тестов. Triggers: "проверь мой продукт/приложение", "найди баги", "навайбкодил", "можно ли в прод", "работает ли оно", "vibe code", "напиши автотесты", "сгенерируй тесты", "покрой тестами", "e2e тесты", "UI-тесты", "Playwright", "REST Assured", "generate tests", "стабилизируй тесты", "flaky", "тесты флакают", "ревью тестов", "проверь качество тестов".
|
does-it-work: проверка продукта и защита качества автотестами
Скилл отвечает на вопрос «а оно вообще работает?»: прогоняет живое приложение
тестами, находит баги (репорт с severity) и оставляет каркас автотестов как защиту
от регрессий. Пять эталонных каркасов в templates/ — все проверены запуском
против живых стендов. Копируйте их структуру и стиль, а не пишите с нуля.
Оформление (все ветки): имена функций/переменных — латиницей, docstrings, allure-тайтлы,
шаги и тексты assert-сообщений — на русском.
Выбор ветки
| Задача | Стек | Шаблон |
|---|
| API-тесты на Python (дефолт для API) | pytest + httpx (sync) + Pydantic | templates/api-python/ |
| API-тесты на Java | JUnit 5 + REST Assured + Maven | templates/api-java/ |
| UI-тесты на Python (дефолт для WEB) | Playwright + Page Object | templates/web-python-playwright/ |
| UI-тесты на Python (легаси/требование) | Selenium + Page Object | templates/web-python-selenium/ |
| UI-тесты на Java | Selenide + JUnit 5 | templates/web-java-selenide/ |
Если тип (API/WEB) или язык не следует из запроса и контекста проекта — задай один
вопрос пользователю до генерации. README каждого шаблона описывает паттерны своей ветки.
Java- и WEB-шаблоны — проверенные примеры на реальном приложении RV Booker: замените
ресурсы/страницы на свои, сохранив структуру слоёв.
Общие конвенции всех веток (подробно раскрыты ниже на python-ветке, остальные
зеркалят): слои клиенты/страницы → модели → тесты по фичам; конфиг только из
env-переменных (API_TESTS_* / WEB_TESTS_*); маркеры/теги smoke/critical/negative/flaky
- severity на каждом тесте; строгие контракты (Pydantic
extra="forbid" / Jackson records);
никаких sleep — только ожидания (wait_until / Awaitility / встроенные в Playwright и
Selenide); environment.properties и категории в Allure; зелёный прогон обязателен;
«Самопроверка качества» и «Red flags» (секции ниже) применяются во всех ветках.
Специфика WEB-веток: Page Object (страница = класс, локаторы — свойства/константы,
действия — методы с шагом); подготовка данных и логин — через API в обход UI
(форма логина — отдельный тест); артефакты при падении (скриншот + HTML) в Allure;
селекторы: стабильные id → роли → css, хрупкие xpath запрещены; мобильные вьюпорты
и кросс-браузерная CI-матрица — в Playwright-шаблоне.
Маршрутизация: что читать под задачу
- «Проверь мой продукт / найди баги / можно ли в прод» (аудит навайбкоженного
или незнакомого приложения) → те же шаги 1–5, но главный деливерабл — не каркас,
а вердикт: префлайт стенда → smoke ядра → карта покрытия → баг-репорт с severity
(examples/bug-report.md) и ответ «что работает, что
сломано, что не проверено». Каркас остаётся пользователю как защита от регрессий.
- Новый проект с нуля → выбор ветки (таблица выше) + весь порядок работы (шаги 1–5).
- Дописать тесты в существующий проект → шаг 1 (режим «существующий»), шаги 2, 4, 5.
- Стабилизировать флакающие тесты →
reference/stabilize-and-review.md, режим
«Стабилизация»: воспроизведи повторами → классифицируй причину → почини причину,
не симптом → докажи N зелёными прогонами. Каркас не разворачивай.
- Ревью существующих тестов → там же, режим «Ревью»: сначала запуск, потом
чек-листы (включая шаг 5 ниже), находки с severity, отчёт до правок.
- Только негативные кейсы / контракты → шаг 2 + паттерны «негативные», «контракт»
из шага 3; каркас не разворачивай.
- API с логином/ролями или общий стенд → плюс
reference/live-api-patterns.md.
- WEB-тесты → README выбранного web-шаблона; разведай DOM живого приложения
(Playwright-скриптом) до написания Page Object'ов — не выдумывай селекторы.
- Источник — не OpenAPI (код, требования, curl/HAR) →
reference/input-sources.md.
- Стенд недоступен/сомнителен → сначала
scripts/check_env.py (см. шаг 2).
Порядок работы (шаги детализированы для api-python; остальные ветки зеркалят)
1. Определи режим
- Новый проект → разверни каркас из шаблона выбранной ветки, подставь реальные
эндпоинты/страницы вместо примера.
- Существующий тестовый проект → сначала изучи его: conftest, базовый клиент, стиль
именования, маркеры. Новые тесты пиши в стиле проекта; паттерны из
templates/
применяй только там, где в проекте нет своего решения. Не дублируй существующие фикстуры.
2. Извлеки тест-кейсы из источника
Источником может быть OpenAPI-спека, исходный код сервиса, текстовые требования или
примеры запросов (curl/Postman/HAR). Рецепты по каждому — в
reference/input-sources.md. Если источник неоднозначен —
задай вопросы пользователю до генерации, не додумывай.
Перед генерацией проверь стенд префлайт-скриптом — он покажет доступность,
латентность и работоспособность авторизации до того, как ты напишешь хоть один тест.
Скрипт лежит в директории скилла, а cwd при работе — проект пользователя, поэтому
вызывай его по полному пути к директории скилла:
python <директория-скилла>/scripts/check_env.py https://stage.example.com/api [--token ...]
Если в API больше ~15 операций — не генерируй вслепую: построй карту покрытия
(таблица «метод + путь → планируемые тесты»), согласуй с пользователем объём
(полное покрытие / ядро / конкретные фичи, образец —
examples/coverage-map.md) и сохрани карту в docs/coverage.md
сгенерированного проекта. По ней видно, что покрыто, а что осознанно отложено;
обновляй её при доработках.
3. Сгенерируй код по слоям
api-tests/
config.py # pydantic-settings: base_url, токены — из env (API_TESTS_*)
clients/
base.py # BaseApiClient: allure.step + вложения «Запрос»/«Ответ»
<resource>.py # клиент на ресурс: create/get/list/delete + create_raw
models/
<resource>.py # Pydantic-модели ответов, extra="forbid"
utils/
assertions.py # assert_status / assert_contract / assert_error (allure.step внутри)
waiters.py # wait_until: поллинг асинхронных операций вместо time.sleep
retry.py # retry-декоратор с экспоненциальным backoff (сетевые сбои)
soft.py # SoftAssertions: все расхождения одним отчётом
tests/
__init__.py # обязателен здесь и в каждой поддиректории (см. Gotchas)
conftest.py # http_client (2 режима), фабрики faker, created_* с teardown
<feature>/ # директория = фича; файл = сценарная группа, ≤1 класса на файл
__init__.py
test_lifecycle.py # happy path + полный жизненный цикл
test_validation.py # параметризованные негативные (400/404/422)
test_access.py # авторизация и доступ (401/403)
pytest.ini # testpaths, --alluredir, маркеры (см. таксономию ниже)
requirements.txt
.env.example # шаблон всех API_TESTS_*-переменных с комментариями
README.md # установка, запуск, переключение окружений, CI-матрица
allure-categories.json # категории дефектов Allure (копирует pytest_configure из conftest)
.github/workflows/api-tests.yml # CI: e2e по пушу/кнопке/расписанию, артефакт allure-results
Обязательные паттерны (все реализованы в templates/):
- Тесты не вызывают HTTP напрямую — только через методы клиентов. Клиент возвращает
httpx.Response, проверки статуса и тела — в тесте.
- Проверки — через
utils/assertions.py, не голыми assert: assert_status(resp, 201),
model = assert_contract(resp, UserResponse), assert_error(resp, 404, context=case_id) —
каждый даёт Allure-шаг и читаемое сообщение; доменные проверки полей остаются
обычными assert рядом.
- Асинхронные операции — только
wait_until из utils/waiters.py, time.sleep
в тестах запрещён. Если API отвечает «принято в обработку» (202/processing) —
это отдельный тест: дождись конечного статуса поллингом и проверь его.
- Таксономия маркеров (registered в pytest.ini):
smoke — минимальный быстрый
набор ключевых сценариев, critical — бизнес-критичные потоки, negative —
негативные, flaky — карантин (CI гоняет -m "not flaky"). Плюс @allure.severity
на каждом тесте: blocker — ключевые happy path, critical — авторизация/доступ,
normal — остальное, minor — 404 и косметика.
В web- и java-ветках дополнительно маркер/тег e2e на всех тестах (они всегда
идут против живого стенда); в api-python его нет — режим e2e/asgi задаёт
env-переменная API_TESTS_MODE, а не маркер.
create_raw(payload: dict) в каждом клиенте — для негативных кейсов с произвольным телом.
- Контракт через Pydantic:
UserResponse.model_validate(response.json()) с
extra="forbid" — ловит лишние поля, типы и обязательность. Тела ошибок тоже
валидируются моделью (ApiError).
- Негативные кейсы — один параметризованный тест, кейсы вида
("случай", payload),
человекочитаемый case_id идёт в сообщение assert.
- Тестовые данные — фабрики на
faker (фикстура user_payload), никаких хардкодов.
- Очистка — фикстура
created_* создаёт ресурс и удаляет в teardown; teardown не
падает, если тест уже удалил ресурс сам.
- Каждый негативный позитивному в пару: на любой happy path — минимум кейсы
«невалидное тело» (422), «без авторизации» (401), «не существует» (404).
- Группировка по фиче, не по типу теста (выбор пользователя): директория = фича,
файл = сценарная группа, не больше одного класса на файл (класс в pytest — только
пространство имён и
allure.story). Негативные кейсы лежат рядом со своей фичей,
а не в общем «негативном» файле; запуск фичи целиком — pytest tests/<feature>.
Allure-иерархия: feature = директория, story = файл/класс.
- README.md обязателен во всех ветках (шаблоны в
templates/): механизм
переключения окружений должен быть виден без чтения config.py — примеры запуска
в терминале и CI-матрица сред. .env.example обязателен в python-ветках
(pydantic-settings читает .env); в java-ветках dotenv-механизма нет — Java-стек
читает env-переменные напрямую, поэтому вместо .env.example в README должна быть
полная таблица env-переменных с описанием и дефолтами.
- Живой стенд и динамическая авторизация — если токен не статический
(register/login, роли admin/user, общий стенд с чужими данными), бери проверенные
паттерны из reference/live-api-patterns.md:
session_user/temp_user, skip позитивного админского CRUD без кредов,
ретрай при конфликте ресурсов, уникальные суффиксы в данных.
Для ветки api-java — Java-эквиваленты там же (@BeforeAll-пользователь,
@BeforeEach-temp-пользователь, Assumptions.assumeTrue, Awaitility).
4. Запусти и добейся зелёного прогона — обязательно
Сгенерированные, но не запущенные тесты — не результат. Установка и smoke-проверка
окружения — готовыми скриптами из директории скилла (запускать из корня
сгенерированного проекта, путь к скрипту — полный, до директории скилла):
python-ветки — scripts/bootstrap.sh (venv + зависимости + проверка коллекции
тестов), java-ветки — scripts/bootstrap-java.sh (проверка java/mvn +
mvn test-compile).
Что делает scripts/bootstrap.sh (эквивалент вручную, проверено):
uv venv .venv --python 3.12
uv pip install --python .venv/bin/python -r requirements.txt
PYTHONPATH=. .venv/bin/pytest --collect-only -q
Интеграционный режим (in-process, без развёрнутого стенда — если приложение импортируемо):
API_TESTS_MODE=asgi PYTHONPATH=.:<путь-к-приложению> .venv/bin/pytest
E2E против стенда:
API_TESTS_BASE_URL=https://staging.example.com API_TESTS_API_TOKEN=... PYTHONPATH=. .venv/bin/pytest
Allure-результаты пишутся в allure-results/ (задано в pytest.ini); отчёт:
allure serve allure-results. Категории дефектов (allure-categories.json в корне
проекта) подкладывает в results хук pytest_configure из conftest — известные баги
(strict xfail с текстом «Баг API: …») попадают в отдельную категорию отчёта.
Тренды/история Allure появляются, только если переносить history/ из прошлого
отчёта в новые results — в CI сохраняйте отчёт артефактом или публикуйте на Pages.
Если тест падает из-за реального расхождения API со спекой —
не подгоняй тест под фактическое поведение молча: покажи расхождение пользователю.
Подтверждённый баг фиксируй тестом с xfail(reason="Баг API: ...", strict=True) —
прогон остаётся зелёным, а когда баг починят, тест сам просигналит (XPASS→FAILED).
Найденные баги API в итоговом отчёте пользователю классифицируй по severity
(шаблон — examples/bug-report.md):
Critical — потеря денег/данных, дыры авторизации; High — функция не работает
или спека врёт о ключевом поведении; Medium — принимаются невалидные данные,
неверные коды ошибок; Low — расхождения форматов, косметика.
5. Самопроверка качества — после зелёного прогона
Зелёный ≠ качественный. Пройди по сгенерированным тестам чек-листом; каждое «да» — чинить:
- Есть тест, который проверяет только статус-код, хотя ответ содержит тело?
(слабый assert — добавь контракт/проверку полей)
- Есть проверки только «поле существует», где можно проверить значение?
- Тест зависит от результатов другого теста или от порядка запуска?
- В данных есть хардкоды (id, email, даты), которые сломаются на другом стенде?
- Название теста содержит «и» — он проверяет два поведения? Раздели.
- Негативный кейс проверяет только код ошибки, но не контракт тела ошибки?
- Happy path без пары негативных (401/404/невалидное тело)?
- Есть
time.sleep вместо wait_until?
- Асинхронные операции API (202/processing) проверены до конечного статуса?
- Все тесты размечены маркерами и severity?
Red flags — сигналы остановиться
Если ловишь себя на одной из этих мыслей — остановись, это ошибка процесса:
| Мысль | Реальность |
|---|
«Ослаблю модель (extra="ignore", Any), чтобы прошло» | Это расхождение контракта — покажи пользователю, ослабляй только точечно с комментарием |
| «Поменяю ожидаемый статус на фактический, спека наверное устарела» | Может и устарела — но это решает пользователь, а не тест |
| «Тест против живого API прошёл с первого раза — отлично» | Проверь, что он вообще может упасть: сломай ожидание и убедись, что падает |
| «Этот эндпоинт слишком простой, чтобы тестировать» | Простые эндпоинты ломаются так же часто; health-check — самый дешёвый smoke |
| «Пропущу запуск, тесты очевидно корректные» | Незапущенные тесты — не результат (шаг 4 обязателен) |
| «Данные захардкожу, на этом стенде они всегда есть» | Стенд общий/пересоздаваемый — бери опорные данные запросом, генерируй свои фабрикой |
| «Флаки-тест перезапущу, наверное повезёт» | Разберись в причине; временно — маркер flaky (карантин), не игнор |
Режимы запуска и CI
- Переключение окружений — только через env-переменные
API_TESTS_* (см. config.py),
без правок кода. Приоритет: переменная окружения → .env → дефолт в config.py.
Зафиксированное решение пользователя: не добавлять CLI-флаги (--base-url через
pytest_addoption) и плагины (pytest-base-url) — один источник правды Settings,
ноль лишних зависимостей; вместо этого механизм документируется в README
(примеры терминала + CI-матрица, шаблон в templates/api-python/README.md).
- Для CI:
pytest -m "not flaky" (карантин не валит регрессию; флаки гоняются
отдельной джобой -m flaky), --alluredir уже включён; среда задаётся переменными
джобы (матрица сред), секреты — только через env, не через флаги (флаги видны в логах CI).
- Готовый workflow в
templates/api-python/.github/workflows/api-tests.yml — две джобы:
прогон + публикация Allure-отчёта на GitHub Pages с переносом history/
(тренды между прогонами копятся автоматически).
- Моки внешних API (когда тестируем свой сервис in-process, а он ходит наружу) —
respx:
respx.mock фикстурой, роуты на конкретные URL, assert_all_called.
- Параллельность —
pytest-xdist (-n auto); тесты обязаны быть независимыми
(свои данные через фабрики, очистка в teardown) — паттерны шаблона это гарантируют.
Gotchas (найдены при реальном прогоне)
EmailStr требует email-validator: ставьте pydantic[email], иначе падение
на этапе сборки схемы модели (ImportError при коллекции тестов).
httpx.ASGITransport — только async. С синхронным httpx.Client он падает с
AttributeError: 'ASGITransport' object has no attribute 'handle_request'.
Для sync in-process тестов используйте fastapi.testclient.TestClient — он наследник
httpx.Client, поэтому API-клиенты каркаса работают с ним без изменений.
- Кириллические id в
parametrize в выводе терминала экранируются
(\u043f\u0443... вместо пу...) — это косметика pytest, в Allure-отчёте всё читаемо. Если мешает,
добавьте disable_test_id_escaping_and_forfeit_all_rights_to_community_support = True
в pytest.ini.
TestClient(app, headers=...) принимает заголовки в конструкторе — токен
авторизации задаётся один раз, как и у сетевого клиента.
- Пустая env-переменная не «сбрасывает» настройку:
API_TESTS_BASE_URL= pytest
задаёт пустую строку (перекрывая и .env, и дефолт) — тесты падают с
httpx.UnsupportedProtocol. Проверяйте, не экспортирована ли переменная пустой.
- Одинаковые имена тест-файлов в разных директориях (
users/test_validation.py
и bookings/test_validation.py) без __init__.py роняют коллекцию pytest
с «import file mismatch». Кладите пустой __init__.py в tests/ и каждую
поддиректорию — заодно это делает надёжными импорты вида from tests.factories import.
Выше — gotchas ветки api-python. Gotchas остальных веток (api-java, все web) —
в разделе «Gotchas» README соответствующего шаблона: прочитай его перед
генерацией своей ветки.