Коротко:
Мы разработали систему для автоматического определения набора тестов на основеgit diff. Связали модули проекта с бизнес-фичами через трассировку выполнения кода во время тестов. Теперь любой релиз можно оценить на достаточность покрытия e2e-тестами. Решили вопрос селективного запуска на всех уровнях пирамиды тестирования. Что важно — маппингtests->feature->filesсоздаётся и поддерживается автоматически при поддержке тестов, без дополнительной ручной работы.
Проблема: что запускать и как понять достаточно ли покрытия?
Мини-глоссарий перед началом
Фича (Feature) — единица функциональности конечного продукта, каждая функциональная бизнес-единица может быть описана одной или несколькими спецификациями с бизнес-требованиями, а значит может быть связана с тест-кейсами, созданными из этих требований. В TMS (Allure TestOps) фича — это
custom-field, которым размечаются все тест-кейсы. Все связи в статье строятся вокруг фич:files/modules <-> features <-> tests.-
E2E-тест — автоматизированный сценарий позитивного пользовательского пути фичи на полностью поднятой инфраструктуре (UI/API, очереди, БД, внешние сервисы). Цель E2E — максимально релевантно имитировать опыт пользователя минимальным числом действий. Пример E2E-сценария (фича «Регистрация»):
Открыть модалку регистрации
Ввести данные пользователя
Отправить на бэкенд
Провалидировать данные
Отправить SMS-код
Отправить событие начисления бонуса при регистрации
Отобразить начисленный бонус
Редирект после успешной регистрации
У нас несколько проектов: 7 080 тест-кейсов в одном (4 211 автоматизированных), 4 685 в другом (3 718 автоматизированных). Разработчик меняет десятки файлов, а если это релиз в prod, то и вся сотня может залететь. Нужно тестировать перед релизом. Начинается парад вопросов.
Проблема 1: Селективный запуск
Что запускать при изменениях (в feature-ветке и на регрессе), чтобы тестировать быстро и с минимальными рисками пропустить регрессию?
А: Запускать всё — долго/дорого. И при этом всё равно нет ответа «есть ли у нас в автотесты разных слоев, которые проверяют именно эти изменения?»
Б: Только smoke — быстро, но рискованно: вне смоука вполне может быть и будет риск регрессии
В: Ручной выбор — субъективно и медленно, требует глубокой экспертизы в репозиториях
Г: Code coverage/графы зависимостей монорепо — покажет, какие модули и какие строки кода выполнились, а продвинутые инструменты монорепо и AI даже могут запускать unit-тесты на основе статического анализа импортов или обучения на истории коммитов, но не ответит на главные вопросы: какие фичи аффектят изменения, как их покрывают E2e-тесты, и достаточно ли этого покрытия.
Долгое время наш путь — это вариант Б + В. Этот симбиоз хоть и компенсирует недостатки друг друга, но остаётся узким горлышком и всё равно несёт риски ошибок.
Проблема 2: Покрытие изменений — как понять, достаточно ли?
Даже выбрав тесты, остаётся главный вопрос: достаточно ли покрыто конкретное изменение для безопасного релиза?
Что считается достаточным покрытием:
Классически самая уверенная метрика пройденного регресс-тестирования — это прохождение позитивных путей человеком. Именно так работает ручной регресс: QA проходит ключевые сценарии, чтобы убедиться, что всё работает как раньше.
Почему E2E‑сценарии — опора для регресса.
E2E ближе всего к ручной проверке фичи: позитивный путь от начала до конца, реальная инфраструктура и интеграция всех частей (UI <-> API <-> очереди <-> БД <-> интеграции с микросервисами <-> внешние интеграции). Мы используем сценарный тест‑дизайн для регресса — полноценные пользовательские сценарии по фиче в e2e-кейсах; атомарные проверки уезжают на нижние уровни пирамиды.
При этом E2E — самые дорогие по ряду качеств. Запускать «все E2E-тесты всегда» невозможно, да и еще != «проверить всё».
Нужна объективная метрика, показывающая, какая доля изменённых модулей относится к фичам с пройденными E2E‑сценариями. Только так можно ответить:
Покрыты ли изменения реальными пользовательскими сценариями?
Достаточно ли этого покрытия для релиза в prod без проведения доп. ручных проверок?
Unit/интеграционные тесты важны для быстрой обратной связи при разработке, но решение о релизе требует понимания: прошли ли изменения через реальные пользовательские пути.
Проблема 3: Частые релизы — убрать человека из цепочки
Теперь про релизы. Мы хотели увеличить частоту релизов, но каждый раз упирались в один вопрос:
Можем ли мы объективно сказать: «Этот релиз протестирован достаточно»?
Без ответа на этот вопрос — невозможно убрать человека из процесса. QA вручную смотрит изменения, вручную выбирает тесты, вручную решает: «Да, можно выкатывать» или «Нет, рискованно». Релиз может растягиваться на дни, бизнес теряет скорость.
Простой расчёт:
Релиз раз в месяц -> можно позволить 2–3 дня на ручное тестирование
Релиз раз в неделю -> желательно уложиться в 4–6 часов
Релиз ежедневно -> нужно не более 20–30 минут
Релизы когда угодно -> нужны полностью автоматические
Quality Gatesс объективными метриками
Что нужно для автоматизации выпуска релизов:
Знать, какие конкретно файлы изменены с момента последнего релиза
Понимать, какие бизнес-фичи затронуты (какие сценарии под риском)
Видеть E2E Coverage этих изменений (реально ли прогнаны пользовательские пути)
Иметь зоны риска (фичи, задетые множеством изменений)
С этими данными можно выстроить автоматический процесс: E2E Coverage выше порога -> тесты прошли -> автоматический/полуавтоматический релиз в prod.
Что нужно было решить
Итак, разобрав проблемы приходим к выводу, что нужен инструмент, который:
Селективный запуск: автоматически определяет, какие тесты всех уровней пирамиды релевантны изменениям (не все 7k, а только нужные)
Связь файлов с фичами: создаёт базу знаний (файл -> фича -> вся пачка тестов фичи)
Метрики E2E Coverage: показывает, какой процент изменений покрыт реальными пользовательскими путями
Зоны риска: выделяет фичи, затронутые сильнее всего
Автоматическая поддержка: маппинг обновляется сам, без ручной дополнительной работы
Анализ существующих подходов
Прежде чем писать свою систему, мы изучили некоторые решения. Есть ли готовый инструмент для селективного запуска тестов с автоматическим маппингом фич и метриками покрытия изменений по всем уровням пирамиды тестирования?
Test Impact Analysis (TIA)
Начнём с важного: Test Impact Analysis (TIA) — это методология, а не один инструмент. В индустрии есть несколько подходов и реализаций, каждый решает задачу селективного запуска по‑своему. Ниже — краткий обзор.
Статический граф зависимостей + git:
Jest
--findRelatedTests/-o, Vitest--changed/watch: отбор тестов по импорт-графу/кэшу без рантаймаNx affected, Bazel, Buck/Gradle: отбор целей/проектов по графу зависимостей репозитория (особенно в монорепо)
Runtime/coverage-based:
Datadog Test Impact Analysis (JS/TS, Cypress/Playwright/Jest/Vitest/Mocha): собирает покрытие на рантайме и строит карту «тест -> файлы», в CI пропускает нерелевантные тесты
Pytest-testmon (Python, OSS): хранит соответствия «тест -> затронутые файлы» на основе фактического исполнения (coverage), запускает только тесты, которые прогоняют эти файлы
AppMap (Node.js агент): пишет подробные рантайм-трейсы (вплоть до SQL) и может записывать трассировку во время unit-тестов. Не «TIA-кнопка», но хорошее ядро для рантайм-подхода анализа
ML/предиктивные:
Gradle Develocity Predictive Test Selection: вероятностный выбор тестов по истории билдов/изменений
Launchable: поддерживает JS-раннеры, фокус на вероятностной селекции
Testim, ReTest, Functionize: AI-powered инструменты для UI-тестирования с ML-селекцией
Все эти варианты — практические реализации одной идеи: ускорять обратную связь, не гоняя всё подряд. Спойлер — мы также берём TIA как базовую методологию, и ниже покажем, какие требования были у нас и что именно мы добавили поверх базы.
Статический граф зависимостей
Базовый пример статического подхода: изменили файл payment.ts —> инструмент ищет, кто его импортирует —> запускает тесты этих модулей. Это ускоряет CI на уровне unit-тестов.
Допустим, в Nx это выглядит так:
- Изменён packages/payment/utils/formatDate.ts
- Nx строит граф зависимостей всех пакетов
- Находит пакеты, которые зависят от formatDate.ts
- Запускает только тесты этих пакетов
Почему не подходит для наших задач:
У статических реализаций есть особенности, которые не закрывают наши требования: они, как правило, работают на уровне модулей/проектов, а не бизнес-фич; не дают сквозных метрик E2E-покрытия; ориентированы на один репозиторий. Статический граф не видит динамических зависимостей (условные импорты, lazy loading, dependency injection), не учитывает runtime-логику и не может связать код с бизнес-фичами.
Runtime-подходы
Runtime-инструменты собирают данные о том, какие файлы реально выполнялись во время запуска тестов. Это точнее статического анализа, так как учитывает фактическое поведение.
Почему готовые решения нам не подошли:
Готовых runtime-решений для Node.js/TypeScript, которые бы закрывали наши задачи, практически нет. Datadog TIA существует, но у него есть критичные для нас ограничения: требует платную подписку, mapping хранится на сервере Datadog (нет контроля над данными), не даёт связи с бизнес-фичами, не решает проблему кросс-репозиторного анализа.
AppMap — хорошее ядро для рантайм-подхода, но это именно ядро, а не готовое решение под наши требования.
Но самое главное: мы поняли, что runtime-подход можно реализовать достаточно простыми инструментами в рамках общей тестовой системы. Не нужно платить за внешний сервис или зависеть от чужой инфраструктуры — можно собрать свою систему, которая будет точно соответствовать нашим требованиям. О том, как именно мы это сделали и какие инструменты использовали, мы расскажем подробнее ниже.
ML/AI для селективного тестирования
ML-based TIA — отдельная категория инструментов. Они обучают модель на истории: какие коммиты ломали какие тесты, какие файлы часто меняются вместе. При новом MR модель предсказывает релевантные тесты.
Основные инструменты: Gradle Develocity (Java/Kotlin), Launchable (мультиязычный SaaS), Testim/ReTest/Functionize (UI-тестирование).
Почему не подходит:
Чёрный ящик — модель не объясняет, почему выбрала именно эти тесты. Для релизных решений важна прозрачность. Требует 6–12 месяцев истории и дорого (платные подписки или собственная ML-инфраструктура). Маппинг не создаёт — нет явной карты "фича -> тесты -> код". Вероятностный подход — всегда есть риск пропустить критичный баг.
AI-инструменты выглядят перспективно, но для нас важнее прозрачность и объяснимость решений, чем модные технологии. Стоимость внедрения несопоставима с потенциальной пользой.
Ручной маппинг: TMS и теги в коде
Есть ещё два подхода к созданию связей между фичами и кодом. Оба требуют ручной работы, и оба быстро устаревают.
Вариант первый: Test Management Systems (TMS). Это когда ты открываешь Allure, TestRail, Jira/Xray или другую TMS, создаёшь тест-кейс, расписываешь шаги, вручную связываешь его с фичей, вручную указываешь список файлов кода, которые этот тест покрывает.
Процесс:
Написали автотест в коде
Открыли TMS (TestRail/Jira)
Создали тест-кейс, расписали шаги
Вручную связали с фичей
Вручную указали список файлов кода
Сделали рефакторинг -> идите на шаг 4, повторите для всех тестов Полностью ручной труд.
Вариант второй: теги в коде. Прописываешь связи прямо в модулях через комментарии или конфиги:
// @feature Платежи. Пополнение
// @feature Платежи. Токенизация
// @related-tests payment.service.test.ts, payment-flow.e2e.ts
export class PaymentService { /* ... */ }
Или через JSON-конфиг:
{
"src/services/payment.ts": {
"features": ["Платежи. Пополнение", "Платежи. Вывод"],
"tests": ["payment.service.test.ts", "payment-flow.e2e.ts"]
}
}
Процесс (тоже ручной):
Создали новый модуль
Добавили теги фич в файл или конфиг
Указали связанные тесты
Рефакторинг: переименовали файл -> обновите все теги
Разделили модуль на два -> обновите маппинг в обоих
Удалили тест -> не забудьте убрать из тегов
Тоже ручная работа.
Почему не работает.
Мы проанализировали оба варианта и поняли: в условиях постоянно меняющегося кода ручной маппинг обречён на провал.
Маппинг устаревает моментально. Ежедневно рефакторятся десятки файлов, переименовываются модули, разделяются на части, добавляются новые тесты, удаляются старые, меняются названия фич или вовсе выпиливаются.
С TMS после каждого рефакторинга нужно открыть UI, найти все связанные тест-кейсы, обновить списки файлов. При сотнях коммитов в неделю это физически невозможно. С тегами в коде переименовали payment.ts -> нужно найти все файлы, где он упоминается, и обновить. Разделили модуль на 3 части -> перераспределяй теги. Забыл обновить хотя бы в одном месте — маппинг уже неточен. А сказать, какими фичами используется модуль, бывает просто невозможно из-за множества импортов и кондишенов.
Огромные трудозатраты. Для нескольких тысяч тестов нужен выделенный человек на полную ставку для работы с TMS или каждый разработчик должен помнить про маппинг каждого модуля при каждом изменении.
Самое коварное: нет проверки корректности. Можно указать, что тест покрывает payment.ts, а в реальности тест использует mock, и настоящий payment.ts даже не запускается. Можно написать связь с тестом, которого уже не существует. Указать файл, который тест не вызывает. Никто не проверяет в runtime: действительно ли тест реально вызывает указанные файлы? Все ли тесты, которые вызывают файл, указаны в маппинге? Актуальны ли названия фич?
В итоге через месяц-два маппинг превращается в "примерный список, которому можно верить процентов на 60". Для решений о релизе этого недостаточно.
TMS хороши для управления документацией, теги в коде — для быстрых пометок. Но поддерживать актуальный маппинг Feature->Code вручную — это сизифов труд, который никто не тянет долго. Система устаревает быстрее, чем успевает принести пользу.
Но базово сама модель правильная. Связь "тесты E2e -> фича -> тесты -> файлы кода" — это именно то, что нужно. Проблема не в идее, а в том, что её невозможно поддерживать вручную. Если бы существовал способ автоматически собирать и актуализировать такой маппинг, без участия человека — это решило бы все перечисленные проблемы.
Code Coverage — измеряем покрытие строк, не более
Это отдельная история, которая не пересекается с TIA. Coverage-инструменты решают другую задачу: показать, какие строки кода выполнились при прогоне тестов.
Запускаешь тесты с включённым coverage -> он собирает, какие строки выполнились -> показывает отчёт: "83% строк кода покрыто тестами". Звучит полезно, но для наших задач не подходит.
Как мы уже говорили в разделе "Проблема", нам нужна метрика покрытия изменений E2E-тестами.
Проанализировали и стали делать свое
Изучили рынок. Вот что нашли.
Существующие реализации TIA отлично ускоряют прогоны, но под наши релизные требования потребовались дополнения: связь кода с бизнес-фичами, общие метрики по всей пирамиде, мультирепозиторная поддержка и самоподдерживающийся маппинг в TMS.
Что можно решить нашим подходом:
Мы взяли TIA как базовую методологию и реализовали недостающие элементы простыми инструментами в рамках общей тестовой системы:
Автоматический runtime-маппинг — вместо статического графа или ручного труда собираем реальные связи файлы -> фичи -> тесты во время выполнения тестов. Никаких платных SaaS и серверов с данными — всё локально, контролируемо.
Связь с бизнес-фичами — не просто "тест покрывает файл", а "тест покрывает фичу через эти файлы".
Анализ покрытия по всем слоям — мы видим, какие фичи реально аффектят изменения этих файлов, какие из них покрыты E2E-тестами, для скольких есть unit-тесты, и аналогично по остальным уровням пирамиды. Такой сквозной проход через фичи позволяет понять не просто "уровень покрытия", а именно структуру покрытия на разных стадиях тестирования.
Мультирепозиторность — работаем с кодом, распределённым по нескольким репозиториям. Runtime-подход не зависит от границ проектов.
Прозрачность и детерминированность — в отличие от ML-моделей, всегда можем объяснить, почему тест связан с фичей. Нет вероятностей, только факты.
Интеграция в существующий стек — Node.js/TypeScript, никаких сторонних агентов. Всё работает в рамках нашей инфраструктуры.
Ниже мы подробно расскажем, как именно мы это реализовали, какие инструменты использовали и как всё это работает "в бою".
Наше решение: как мы это сделали
Система состоит из трёх компонентов:
┌─────────────────────────────────────────────────────────────┐
│ АРХИТЕКТУРА СИСТЕМЫ │
└─────────────────────────────────────────────────────────────┘
┌───────────────┐
│ GIT DIFF │
│ (изменено N │
│ файлов) │
└──────┬────────┘
│
▼
┌──────────────────────────────┐
│ Git Changes Analyzer │
│ Анализирует изменения и │
│ находит фичи по маппингу │
└───────┬──────────────────────┘
│ (маппинг: File -> Features -> Tests)
▼
┌─────────────────────────────────────┐
│ Allure TestOps │
│ ┌──────────────────────────────┐ │
│ │ • Тест-кейсы с фичами │ │
│ │ • теги (связи)* │ │
│ └──────────────────────────────┘ │
│ ◄────────────────────┘
│ (метаданные и связи тестов │
│ и файлов хранятся тут) │
└───────┬─────────────────────────────┘
│ (заполняется автоматически
│ при запуске тестов)
│
▼
┌──────────────────────────────┐
│ TRACER │
│ • Какие файлы выполнялись │
│ • Какие функции вызваны │
│ • Какие компоненты созданы │
└────────┬─────────────────────┘
│ (интегрируется в тестовые раннеры)
▼
┌───────────────────────────┐
│ ТЕСТЫ │
│ test('...', () => { │
│ qa.doc({ │
│ feature: "Платежи" │ - разработчик автотеста указывает фичу
│ }) │
│ }) │
└───────────────────────────┘
*Обратите внимание: использование тегов в TestOps — мера вынужденная.
Гораздо более удобно и перспективно было бы хранить значения связей (маппинга)
через кастомные поля. Такой подход позволил бы автоматически
строить дерево связей файлов прямо в TestOps и удобно их визуализировать.
Однако сейчас есть ограничение платформы на количество значений custom field,
поэтому временно используем текстовые теги для хранения связей.*
Ключевая идея: связь модулей с фичами через трассировку
Когда мы связываем модуль не только с конкретным тестом, но и с фичей целиком, получаем цепочку связей files<->features<->tests.
Пример:
Изменён
controllers/user-analyzer/checkers/gender.ts-> фича «[Admin] Машина сценариев» (неочевидная связь, выявленная трассировкой)У фичи «[Admin] Машина сценариев» есть 30 unit + 4 интеграционных + 3 E2E-тестов
Что дают эти связи:
Видим набор тестов всех уровней для фичи (unit, интеграционные, E2E)
Автоматически формируем контекстный тест-план по изменённым файлам
Получаем объективную метрику: какая доля изменённых модулей относится к фичам с E2E‑сценариями
Метрики покрытия -> объективные решения:
Зная долю изменений, относящихся к фичам с E2E‑сценариями, мы можем:
-
Задать пороги качества:
E2E Coverage изменений < 30% -> ручная проверка обязательна
E2E Coverage изменений > 60% -> допускаем автоматический релиз
Приоритизировать работу: низкое покрытие по фичам -> задачи на усиление тестов нужных уровней
Автоматизировать релизы: высокое покрытие и пройденные проверки -> выкат без ручных регрессов
Вот это и есть ключ к автоматизации: не человек решает «достаточно или нет», а объективные данные.
Компонент 1: Tracer — трассировщик выполнения кода
Tracer – это инструмент, который инструментирует код приложения и отслеживает, какие файлы и функции исполняются во время выполнения тестов.
Как работает Tracer
Для разных сред у нас свои реализации рантайма трассировщика, но база одинаковая и может расширяться в рамках TS/JS-cтека, но концептуально это реализуемо на любом языке программирования:
Tracer для Node.js (Backend)
import { NodeTracer } from '@sxl/tracer'
const tracer = new NodeTracer({
enabled: true,
includeProjectsPaths: ['src'],
rootPaths: ['src'],
outputPath: './.tmp/tracer',
})
// В тесте:
test('payment creation', async () => {
tracer.start()
// Выполняем код, который хотим трассировать
await createPayment({ amount: 100 })
const result = tracer.stop()
// result.files -> ['src/services/payment.ts', 'src/controllers/payment.ts']
// result.functions -> ['PaymentService | create', 'PaymentController | handle']
})
Tracer для Vue.js (Frontend)
import { VueTracer } from '@sxl/tracer/core/tracer-runtime/vue'
const tracer = new VueTracer({
enabled: true,
includeProjectsPaths: ['entities', 'packages', 'apps'],
rootPaths: ['entities', 'packages', 'apps'],
components: [
{ name: 'wl-payment', match: 'entities/wl-payment/.*\\..*' },
{ name: 'wl-profile', match: 'entities/wl-profile/.*\\..*' },
],
})
// В Playwright-тесте:
test('payment flow', async ({ page, tracer }) => {
await page.gotoComponentStory('PaymentForm')
await tracer.start()
await page.fill('#amount', '100')
await page.click('#submit')
const result = await tracer.stop()
// result.files -> ['entities/wl-payment/PaymentForm.vue', 'packages/wl-core/api.ts']
// result.vue -> [ { name: 'PaymentForm', file: '...', parent: null } ]
})
Трансформация кода
Чтобы трассировать выполнение, Tracer предварительно модифицирует исходный код, добавляя специальные вызовы. Это происходит в два этапа:
1. Трансформация на этапе сборки (build-time)
Перед запуском тестов мы прогоняем CLI-тул, который вставляет трейс-сигналы в код:
# Через CLI вручную:
npx tracer --input "src/**/*" --ignore "node_modules" --outDir "./transformed"
# Или через npm script в package.json:
npm run test:transformed
Пример конфигурации (tracer.config.js):
module.exports = {
transformPluginOptions: {
input: 'src/**/*.{js,ts}',
outDir: 'transformed',
mode: 'magic', // или 'babel'
},
runtimeConfig: {
enabled: process.env.TRACER_ENABLED === 'true',
includeProjectsPaths: ['src'],
rootPaths: ['src'],
template: 'componentName | functionName',
components: [
{ name: 'service', match: '/services/' },
{ name: 'controller', match: '/controllers/' },
],
},
}
2. Сбор данных на этапе выполнения (runtime)
В трансформированный код вставляются вызовы примерно такого вида:
// До трансформации
function createPayment(amount) {
return db.insert({ amount })
}
// После трансформации
__traceModule('src/services/payment.ts') // в начале модуля
function createPayment(amount) {
__traceFunctionCall('createPayment', 'src/services/payment.ts')
return db.insert({ amount })
}
При запуске теста глобальная функция __traceFunctionCall зарегистрирована Tracer'ом и сохраняет имя функции и путь файла в коллекцию.
Как расставляются трейс-сигналы:
Для трансформации кода используется Open Source библиотека Babel — она даёт доступ к AST (абстрактное синтаксическое дерево) JavaScript/TypeScript кода. С помощью AST мы:
Парсим исходный код и получаем его древовидное представление
Находим все объявления функций, методов классов, стрелочных функций
В найденных местах вставляем вызовы
__traceFunctionCall()или__traceModule()с нужными параметрами
Результат трассировки
После вызова tracer.stop() мы получаем объект:
interface TracingResult {
functions: string[] // список функций, например ['PaymentService | create', ...]
files: string[] // список файлов, например ['src/services/payment.ts', ...]
vue?: VueTrace[] // для фронтенда: массив Vue-компонентов
}
В files – все модули, реально выполнившиеся во время теста, включая даже те, что были заимпортированы косвенно (через другие модули).
В functions – именованные функции/методы, которые вызваны. Пока не используется в маппинге из-за ограничений TMS. В планах:
Включить функции в анализ для более детального маппинга
Добавить трассировку условных блоков (if-конструкций) для точной трассировки выполненных веток кода
Компонент 2: Allure + автоматический маппинг
Второй компонент — это связка Allure TestOps + библиотека метаданных. Это не просто хранилище тест-кейсов, а целая система:
Тест-разметка — через библиотеку Allure размечаем тесты метаданными (название, фича, компонент, настроение)
Тестовый результат — после прогона получаем детальный отчёт с трассировкой
ТМС для хранения связей — Allure TestOps хранит связи фича<->файлы<->тесты в одном месте
Почему разметка критична:
Без разметки тест — это просто код с проверками. С разметкой он становится:
Частью дерева тестов нашей TMS, корректно кластеризованного по фичам
Тест-кейсом с нормальным названием (не
test_payment_001, а "Создание платежа с токенизацией")Отчётом с понятными шагами и метаданными
Элементом системы, где фичи и модули связаны через трассировку
Тестовые результаты содержат не только статус (passed/failed), но и трассировку выполнения — какие файлы, функции или компоненты реально использовались. Это всё выгружается в Allure, и связь фича->файлы живёт в одной системе.
Связываем тесты с фичами
В каждом автотесте мы указываем фичу из предопределённого списка (TypeScript-тип). Например:
// packages/bk-allure-meta/index.d.ts
export type Feature =
| "Регистрация пользователя"
| "Авторизация пользователя"
| "Платежи"
| "Платежи. Пополнение"
| "Платежи. Вывод"
| "Ставки"
| "Ставки. Создание ставок"
// ... ещё 140+ фич
Пример: Backend-тест (Node.js, Mocha)
// test/_allure.ts
import { AllureTestProject } from '@sxl/qa-tools/allure'
import { Feature } from '@sxl/bk-allure-meta'
import tracer from './_tracer'
const allure = new AllureTestProject({
feature?: Feature | Feature[]
component?: string | string[]
mood?: 'positive' | 'negative'
})('DEV')
export const qa = {
async doc({ name, feature, component, suite, mood }) {
// Задокументировать тест (отправить метаданные в Allure)
await allure.documentation({
name,
fields: { feature, component, suite, mood },
})
},
// Обёртка для автоматического запуска/остановки трассировки
wrap(func) {
return async () => {
this.trace = tracer.start()
this.trace.pause()
try {
await func()
} catch (error) {
await this.traceStop()
throw error
}
await this.traceStop()
}
},
async traceStop() {
if (!this.trace) return
const result = this.trace.stop()
// Вытаскиваем трассировку: прикрепляем каждый файл как тег к тест-кейсу Allure
await allure.base.tags(...result.files.map(f => `<file> ${f}`))
this.trace = null
},
}
// В самом тесте:
test('Create payment', qa.wrap(async () => {
// Документация (метаданные теста)
await qa.doc({
feature: "Платежи. Пополнение",
component: "PaymentService",
mood: "positive",
})
// Запускаем трассировку перед действием
qa.trace.resume()
const payment = await createPayment({ amount: 100 })
qa.trace.pause()
// Управление трассировкой полностью завернуто в шаги, чтобы упростить написание и чтение кода. Но тут демонстрация оригинального API Tracer
// Проверки результатов
expect(payment.status).toBe('created')
}))
Здесь:
qa.doc— отправляет в Allure информацию о тесте: название, фичи, компоненты, настроение (позитивный/негативный сценарий).qa.wrap— обёртка для тест-функции: автоматически запускает Tracer (tracer.start()), а после выполнения теста останавливает его и прикрепляет результаты.allure.base.tags(...[`<file>...`])— низкоуровневый метод, добавляющий метки (теги) к тест-кейсу. Мы помечаем каждый выполненный файл тегом вида<file> path/to/file.ts.
Пример: Frontend-тест (Playwright + Vue)
// packages/wl-test-utils/playwright-runner.ts
import { AllureTestProject } from '@sxl/allure'
import { test as base } from '@playwright/test'
export const test = base.extend({
tracer: TracerFixture
})({
tracer: [
async ({ page }, use) => {
// Инициализируем tracer fixture для Playwright
const api = {
start: async () => {
await page.evaluate(() => { window.__tracer = window.__tracer.start() })
},
stop: async (): Promise => {
return await page.evaluate(() => { return window.__tracer.stop() })
},
}
await use(api)
// По завершении теста автоматически собрать и отправить трассировку
const result = await page.evaluate(() => window.__tracer.stop())
await allure.tracing(result) // отправляем данные в Allure
},
{ auto: true },
],
})
// В тесте:
test('Payment form submission', async ({ page, tracer }) => {
await allure.documentation({
fields: {
feature: "Платежи. Пополнение",
platform: 'desk',
mood: 'positive',
},
})
await page.gotoComponentStory('PaymentForm')
await tracer.start()
// Взаимодействие с UI компонента:
await page.fill('#amount', '100')
await page.click('#submit')
await expect(page.locator('.success')).toBeVisible()
// tracer.stop() вызван автоматически, данные отправлены в Allure
})
В Playwright-фреймворке мы использовали механизм Fixtures для интеграции Tracer:
tracer.start()иtracer.stop()делаются на стороне браузера (черезpage.evaluate), чтобы охватить выполнение Vue-компонентов.После теста
allure.tracing(result)сохраняет результат трассировки (файлы, компоненты) в Allure.
Что сохраняется в Allure TestOps
После прогона тестов, в Allure TestOps у нас появляется тест-кейс со связями:
{
"id": 12345,
"name": "Create payment",
"status": "passed",
"statusDetails": "...",
"parameters": [],
"steps": [ ... ],
"labels": [
{ "name": "Layer", "value": "Unit test" },
{ "name": "Framework", "value": "mocha" }
],
"workItems": [],
"customFields": [
{
"customField": { "name": "Feature" },
"name": "Платежи. Пополнение"
},
{
"customField": { "name": "Mood" },
"name": "positive"
}
],
"tags": [
"<file> src/services/payment/index.ts",
"<file> src/controllers/payment-controller.ts",
"<file> src/lib/db/index.ts"
]
}
Обратите внимание на tags: каждая запись вида <file> ... указывает файл, участвовавший в выполнении этого теста. Именно эти теги и являются автоматическим маппингом: тест -> файл -> фича.
Ключевая идея: самоподдерживающийся маппинг
При ручном подходе:
Изменили файл -> Нужно вручную обновить маппинг "Feature -> Files" -> Подобрать соответствующие тесты
↑
(легко забыть или сделать неверно) ❌
Наш подход:
Изменили файл -> (Если что-то ломается, падает тест) -> Исправили тест
↓
Прогнали тест снова
↓
Tracer собрал новые связи (файл <-> фича)
↓
Allure обновил маппинг автоматически ✅
Маппинг актуализируется как часть обычной работы над тестами. Если изменение кода нарушило логику – упадёт тест, разработчик его поправит, и при этом Tracer запишет новую связь. Если изменение просто изменяет цепочку импортов в рантайме — тоже все перезапишется автоматически. Никакой отдельной задачи «не забыть обновить список файлов фичи X» нет.
Как итог мы получаем примерно такую картину в TMS

