Кейс

karkase2e — единая E2E-система тестирования для self-hosted FastAPI-приложений

Один фреймворк на все self-hosted FastAPI-приложения: 404 автотеста для Kanban-доски, учётной системы и CPA-трекера. Playwright, эфемерная SQLite, GitHub Actions CI.

Архитектура и разработка, Python, pytest, Playwright, GitHub Actions 2026
karkase2e — единая E2E-система тестирования для self-hosted FastAPI-приложений

Какую задачу решал проект.

E2E-тестирование веб-приложения — это всегда один и тот же каркас: поднять приложение на чистой базе, дождаться готовности, авторизоваться, открыть браузер, действовать от имени пользователя, прибраться за собой. Каркас один, а приложения разные: у доски drag-and-drop и файлы, у учётной системы — табличные документы и деньги в минорных единицах, у трекера — HTTP-пайплайн кликов и постбэков.

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

Ограничения и требования
  • Единая точка входа: pytest –karkas-app=<name> + путь к тестам приложения; случайный сбор тестов двух приложений в одну сессию исключён конфигурацией.
  • Изоляция: приложение поднимается subprocess'ом на эфемерной SQLite и свободном порту, база удаляется после прогона.
  • Честная авторизация: cookie сессии из 303-редиректа, зеркалирование в Playwright storage_state, свежий контекст браузера на каждый тест.
  • Ядро без единого упоминания имён приложений — всё различие в конфиге плагина.
  • Типизированные доменные поля: деньги в минорных единицах, справочники, файлы; генераторы данных на Faker.
  • Диагностика падений: скриншот браузера + дамп серверных логов за время прогона.
  • CI на GitHub Actions с тем же сценарием, что и локально.

Результат

karkase2e — один фреймворк на все self-hosted FastAPI-приложения проекта: 404 теста (168 на доску задач, 106 на учётную систему, 130 на трекер), ядро без единого упоминания имён приложений. Smoke-набор каждого приложения проходит меньше чем за полминуты, полный набор — за минуты. Новое приложение подключается одной папкой-плагином: конфиг, профиль доменных полей, страницы и тесты.

Решение

Как устроена архитектура.

Ядро karkas_testkit ничего не знает о приложениях: единственный шов — замороженная dataclass AppConfig, которую строит плагин. Всё остальное — сервер, авторизация, страницы, формы, отчётность — общее.

Шов AppConfig

Одна frozen-структура описывает всё, что различается: env-префикс, uvicorn-цель, путь readiness, тестиды формы логина, флаг uploads-каталога. load_app_config() читает YAML, применяет KARKAS_*-переопределения и импортирует app.py плагина по пути файла (дефис в имени пакета регистрируется синтетическим модулем).

ServerController

Поднимает приложение subprocess'ом uvicorn на эфемерной SQLite и свободном порту (portpicker), ждёт готовности по readiness-пути, прогоняет seed-demo, после прогона удаляет временную базу.

Аутентификация как браузер

Логин через raw http.client с чтением Set-Cookie из 303-редиректа — urllib при редиректе cookie теряет. Cookie зеркалится в Playwright storage_state: каждый тест стартует залогиненным, но в свежем контексте, поэтому logout и смена локали не каскадируются.

Доменный профиль и формы

FieldType/FieldSpec описывают типы полей (деньги в минорных единицах, reference-поля с пикером, COLOR/FILE), type-aware filler заполняет формы, проверки Excel-экспортов — через openpyxl.

Маркеры и темп прогонов

Базовые маркеры smoke/auth/flow/contract/unit плюс динамические маркеры каждого приложения (board, card, catalog, document, campaign, pipeline…): 14 smoke-тестов — 20 секунд, 404 теста — минуты.

Диагностика и CI

При падении сохраняются скриншот браузера и дамп серверных логов за время прогона; GitHub Actions повторяет тот же сценарий на каждый push.

Экраны

Фреймворк в работе.

Архитектура karkase2e: ядро karkas_testkit и плагины приложений

Ядро karkas_testkit и три плагина — всё различие живёт в AppConfig

Сборка тестов трёх приложений: 168 + 106 + 130 = 404 теста

Сборка тестов трёх приложений: 404 автотеста (реальный вывод pytest)

Прогон smoke-набора: 14 тестов пройдены

Реальный прогон smoke-набора: 14 passed за 18 секунд

Итог

Что получает команда.

Один фреймворк вместо трёх копий: меньше поддержки, быстрее новые приложения.

404

автотеста на 3 приложения

168 — Kanban-доска (DnD через SortableJS, файлы, голосование), 106 — учётная система (документы, проводки, деньги), 130 — CPA-трекер (пайплайн кликов и постбэков без браузера).

0

упоминаний приложений в ядре

Всё, что различается, живёт в AppConfig плагина. Ядро не менялось при подключении всех трёх приложений.

~20 сек

smoke-набор приложения

Логин, ключевые страницы и health-check; полный прогон с браузером — минуты, для трекера — вообще без браузера.

1 папка

для нового приложения

app.py с AppConfig, профиль доменных полей, страницы и тесты. Шаблон и промпт для AI-агента — в docs/ADD-NEW-APP.md.