Почему именно JUnit XML
Это самый старый и самый распространённый формат отчёта: его пишут PHPUnit, pytest, Jest, Vitest, Playwright, Surefire, go test через обёртку, Vanessa Automation и почти всё остальное. Придумывать свой формат означало бы заставить каждую команду тащить плагин; вместо этого QA Деск принимает то, что уже лежит в артефактах вашей сборки.
Второй поддерживаемый формат — Allure (NDJSON). Больше форматов не требуется.
Приём: один запрос
curl -H "Authorization: Bearer $QADESK_TOKEN" \
--data-binary @reports/junit.xml \
"https://api.qadesk.ru/ingest/v1/junit?name=regress&environment=stage&platform=web&ciRunId=$CI_PIPELINE_ID&attempt=1"
Параметры: name — имя прогона, environment — prod | stage | test | dev | local, platform — web | ios | android | desktop | api, ciRunId и attempt — ключ идемпотентности.
QADESK_TOKEN — токен приёма на проект (qdit_…), а не личный токен человека: выпускается в кабинете (Настройки → Интеграции → CI / автотесты), показывается один раз, хранится хешем и отзывается одной кнопкой. Уволившийся автоматизатор не уносит доступ с собой, и заводить служебного пользователя ради пайплайна не нужно.
Удобнее — qadesk-cli: находит отчёты в каталоге, склеивает несколько файлов (Surefire, шарды pytest-xdist), берёт ключ идемпотентности из переменных CI и печатает ссылку на прогон последней строкой.
Ключ кейса: три источника
Чтобы результат лёг в ту же строку покрытия, что и ручная проверка, тест помечается ключом кейса вида QAD-C17. Источники в порядке приоритета:
<testsuite name="checkout">
<!-- 1. явная разметка -->
<testcase name="оформление заказа гостем">
<properties><property name="qadesk.case" value="QAD-C17"/></properties>
</testcase>
<!-- 2. имя теста -->
<testcase name="QAD-C18 оплата картой" time="1.204"/>
<!-- 3. classname -->
<testcase classname="checkout.QAD_C19" name="повторная оплата"/>
</testsuite>
Регистр нормализуется. Ключ дефекта (QAD-17) ключом кейса не считается — буква C разводит их по построению, поэтому упоминание бага в названии теста ничего не сломает.
Результаты без ключа не записываются и возвращаются поимённо с причиной (no_key, case_archived). Тихо принять отчёт целиком и записать из него восьмую часть — это ровно тот зелёный, который потом стоит дороже красного.
Идемпотентность
Приём идемпотентен по паре «прогон CI + попытка». Перезапустили упавшее задание — второго прогона не появится, цифры на дашборде не удвоятся. Тот же ключ с другим содержимым (шард матрицы, отдельный прогон тестов) получает отказ 409: передайте свой attempt или свой ciRunId на шард.
Там, где CI не даёт узнаваемых переменных, утилита ключ не выдумывает: ключ из текущей даты молча выключил бы защиту от дублей.
Чем это отличается от вкладки с отчётом в CI
Вкладка показывает один прогон и живёт столько же, сколько артефакт сборки. Прогон в деске остаётся: у него есть история падений, окружение и сборка полями, связь с дефектами и — главное — общая таблица с ручными проверками. Покрытие считается по всему, что проверено, а не отдельно «машиной» и отдельно «руками».
Из упавшего результата заводится дефект: описание и ссылка на прогон переносятся, дальше он идёт по воркфлоу из восьми статусов с проверкой переходов на сервере.
Как считаются статусы
| В отчёте | В прогоне |
|---|---|
failure, error | упало |
skipped | пропущено |
| нет вложенных тегов | пройдено |
| кейс встретился дважды | худший исход |
Чего в продукте нет
- нет парсинга произвольного XML: файл должен быть отчётом JUnit, иначе приходит ошибка данных, а не «принято»;
- нет приёма артефактов сборки — логи, видео и трейсы остаются в CI;
- нет автозаведения дефектов по упавшим тестам.
С чего начать
- Найдите в своём раннере флаг вывода JUnit XML — он почти наверняка уже есть.
- Выпустите токен приёма на проект.
- Добавьте шаг выгрузки с
when: always, иначе отчёт не уедет именно в тот раз, когда он нужен. - Проставьте ключи кейсов у важных тестов и посмотрите список несматченных — он покажет остаток работы честно.
Попробуйте на своём проекте
Заведите проект, загрузите первый отчёт или заведите первый дефект — бесплатный тариф без карты. Нужно демо на ваших сценариях — напишите на hello@qadesk.ru.
Создать проектРядом по теме
Playwright
Playwright пишет отчёт, QA Деск делает из него прогон: ключ кейса связывает автотест с ручной проверкой, повтор задания не плодит дубли, а упавший сценарий превращается в дефект.
Playwright — сценарии в браузере, результат в покрытииAllure
Каталог allure-results уезжает в QA Деск одним шагом. Отличие от отчёта-артефакта в том, что прогон остаётся: с историей, покрытием вместе с ручными кейсами и дефектами из упавших шагов.
Allure — результаты, которые не пропадают вместе со сборкойGitLab CI
Отчёт из GitLab CI уезжает в QA Деск шагом в пять строк: токен проекта в masked-переменной, ключ идемпотентности утилита берёт из CI_PIPELINE_ID сама.
GitLab CI — один шаг в пайплайне, прогон в деске