Третий компонент – утилита, которая берёт git diff и на основе данных из Allure (тех самых <file> тегов) формирует список тестов для прогона.
Компонент 3: Как работает анализатор изменений
Пример вызова CLI:
npx @sxl/qa-git-changes-analyzer create-e2e-testplan \
--gitlab-token $TOKEN \
--environment-name by.prod-desktop \
-f testplan.env
Основные шаги алгоритма:
Шаг 1: Получить список изменённых файлов
# Определяем базовую ветку (master или последний деплой в prod)
git fetch origin master --depth 200
BASE=$(git merge-base FETCH_HEAD HEAD)
# Получаем список изменённых файлов между BASE и текущей веткой
git diff --name-only $BASE HEAD > changed_files.txt
Фильтруем интересующие нас файлы (исходники проекта):
src/services/payment/index.ts
src/services/payment/types.ts
src/controllers/payment-controller.ts
entities/wl-payment/PaymentForm.vue
packages/wl-core/api.ts
... и т.д.
Шаг 2: Найти связанные unit-тесты
Делаем запрос в Allure TestOps (RQL – query language) по тегам файлов:
const files = [
"src/services/payment/index.ts",
"src/controllers/payment-controller.ts",
// ...
]
const rql = `tag in [${files.map(f => `"\\ ${f}"`).join(', ')}]
and layer = "Unit test"
and status in ["Active"]`
const unitTests = await allureApi.getTestCases(rql)
// Получаем все тесты, у которых есть указанные файлы в тегах
Шаг 3: Выделить затронутые фичи
Из полученных тест-кейсов вытаскиваем уникальные фичи:
const features = new Set()
for (const test of unitTests) {
for (const cf of test.customFields) {
if (cf.customField.name === "Feature") {
features.add(cf.name)
}
}
}
// Например: features = { "Платежи. Пополнение", "Платежи. Вывод", "Платежи. Токенизация" }
Шаг 4: Найти соответствующие E2E-тесты
Теперь зная, какие фичи задеты, найдем все E2E тесты этих фич:
const rqlE2E = `cf["Feature"] in [${[...features].map(f => `"${f}"`).join(', ')}]
and layer = "E2e test"
and automation = true
and status in ["Active"]`
const e2eTests = await allureApi.getTestCases(rqlE2E)
// Все автоматизированные E2E тесты указанных фич
(Примечание: cf["Feature"] – специальный синтаксис Allure для поиска по кастомному полю.)
Шаг 5: Сформировать тест-план
Объединяем списки unit + E2E тестов и создаём в Allure TestOps тест-план:
const allTests = [...unitTests, ...e2eTests]
const testPlan = {
title: `Git-analyzer. build ${process.env.CI_PIPELINE_ID}`,
tests: allTests.map(t => ({ id: t.id }))
}
await allureApi.createTestPlan(testPlan)
В CI мы сохраняем полученный план в переменную окружения для дальнейшего использования в рамках реализации Continuous Delivery (пока в проработке):
echo "ALLURE_TEST_PLAN='${JSON.stringify(testPlan)}'" > testplan.env
Пример вывода анализатора
Важно: Каждый релиз даёт разную статистику в зависимости от того, какие файлы изменены, сколько их, и как они связаны с фичами. Ниже — реальный пример из одного из релизов.
================================================================================
ИТОГОВАЯ СТАТИСТИКА
================================================================================
[FILES] Всего файлов изменено: 75
[FEAT] Уникальных фич затронуто: 40
[UNIT] Unit-тестов для выполнения: 249
[E2E] E2E-тестов для выполнения: 81
---------------------------------------------------------------------------
[COV1] Файлы с фичами: 52 (69.3%)
[COV1] Файлы без фич: 23 (30.7%)
---------------------------------------------------------------------------
[COV2] Файлы с фичами и E2E: 44 (58.7%)
[COV2] Файлы без фич и E2E: 31 (41.3%)
---------------------------------------------------------------------------
[MANUAL] Ручных E2E (Approved): 15
[TOTAL] Общее количество тестов (текущий репо): 345
---------------------------------------------------------------------------
[WARN] Фичи с множественным воздействием: Raffle - ГСЧ, Идентификация, Идентификация. Видеоидентификация (Paydala), Главная страница. Управление шторкой, Подфт
================================================================================
>> СОЗДАНИЕ НОВОГО ТЕСТ-ПЛАНА В ALLURE
--------------------------------------------------
[MODE] Режим: СОЗДАНИЕ НОВОГО (NEW)
[NAME] Название: "Git-analyzer. v777.81 [y0k2pb]"
[PROJECT] Project ID: 7
[TESTPLAN] Тест-план ID: 1543
[TESTS] Всего тестов в плане: 345
[AUTO] Автоматизированных: 330
[MANUAL] Ручных E2E: 15
[OK] Тест-план успешно создан!
[URL] Ссылка: https://allure.stand.example/testplan/1543
Здесь:
[FILES] – сколько файлов изменилось в этом конкретном релизе.
[FEAT] – сколько уникальных фич затронуто.
[UNIT]/[E2E] – сколько тестов найдено для запуска по результатам анализа.
[TOTAL] – общее количество тестов в сформированном тест-плане (включая ручные).
[COV1] – метрика Feature Coverage Level 1: доля изменённых файлов, которые имеют связь с фичами (через хотя бы один тест). В этом примере 69.3% файлов «под колпаком» фич.
[COV2] – метрика E2E Feature Coverage: доля изменённых файлов, покрытых фичами, для которых существуют сценарные E2E‑кейсы (связь файлов с фичами формируется трассировкой unit/интеграционных/UI‑тестов). В этом примере 58.7%.
[WARN] – список фич, на которые изменение влияет сразу в нескольких местах. Это сигнал, что надо пристально проверить регрессию в этих областях.
Обратите внимание: Всего в проекте А — 7 080 тест-кейсов, но в этом конкретном релизе к запуску отобрано только 345 (≈5%) на основе изменённых файлов.
Интерпретация метрик покрытия
Feature Coverage (уровень 1) — показывает, какая доля изменённых файлов покрыта хотя бы одним автотестом, привязанным к бизнес-фиче. В примере из проекта А 69.3% файлов имеют такой маппинг. Остальные 30.7% файлов не имеют покрытия тестами со стороны разработчиков — это не «слепые зоны», а прямой сигнал нам и команде разработки, что нужно обратить внимание на процесс тестирования кода при разработке и устранить этот пробел.
E2E Feature Coverage (уровень 2) – сколько изменённых файлов имеют E2E‑тест(ы) на свои фичи. В примере: 58.7% – значит, больше половины изменений покрыта сквозными сценариями, остальное – только unit‑тестами (или вообще только manual, если автотестов нет). Эту метрику мы стремимся растить за счёт увеличения числа E2E‑тестов и расширения покрытия тестами разработчиков своего кода.
Обратите внимание: Эти метрики могут значительно различаться для каждого релиза! Где-то можно увидеть 72.7% или 54.5%, а в некоторых случаях покрытие фичами или E2E может быть и всего 15–10%. Всё зависит от того, какие файлы были изменены, насколько они новые, и много ли среди них кода, который уже давно покрыт тестами или только что появился без тестового покрытия.
«Диаграммы» воздействия
Анализатор также выводит списки наиболее затронутых файлов и фич. Пример из проекта А:
1. Вес по файлам (сколько уникальных фич затрагивает каждый изменённый файл):
================================================================================
ДИАГРАММА ВЕСА ПО ФАЙЛАМ
================================================================================
Вес по файлам (количество уникальных задетых фич)
1. src/core/injectors/service-map.ts ╢██████████████████████████████████████████████████████████████████████
2. src/modules/admin/reports/user-stats.rep.ts ╢█████████████████████████████████████████████████████
3. src/app/dashboard/routes/settings-main.route.ts ╢█████████████████████████████████████████
4. src/app/gateway/routes/carrot-flow.route.ts ╢█████████████████████████████████████████
5. src/app/admin/routes/user-approve.route.ts ╢███████████████████████████████████
6. src/controllers/kz/verify-approve.ctrl.ts ╢████████████████████████
7. src/controllers/kz-check/helpers/utils.ts ╢██████████████████
8. src/controllers/kz-check/entrypoint.ts ╢██████████████████
9. src/services/web/repository.repo.ts ╢██████████████████
10. src/app/api/routes/kz/validate-person.route.ts ╢████████████
11. src/project-services/kz/compare-data.ts ╢████████████
12. src/services/external/reporting/blr-sskk/sskk.rep.ts ╢████████████
13. src/vision/web/components/curtain-block.view.ts ╢████████████
14. src/app-events/handlers/carrot-handler.ts ╢██████
15. src/app/admin/routes/kz/user-checker.route.ts ╢██████
16. src/app/admin/routes/site-admin.route.ts ╢██████
17. src/app/admin/routes/top-entity-group.route.ts ╢██████
18. src/app/api/routes/root.route.ts ╢██████
19. src/controllers/free/bonus-activate.ctrl.ts ╢██████
20. src/services/raffles/constants.ts ╢██████
21. src/services/raffles/index.ts ╢██████
22. src/services/raffles/init-module.ts ╢██████
23. src/services/raffles/storage.repo.ts ╢██████
24. src/vision/admin/components/slider-search.view.ts ╢██████
25. src/app/cron/jobs/freebet-expiration.job.ts ╢
26. src/app/cron/jobs/kz-compare-retry.job.ts ╢
27. src/app/tasks/core-single/index.ts ╢
28. src/app/tasks/core-single/randomizer.task.ts ╢
29. src/config/schema/config.model.ts ╢
30. src/constants/events/admin-types.ts ╢
31. src/constants/permissions/admin-list.ts ╢
32. src/constants/base.ts ╢
╚══════════════════════════════════════════════════════════════════════
2. Вес по фичам (сколько изменённых файлов пришлись на каждую фичу):
Пример из проекта Б:
================================================================================
ДИАГРАММА ВЕСА ПО ФИЧАМ
================================================================================
Вес по фичам (количество затронутых файлов)
1. Raffle - ГСЧ ╢██████████████████████████████████████████████████████████████████████
2. Идентификация ╢████████████████████████████████████████████████████████████
3. Идентификация. Видеоидентификация (Paydala) ╢██████████████████████████████████████████████████
4. Главная страница. Управление шторкой ╢██████████████████████████████████████████████████
5. Подфт ╢████████████████████████████████████████
6. Программа лояльности ╢██████████████████████████████
7. Управление клиентами. Карточка клиента ╢████████████████████
8. Системные настройки ╢████████████████████
9. Группировка пользователей ╢████████████████████
10. Бонусные теги ╢████████████████████
11. СККС ╢████████████████████
12. Идентификация. Обработка запроса ╢████████████████████
13. События и линии. Главная страница. Управление шторкой ╢████████████████████
14. События и линии. Управление стейтами событий ╢██████████
15. Партнерская программа Admon ╢██████████
Proof of Concept: объективная метрика покрытия всего проекта
Ключевой вопрос из раздела «Проблема»: как объективно измерить, какой процент бизнес‑логики покрыт E2E‑тестами?
Теперь мы можем ответить на него.
Что у нас есть:
-
Все модули проекта (по фильтрам) — файлы с исходным кодом в директории с бизнес-логикой (например,
src/), отфильтрованные по паттернам:Исключаем модули, не участвующие в бизнес-сценариях (не вызываются в цепочке вызовов, которая инициализируется через API приложения)
Оставляем только модули, которые мы определяем как бизнес-логику
Фильтры гибко настраиваются под проект
Пример: получилось 2 500
.tsфайлов
-
Модули в базе Allure — файлы, которые хотя бы раз встречаются в тестах с фичами (хранятся как теги
<file>)Пример: 1 750 файлов
-
Модули, покрытые E2E — файлы, которые прогоняются в E2E-тестах
Пример: 1 475 файлов
Считаем покрытие проекта:
Всего модулей проекта (по фильтрам): 2 500 файлов
Модулей в базе Allure (с фичами): 1 750 файлов
──────────────────────────────────────────────────
Feature Coverage проекта: 70% (1750/2500)
Всего модулей проекта (по фильтрам): 2 500 файлов
Модулей, покрытых E2E: 1 475 файлов
──────────────────────────────────────────────────
E2E Coverage проекта: 59% (1475/2500)
Вот они — объективные метрики!
Не просто «85% строк выполнились» (code coverage), а:
Feature Coverage: 70% — большая часть бизнес-модулей привязана к фичам через тесты. Остальные 30% либо не покрыты тестами, либо тесты не помечены фичами.
-
E2E Coverage: 59% — больше половины бизнес-модулей прогоняется в реальных пользовательских сценариях (E2E), проверяющих:
Логику самого модуля
Интеграцию с другими сервисами
Контракты между компонентами
Взаимную работу фронтенда, бэкенда, БД, внешних API
Это метрики другого уровня. Они показывают, насколько проект готов к частым релизам с точки зрения покрытия реальных сценариев.
Что НЕ решает этот подход:
Остаётся вопрос: «Достаточно ли у нас тестов, чтобы считать фичу полностью покрытой с точки зрения требований?»
Это уже другая история:
Требует декомпозиции требований на тест-кейсы
Нужен анализ полноты покрытия требований тестами
Наш подход решает другое: связываем код -> фичи -> тесты автоматически, измеряем покрытие модулей. Но полноту покрытия требований фичи — это отдельная работа, о которой, возможно, как-нибудь потом.
Практическое применение:
Можем ставить цели: «Поднять E2E Coverage проекта с 59% до 75% за квартал»
Видим прогресс: каждый новый E2E-тест увеличивает покрытие, и это измеримо
Принимаем решения о релизах: «E2E Coverage изменений > 50% -> можно пробовать автоматизировать выкат в prod без ручных регрессов»
Рентген-эффект: переосмысление пирамиды тестирования
Получив метрику E2E Coverage бизнес-логики, мы получаем свободу в построении пирамиды тестирования.
Классический подход:
«E2E-тестов должно быть мало — они дорогие, медленные, сложные в поддержке. Ограничиваем их количество самыми критичными сценариями.»
Наш подход:
«Пишите столько E2E, сколько нужно для покрытия бизнес-логики. Селективный запуск сам решит, когда их гонять.»
Раньше мы ограничивали количество E2E из-за:
Времени прогона (часы на полный регресс)
Стоимости инфраструктуры
Теперь эти ограничения не так критичны:
Селективный запуск гоняет только релевантные тесты (17–42% от всех)
Объективная метрика показывает, достаточно ли E2E для автоматизации релизов
Можем расти в E2E без страха, что прогоны станут невыносимо долгими
Рентген-эффект unit и интеграционных тестов:
Но что не менее важно — это переосмысление роли других уровней пирамиды: тестов в изоляции от части или всей инфраструктуры. Речь о unit, интеграционных, компонентных и других подобных тестах. Они теперь важны не только для быстрой обратной связи разработчикам, но и как "рентген", прошивающий цепочки модулей.
Представьте:
Разработчик пишет unit-тест для функции в модуле
payment.tsПомечает тест фичей «Платежи. Пополнение»
Прогоняет тест -> Tracer записывает всю цепочку выполненных модулей:
payment.ts->card-token.ts->take-my-money-bitch.ts->db.lib.ts->validation.tsВсе эти модули автоматически тегируются фичей «Платежи. Пополнение» в Allure
Один раз прогнали тест — "просветили рентгеном" всю цепочку.
Это не ручные аннотации в начале файлов (типа @feature Платежи), где нужно не только угадывать или анализировать, но и постоянно обновлять. Это автоматический маппинг через выполнение пользовательских сценариев на уровне изолированного приложения.
Результат:
Теперь вся система — unit, интеграционные, E2E — работает как единая самоподдерживающаяся экосистема:
Unit и интеграционные тесты "прошивают" модули фичами в рамках репозитория и дают быструю обратную связь при разработке
E2E на тех же "тегах" фичей проверяют сквозные сценарии через несколько сервисов
Маппинг фича -> модули -> тесты всей пирамиды обновляется автоматически при каждом прогоне
Анализ построен на прозрачной логической цепочке, а не на предположениях
Можем писать тысячи E2E, интеграционных, unit, компонентных тестов, зная, что система сама разберётся, какие из них нужны в конкретном релизе.*
* См. раздел «Ограничения и слепые пятна» в конце статьи.
Может возникнуть вопрос: почему бы не трассировать код прямо во время запуска E2E-тестов на реальном окружении? Ответ: проблема фонового шума.
В изолированных тестах выполняется только та логика, которая реально отвечает за конкретный кейс. На фронтенде мы не обрабатываем события других компонентов, не отрисовываем то, что не относится к тестируемому сценарию. На бэкенде не работают фоновые таски, воркеры, планировщики — только точка входа, которую вызывает тест, и цепочка её зависимостей.
Это ключевая идея, делающая трассировку чище и точнее. Не появляются лишние модули, которые просто "работают фоном", но не имеют отношения к проверяемому сценарию. Приятный бонус: дисциплина поддержки пирамиды тестирования.
Отметим: трассировка на уровне отдельных микросервисов в интеграционных тестах звучит перспективно — когда приложение интегрировано с реальной инфраструктурой в сповокупе с микро-сервисами, которые будут одновременно писать артефакты трассировки. Однако трассировка всего приложения с UI с множеством параллельных фоновых процессов даст слишком много шума и ложных связей.
Интеграция в CI/CD: как система работает на практике
Коротко: как это устроено в GitLab CI.
Backend: Docker-образ с трансформацией
Для бэкенда мы собираем специальный Docker-образ, в котором код уже трансформирован:
build-test-image:
stage: build
script:
- docker build --target=test -t $IMAGE_NAME .
- docker push $IMAGE_NAME
В Dockerfile есть отдельная стадия test:
FROM base AS test
WORKDIR /app
RUN sh ./transform.sh --ci
Скрипт transform.sh в CI-режиме трансформирует код прямо на месте (локально мы создаём копию в ./transformed, чтобы не портить рабочие файлы):
if [ "$1" = "--ci" ]; then
npx tracer --outDir . || exit 1
else
# Локально: создаём ./transformed
rsync -a ./ ./transformed/
cd ./transformed && npx tracer --outDir .
fi
Дальше запускаем тесты в этом контейнере:
unit-tests:
stage: tests
image: $CI_REGISTRY_IMAGE/corm:$CI_COMMIT_REF_SLUG-$CI_PIPELINE_IID-test
variables:
TRACER_ENABLED: "true"
before_script:
- npm run migrate-latest
- curl -LsSo ./allurectl https://github.com/allure-framework/allurectl/...
- chmod +x ./allurectl
script:
- ./allurectl watch --silent --results allure-results -- npm run coverage:ci
TRACER_ENABLED=true включает трассировку. AllureCTL автоматически выгружает результаты в Allure TestOps, включая все собранные теги <file>.
Frontend: Storybook + Playwright
Для фронтенда процесс похожий, но вместо Docker мы трансформируем Storybook перед сборкой:
build:storybook:transformed:
stage: .pre
script:
- yarn install --immutable
- yarn prepare
- yarn workspace @st/storybook build-storybook:transformed
artifacts:
paths:
- "apps/storybook/storybook-static/"
Внутри скрипта сборки (**/storybook/scripts/build.mjs) происходит трансформация и сборка:
// В CI: трансформируем код "на месте"
execSync('yarn tracer --outDir . --config tracer.config.cjs', { cwd: repoRoot })
// Собираем Storybook
execSync('NODE_ENV=development TRACER_ENABLED=true npx storybook build', { cwd: sbPkg })
Playwright-тесты запускаются с включённой трассировкой:
test:playwright:
stage: tests
parallel: 3
variables:
TRACER_ENABLED: "true"
script:
- yarn install --immutable
- yarn prepare
- ln -sf $STORYBOOK_BUILD_DIR packages/st-storybook-utils/storybook-static
- ./allurectl watch --silent -- yarn test:playwright --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL
Git Changes Analyzer: генерация тест-плана
Самое интересное — это анализатор изменений. Он запускается отдельным шагом:
git-changes-to-testplan:
stage: testplan
when: manual
script:
- npx --yes @sxl/qa-git-changes-analyzer@latest \
create-e2e-testplan \
--gitlab-token $GIT_CHANGES_ANALYZER_TOKEN \
-f testplan.env
artifacts:
reports:
dotenv: testplan.env # Сохраняет ALLURE_TEST_PLAN
При необходимости фильтры по окружению передаются параметром --environment-name.
Анализатор сравнивает текущий коммит с базовым (git diff), обращается в Allure TestOps за маппингом файлы <-> фичи <-> тесты, формирует тест-план и сохраняет его в переменную окружения.
Делаем этот шаг manual, чтобы не гонять на каждый push, но на релизных ветках можно включить автоматически.
Реальные результаты: цифры из боевых проектов
Теперь к самому интересному — что дала система на практике. Без конкретики и цифр это была бы просто теория.
Разные проекты, разная статистика по тест-кейсам
У нас работают два основных проекта:
Проект А (первая букмекерская платформа):
Всего тест-кейсов: 7 080
Автоматизация: 59.48% (4 211 авто)
Ручные: 2 869
Фич в TMS: 100+
Проект Б (вторая букмекерская платформа):
Всего тест-кейсов: 4 685
Автоматизация: 79.36% (3 718 авто)
Ручные: 967
Фич в TMS: 60+
Важная ремарка: Дальнейшие цифры — это примеры из конкретных релизов. От релиза к релизу результаты будут разными в зависимости от того, какие файлы изменены, сколько их, как они связаны с фичами, и насколько эти файлы покрыты тестами.
Релизы проекта А
Начнем с менее оптимистичного примера релиза. Это реальный релиз на проекте А, включающий как фронтенд-, так и бэкенд-изменения:
Frontend-релиз (1 263 изменённых файла):

Backend-релиз (75 изменённых файлов):

Фичи с множественным воздействием (backend):
Raffle - ГСЧ
Идентификация
Идентификация. Видеоидентификация (Paydala)
Главная страница. Управление шторкой
Подфт
Фичи с множественным воздействием (frontend):
События и линии
Профиль игрока
Регистрация пользователя
Идентификация
Программа лояльности. Cashback
Мерж тест-планов и итоговое время регресса:
Для релиза мы объединяем тест-планы фронтенда и бэкенда в один общий план:
Автоматизированные E2E-тесты, селективно запущенные по изменениям фронта и бэкенда: ~20-25 минут
Ручные E2E-тесты (15 + 15 = 30 ручных кейсов): ~1-2 часа
Итого на полный регресс: ~2-2.5 часа
Даже такое покрытие изменений позволяет принять решение о выкате в production за несколько часов вместо нескольких дней исследовательского тестирования.
Регресс-менеджер может исключать некоторые ручные кейсы из проверки в зависимости от характера изменений. Например, если кейсы являются вариациями позитивных путей, и хотя бы один позитивный сценарий уже проверен — вероятность регрессии в вариациях будет ниже.
На практике, при покрытии изменений E2E-автотестами в 70%+, можно принять риск и катить в продакшн только на основании автотестов, без ручной проверки. Разумеется, лучше увеличивать E2E-покрытие — и тут расширенные сквозные метрики помогают расставлять приоритеты.
Принятие решения о релизе:
При низком покрытии (как в этом примере: COV1 27.6-32%, COV2 18.4-18.7%) решение принимается с учётом:
-
Характер изменений:
Форматирование кода, обновление линтера, рефакторинг без изменения логики -> низкий риск
Функциональные изменения бизнес-логики -> высокий риск, требуется дополнительное ручное тестирование
-
Зоны риска:
Фичи с множественным воздействием требуют особого внимания
Файлы без покрытия — под ответственность того, кто делает изменения
-
Итоговое решение:
Релиз помечается как рискованный
Может потребоваться расширенный ручной регресс
Такой релиз точно не катим в пятницу вечером :)
Релизы проекта Б
Далее рассмотрим более оптимистичный релиз, где покрытие получилось значительно выше — как по фичам, так и по E2E. Это отличный результат, к которому мы стремились: тесты покрывают большую часть функционала, а любые изменения автоматически трассируются к нужным сценариям.
Frontend-релиз (76 изменённых файлов):

Фичи с множественным воздействием (frontend):
Платежи (11 файлов)
Бонусы. Бонус за депозит (9 файлов)
Регистрация пользователя (7 файлов)
Авторизация (6 файлов)
Бонусы. Cashback (6 файлов)
Backend-релиз (34 изменённых файла):

Запущено 38% от общего количества тестов проекта (1 790 из 4 685).
Примеры «тяжёлых» файлов (из детального анализа backend):
Файл |
Фичи |
Unit-тесты |
E2E-тесты |
|---|---|---|---|
|
50 |
1 642 |
180 |
|
18 |
225 |
40 |
|
12 |
121 |
60 |
|
8 |
149 |
26 |
|
8 |
52 |
54 |
Видите src/lib/db.lib.ts? Один файл утилиты для работы с БД затрагивает 50 разных фич! Это может быть несущественное изменение без влияния, а может оказаться, что для разных фич оно повлияет по-разному — нужно разбираться. Но так или иначе, наше внимание уже привлечено: что делать дальше — решать нам.
Фичи с множественным воздействием (backend):
[Admin] Бонусы (11 файлов)
[Admin] Клиенты (7 файлов)
*Скрыто* (6 файлов)
Платежи (6 файлов)
Идентификация KYC (5 файлов)
Мерж тест-планов и итоговое время регресса:
Для релиза объединяем тест-планы фронтенда и бэкенда:
Автоматизированные E2E-тесты (frontend + backend): ~20 минут
Ручные E2E-тесты (44 + 62 = 106 ручных кейсов): ~2-2.5 часа на всю команду или можно пропустить, если покрытие позволяет
Итого на полный регресс: ~2.5-3 часа с ручными тестами, 20 минут если положиться на автотесты и покрытие
Но все же при таком высоком покрытии (COV1 69.7-79.4%, COV2 43.4-67.6%) можно с гораздо большей уверенностью выкатывать в production после успешного прохождения тестов.
Что показывают метрики
Как видите, результаты сильно различаются даже между релизами одного проекта:
Проект А: COV1 от 27.6% до 32%, COV2 от 18.4% до 18.7%
Проект Б: COV1 от 69.7% до 79.4%, COV2 от 43.4% до 67.6%
Что означают эти цифры:
Еще раз определение метрик и расшифровка:
Feature Coverage Level 1 (COV1) — показывает, какая доля изменённых файлов имеет хотя бы один тест, помеченный фичей.
Низкий COV1 (27.6-32% в проекте А) -> много файлов без тестов вообще, либо тесты есть, но не помечены фичами. Это сигнал о техническом долге: нужно дописать тесты или разметить существующие.
Высокий COV1 (69.7-79.4% в проекте Б) -> большая часть изменённых файлов прогоняется через тесты, привязанные к бизнес-фичам.
E2E Feature Coverage (COV2) — показывает, какая доля изменённых файлов покрыта фичами, имеющими сценарные E2E‑кейсы.
Низкий COV2 при низком COV1 -> вообще мало тестов. Нужно дописывать и unit, и E2E.
Низкий COV2 при высоком COV1 -> много unit/интеграционных тестов, но мало сценарных E2E. Либо это новая функциональность (E2E ещё не написаны), либо нужно усилить сценарное покрытие.
Высокий COV2 (67.6% в проекте Б backend) -> 2/3 изменений прогоняются через полные пользовательские пути.
От релиза к релизу результаты разные:
Один релиз может затронуть 75 файлов с хорошим покрытием -> высокий COV1/COV2.
Другой релиз может затронуть 1 263 файла, из которых много legacy -> низкий COV1/COV2.
Система не "оценивает" проект, она показывает объективную картину:
Где технический долг
Где не хватает E2E
Какие фичи в зоне риска
На что обратить внимание
Раньше мы этого не видели. Теперь видим — и можем планировать работу по улучшению.
Что это дало на практике: как мы решили заявленные проблемы
Теперь, когда мы прошли весь путь от проблемы до реализации и реальных цифр, давайте подведём итоги. Помните три проблемы из начала статьи? Давайте посмотрим, как наша система их закрыла.
Решение Проблемы 1: Селективный запуск без компромиссов
Вариант А (запускать всё) — долго, дорого, нет ответа "достаточно ли покрыто"
Вариант Б (только smoke) — быстро, но рискованно
Вариант В (ручной выбор) — субъективно, медленно
Вариант Г (положится на code coverage или графы зависимости монорепо) — ограничивается слоем "низкоуровневых" тестов
Что мы получили:
Автоматический селективный запуск, который знает:
Какие файлы изменены (
git diff)Какие фичи затронуты (через маппинг файл -> фича)
Какие тесты покрывают эти фичи (unit + интеграционные + E2E)
Результаты в цифрах:
Проект А: из 7 080 тестов запущено 345-1 053 (в зависимости от релиза) -> 15-20 минут
Проект Б: из 4 685 тестов запущено 412-1 790 (в зависимости от релиза) -> ~20 минут
Прирост производительности в несколько раз без потери качества.
В чём фишка:
Мы не просто "запустили меньше тестов". Мы запустили именно те, которые проверяют изменённую функциональность — от unit до E2E. Система сама подобрала релевантные тесты по всей пирамиде.
Решение Проблемы 2: Покрытие по всей пирамиде, а не «голые цифры»
Помните вопрос: "Достаточно ли покрыто изменение для безопасного релиза?"
Классический code coverage говорит: "95% покрыто" - какие тесты являлись релевантными, что по другим слоям?
Что мы получили:
Многоуровневую систему метрик:
Feature Coverage Level 1 (COV1) — какая доля файлов связана с фичами через тесты, основанные на требованиях, через всю пирамиду тестирования
E2E Feature Coverage (COV2) — какая доля файлов относится к фичам, у которых есть сценарные E2E‑кейсы
Статистика по файлам и фичам при каждом релизе — можно оценить — модули, затрагивающие десятки фич, так можно увидеть и сами фичи, которые "задеты" множеством модулей - наши дополнительные инструменты контроля
Можно задавать вопросы и ставить задачи:
Достаточно ли E2E для релиза? -> Смотрим COV2
Где технический долг? -> Смотрим низкий COV1 со списком конкретных модулей
Где много unit, но мало E2E? -> COV1 высокий, COV2 низкий (возможно, новая функциональность)
И самое важное: можем проследить связи:
Файл изменён -> какие фичи затронуты -> какие тесты покрывают -> какого уровня эти тесты
Это не "голые цифры", а реально полная карта связей кода, фич и всех уровней тестирования.
Решение Проблемы 3: Частые релизы с объективными метриками
Помните расчёт из начала?
Релиз раз в месяц -> 2-3 дня на тестирование
Релиз раз в неделю -> 4-6 часов
Релиз ежедневно -> 20-30 минут
Релизы когда угодно -> нужен автоматический Quality Gate
Что мы получили:
Создание регрессионного тест-плана за несколько кликов вместо тройки часов изучения состава релиза.
Полный регресс за 2-2.5 часа (автотесты 20 мин + ручные E2E 1.5-2 часа) вместо пары дней совокупности всех мероприятий регрессионного тестирования.
Объективные метрики для принятия решений:
При высоком покрытии (COV2 67.6%):
-> Можем с уверенностью выкатывать в production
При низком покрытии (COV2 18.4%):
-> Смотрим на характер изменений:
- Форматирование, линтер -> низкий риск
- Функциональные изменения -> высокий риск, нужны доп. проверки
-> Релиз помечается как рискованный
-> Точно не катим в пятницу вечером :)
Главное: у нас гораздо больше данных для принятия решений:
Какие фичи затронуты
Какой процент связан с фичами, имеющими E2E‑сценарии
Какие зоны риска
Какой характер изменений
Это и есть тот самый Quality Gate, который позволяет делать релизы чаще и безопаснее. А если принять COV2 > 60% как достаточный для решения о деплое без дополнительных ручных проверок, то это и есть автоматический Quality Gate, но всё же нам есть куда расти в покрытии, и я бы сделал планку повыше.
Test Impact Analysis: что мы расширили
Итого как мы расширили TIA‑методологию:
1. Сквозная runtime-трассировка через всю пирамиду тестирования
Классический TIA обычно работает в рамках одного репозитория. У нас микросервисная архитектура: Frontend (Vue, Nuxt), Backend (Node.js) и другие сервисы на ноде, с которыми взаимодействует клиентский бэк.
Нам нужна сквозная трассировка:
Связка тестов фичи "Регистрация пользователя":
-> unit/интеграционные тесты фронтенда трассируют компоненты и модули UI
-> unit/интеграционные тесты бэкенда трассируют контроллеры и доменные сервисы
-> модульные/интеграционные тесты микросервиса трассируют соответствующую логику
-> E2E‑тесты сценарные и привязаны к той же фиче
-> все файлы и сервисы оказываются связаны с фичей через эти тесты, формируя пирамиду тестирования
2. Хранение маппинга через систему управления тестами
Маппинг "фича -> тесты -> файлы" хранится не в отдельной базе, а прямо в TMS как теги <file>. Тесты сами документируют, какой код они покрывают.
3. Автоматическая актуализация маппинга
Маппинг обновляется автоматически при каждом прогоне тестов. Переименовали файл, разделили модуль, изменили логику — при следующем запуске связи обновятся сами. Никакого дополнительного труда для поддержки маппинга.
4. "Фичирование"
Связь кода с бизнес-фичами, а значит и с требованиями.
Базовая TIA работает на уровне модулей:
git diff -> изменённые файлы -> тесты, импортирующие эти файлы
Нам нужна связь с бизнес-логикой:
git diff -> изменённые файлы -> фичи -> все тесты фичи (unit + интеграционные + E2E)
Это позволяет отвечать на вопросы в терминах бизнеса, оперируя фичами, которые напрямую связаны с требованиями, а не "голыми" цифрами code coverage или селективно запущенными unit-тестами.
5. Анализ покрытия изменений на всех уровнях
Видим покрытие измененных модулей тестами всех уровней пирамиды — в первую очередь E2E. Можем селективно запускать только релевантные тесты, найденные для данных измененных модулей.
Такое вот расширение методологии TIA для задач релизного тестирования в мультирепозиторной архитектуре с (requirement-based*) подходом к тестированию.
* Requirement-based testing (тестирование на основе требований) — подход, когда тесты организованы на основе бизнес-требований (фич), а не просто для покрытия кода.
Вся пирамида тестирования в единой системе
Одно из ключевых бонусов работающей системы.
Раньше у нас были:
Unit-тесты — для разработчиков
Интеграционные — проверка связок
E2E — проверка сценариев на всей инфре
Ручные кейсы — для регресса QA и приемки
Все жили отдельно. Разработчик из команды "Альфа" пишет тесты одним образом, разработчик из команды "Браво" не пишет их вовсе, а "Гамма" всей командой решили, что их тесты должны называть по типу "test_A_12345_payment-check". Никакой общей картины.
Теперь:
Все уровни используют общий инструмент трассировки (Tracer)
Все тесты размечаются общими правилами и используют типизированные названия фичей (единый справочник типов)
Все результаты в одной TMS (Allure TestOps)
Все связи автоматически обновляются при каждом прогоне
Мы получили единую самоподдерживающуюся экосистему:
Unit и интеграционные тесты "прошивают" модули фичами
E2E прошивают сквозные сценарии через несколько сервисов
Маппинг фича -> модули -> тесты всей пирамиды живёт автоматически
Анализ построен на прозрачной логической цепочке
И самое важное — контроль. Видим полную картину: какой процент изменений покрыт unit, какой — интеграционными, какой — E2E. Принимаем решения на основе данных, а не интуиции.
Неожиданный бонус: Культура тестирования как естественное следствие системы
Это неожиданный, но очень важный эффект.
Проблема, которую мы не планировали решать таким образом:
Как увеличить культуру автотестирования внутри всего департамента QA и всей разработки? Это всегда живёт на фоне, но здесь система неожиданно помогла.
Что было раньше:
Разработчики писали тесты как хотели, размечали их как хотели. Тест-дизайн никакой не предполагался. Тест-кейсы иногда было сложно вычитать из этих тестов — некоторые были монстрозными по объему проверок и действий, некоторые просто ничего не проверяли. Не было систематизации и централизации подхода к работе с тестами.
Что изменилось:
Необходимость проставлять аннотации к существующим тестам и погружение в тесты через их разметку создали прецедент: теперь каждый, кто разрабатывает тесты, для правильного наименования и проставки мета-данных постоянно задаёт себе вопрос — "Что мой тест проверяет?"
Это погружение сильно увеличило экспертизу внутри команды. Многие в QA-департаменте научились писать полноценные тесты именно в процессе осознания тест-кейсов — когда мы массово покрывали уже существующие тесты разметкой и трассировкой.
Объединение всех команд:
Автотестеры и разработчики теперь работают в общей системе, где всё делается абсолютно системно. Не каждый сам по себе, а единый подход к написанию, разметке и документированию тестов всех уровней.
Что изменилось после внедрения системы:
Система создала естественную необходимость вести пирамиду тестирования не "просто так", а для конкретных целей:
-
Unit-тесты теперь не просто для разработчика:
Они "прошивают" файлы фичами автоматически
Данные тесты прекрасно подходят для автоматизации негативных сценариев
-
Аннотации фич стали критичны:
Без
qa.doc({ feature: "..." })тест не попадёт в статистикуCOV1 будет низким -> команда увидит проблему
Копипаст фичи -> tracer покажет несоответствие (тест помечен "Платежи", а файлы платежей не выполнялись)
-
E2E-тесты теперь измеримы:
Видим, сколько процентов изменений они покрывают (COV2)
Можем ставить цели: "Поднять E2E Coverage с 43% до 60% за квартал"
Каждый новый E2E -> измеримый рост покрытия
-
Взаимная работа и ответственность:
Разработчики видят свои зоны без покрытия
QA видят, где не хватает E2E
Менеджмент видит объективные метрики
Все работают с одной системой координат
Результат:
В команде появилась культура проверки:
Проверяют, что тесты правильно аннотированы
Проверяют, что unit-тесты реально выполняют код и делают ассерты согласно кейсу
Достаточность аннотированных тестов у фичей
Это не "процессы и политики", которые нужно навязывать. Это естественное следствие наличия объективных, прозрачных метрик.
Когда команда видит:
COV1: 27.6% — только четверть файлов связана с тестами
COV2: 18.4% — менее 1/5 покрыто E2E
Она сама понимает: нужно что-то менять. Не потому что "начальник сказал", а потому что данные показывают проблему.
Итого бонусы данной системы:
Тесты нижних уровней стали полезны не только разработчикам, но и бизнесу
Решения о релизах стали объективными, а не субъективными
Технический долг стал видимым и измеримым
Ограничения и планы развития
Как и любая система, наша имеет ограничения. Важно их понимать и знать, как с ними работать.
Что не идеально
1. Требуется трансформация кода
Мы встраиваем трассировщики прямо в исходники — это дополнительный шаг сборки. Потенциально может что-то сломать, если в плагине баг. Пока обкатываем на всех проектах, всё автоматизировано в CI. В будущем, возможно, сделаем трассировку иначе.
2. Небольшой overhead
Вставленные вызовы __traceFunctionCall занимают немного времени. Поэтому трассировка включена только в CI (TRACER_ENABLED=true), в production её нет. На CI несколько секунд overhead — мелочь по сравнению с экономией часов.
3. Feature указывается вручную
Разработчик теста обязан пометить тест фичей — иначе откуда система узнает? Но мы облегчили задачу:
Типы
Featureхранятся централизованно, TypeScript не даст написать что-то не тоМожно добавить линтер, проверяющий наличие
qa.doc({ feature: ... })
4. Слепые пятна: асинхронные зависимости
Представьте тест, который через модуль A кладёт данные в БД, а в реальной системе эти данные читает крон-задача через модуль B. Но в тесте модуль B не вызывается.
Результат: Модуль B не будет связан с фичей. Если его изменить, TIA не предложит запустить этот тест.
Решение: Писать тесты, проверяющие полный цикл (запись + чтение).
5. Распределённые сценарии
В микросервисной архитектуре: сервис A отправляет событие в очередь, сервис B обрабатывает его. Тест в репозитории A не запускает сервис B.
Результат: Изменения в обработчике сервиса B не будут связаны с фичей из сервиса A.
Решение: низкоуровневые сценарные тесты, запускающие несколько сервисов одновременно.
6. Недостаток тестов
Если у модуля нет тестов или тесты не помечены фичами — он не попадёт в маппинг.
Решение: Растить покрытие. Метрика Feature Coverage проекта (70% в нашем примере) показывает прогресс. Никакой магии тут быть не может. Как говорится, покрытие - это база.
Принцип: полное тестирование невозможно
Вспомним фундаментальный принцип тестирования:
Исчерпывающее тестирование невозможно.
Проверить все возможные комбинации входных данных, состояний системы и окружений физически нереально.
Наш подход не решает эту проблему полностью (никто не решает). Но он делает максимум возможного:
Автоматизирует маппинг фича -> модули -> тесты
Измеряет покрытие объективно
Направляет усилия туда, где покрытие слабое
Мы стремимся к максимальному покрытию, понимая, что идеала достичь невозможно. Но даже при 59% E2E Coverage бизнес-логики мы получаем огромный шаг вперёд по сравнению с «надеемся, что ничего не сломали».
Заключение
Мы прошли путь от проблемы селективного запуска и оценки покрытия до единой системы, которая автоматически связывает код, фичи и тесты.
Что получилось
Автоматическая связь кода, фич и тестов — за счёт наличия размеченных тестов
Самоподдерживающийся маппинг — обновляется при прогоне тестов
Прогоны можно ускорять в разы (от 17% до 42% тестов всех уровней вместо 100%)
Объективные метрики E2E-покрытия — решения о релизе на основе данных, а не интуиции
Зоны риска — видим, какие фичи затронуты сильнее всего
Универсальность — работает для backend и frontend
Интеграция в CI/CD — не требуется ручной работы, кроме поддержки тестов
Вся пирамида тестирования в единой системе — от unit до E2E
Результаты в цифрах
Общая статистика проектов:
Метрика |
Проект А |
Проект Б |
|---|---|---|
Всего тест-кейсов |
7 080 |
4 685 |
Автоматизация |
59.48% (4 211) |
79.36% (3 718) |
Фич в TMS |
100+ |
60+ |
Примеры релизов (реальные данные из production):
Метрика |
Проект А (frontend) |
Проект А (backend) |
Проект Б (frontend) |
Проект Б (backend) |
|---|---|---|---|---|
Изменено файлов |
1 263 |
75 |
76 |
34 |
Затронуто фич |
69 |
40 |
25 |
50 |
Запущено тестов |
1 053 |
345 |
412 |
1 790 |
Feature Coverage (COV1) |
27.6% |
32% |
69.7% |
79.4% |
E2E Feature Coverage (COV2) |
18.4% |
18.7% |
43.4% |
67.6% |
Время прогона |
~20 мин |
~15 мин |
~20 мин |
~20 мин |
Важно: Метрики варьируются от релиза к релизу в зависимости от того, какие файлы изменены и насколько они покрыты тестами!
Главное достижение: путь к Continuous Delivery
Раньше перед каждым релизом приходилось часами вручную собирать регресс-тест-план, потом прогонять все тесты (ручные и автоматизированные) и долго ждать результатов. В feature-ветках ограничивались только smoke-тестами, чтобы не тратить время. И всё равно не было объективного ответа на простые вопросы — достаточно ли протестирован этот релиз? Какой процент изменений реально покрыт полными пользовательскими сценариями? Где наши слабые места?
Без этого было невозможно организовать полноценный Continuous Delivery — когда любые изменения можно быстро и безопасно катить в production.
Теперь мы получили прозрачность и контроль. Система сама подбирает релевантные тесты для конкретных изменений, сохраняя баланс между скоростью и качеством. Мы видим цифры — 18% или 67% E2E-покрытия изменений — и можем осознанно принимать решение о релизе, а не полагаться на интуицию.
Самое ценное — это возможность быстро принимать решения о качестве релиза по автоматическим метрикам. Видим объективные данные, оцениваем риски, принимаем решение — и делаем релиз. Всё это за минуты, а не дни. Именно это открывает дорогу к полноценному Continuous Delivery, где релизы можно делать так часто, как требует бизнес.
Приятный бонус — вся пирамида тестирования теперь работает как единая самоподдерживающаяся система. Unit-тесты разработчиков, интеграционные тесты, E2E-сценарии — все они связаны общими фичами, автоматическим маппингом и едиными метриками. Не нужно вручную поддерживать связи, не нужно угадывать, что покрыто, а что нет. Система сама следит за собой.