lenec ru

← все посты

Allure-отчёты для Playwright и pytest: что включить, что не превратить в свалку

15K

Allure — самый популярный репортер в мире автотестов на пост-советском пространстве. На Stack Overflow по нему вопросов в три раза больше, чем по аналогам. На моих проектах он стоит везде, где гоняются Playwright и pytest. Не потому, что это лучший инструмент в мире, а потому, что разрыв между «дефолтным репортом» и Allure-дашбордом — пропасть.

Покажу, как поднять Allure для двух стеков, какие практики реально полезны на длинной дистанции, и где Allure начинает раздражать.

Зачем нужен Allure поверх дефолта

Дефолтный репорт Playwright показывает, какие тесты упали и трейс к ним. Дефолтный репорт pytest — список с зелёными точками и красными буквами F. Этого хватает, пока тестов меньше пятидесяти и команда из двух человек.

Когда тестов 500+, нужны:

  • Группировка по фичам, эпикам, юзер-стори.
  • История прогонов (тренд flaky-rate, тренд длительности).
  • Шаги внутри теста с длительностью каждого.
  • Прикреплённые скриншоты, логи, network-ответы.
  • Категоризация падений (продукт-баг, тестовый баг, инфраструктура).

Allure всё это умеет. Главное — не превратить отчёт в чёрный ящик с тремя сотнями скриншотов «на всякий случай».

Allure для Playwright

Установка и подключение:

npm i -D allure-playwright
// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [
    ['list'],
    ['allure-playwright', {
      detail: true,
      outputFolder: 'allure-results',
      suiteTitle: false,
    }],
  ],
});

После прогона:

npx allure generate allure-results -o allure-report --clean
npx allure open allure-report

В тестах используй декораторы для метаданных:

import { test, expect } from '@playwright/test';
import { allure } from 'allure-playwright';

test('пользователь сохраняет черновик', async ({ page }) => {
  await allure.epic('Editor');
  await allure.feature('Drafts');
  await allure.story('Auto-save');
  await allure.severity('critical');
  await allure.tms('PROJ-1234');

  await test.step('открыть редактор', async () => {
    await page.goto('/editor');
  });

  await test.step('ввести 100 символов', async () => {
    await page.getByRole('textbox').fill('a'.repeat(100));
  });

  await test.step('подождать автосохранения', async () => {
    await expect(page.getByRole('status', { name: /сохранено/i })).toBeVisible();
  });
});

test.step в Playwright виден в Allure как раскрывающийся блок с длительностью. На длинных тестах это бесценно: сразу видно, на каком шаге упало и сколько занимал каждый.

Allure для pytest

pip install allure-pytest
pytest --alluredir=allure-results
allure generate allure-results -o allure-report --clean
allure open allure-report

В pytest декораторы выглядят так:

import allure
import pytest

@allure.epic("Orders")
@allure.feature("Checkout")
@allure.story("Promo codes")
@allure.severity(allure.severity_level.CRITICAL)
@allure.tag("smoke")
def test_apply_valid_promo(client):
    with allure.step("Создать корзину"):
        cart = client.post("/carts").json()

    with allure.step("Применить промокод"):
        response = client.post(f"/carts/{cart['id']}/promo", json={"code": "WELCOME10"})
        assert response.status_code == 200

    with allure.step("Проверить итоговую сумму"):
        cart_after = client.get(f"/carts/{cart['id']}").json()
        allure.attach(str(cart_after), "cart state", allure.attachment_type.JSON)
        assert cart_after["total"] == 90.00

allure.attach прикрепляет к шагу любые данные — JSON-ответ, скриншот, текстовый лог. На разборе падения это спасает: видно тело ответа сервера, не нужно лезть в логи бекенда.

История и тренды

Главная фича, ради которой ставят Allure — это история. После каждого прогона нужно копировать allure-report/history из предыдущего отчёта в новый allure-results/history. Тогда на дашборде появятся графики flaky-rate, длительности тестов, общего количества за период.

В CI это выглядит так:

- name: Restore Allure history
  uses: actions/cache@v4
  with:
    path: allure-history
    key: allure-history-${{ github.run_id }}
    restore-keys: allure-history-

- name: Run tests
  run: pytest --alluredir=allure-results

- name: Copy history
  run: cp -r allure-history/* allure-results/history/ || true

- name: Generate report
  run: |
    allure generate allure-results -o allure-report --clean
    cp -r allure-report/history allure-history

- name: Publish
  uses: peaceiris/actions-gh-pages@v3
  with:
    publish_dir: allure-report

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

Категоризация падений

По дефолту все падения у Allure лежат в одной куче «failed». Через файл categories.json в allure-results их можно делить на типы:

[
  {
    "name": "Network errors",
    "matchedStatuses": ["broken"],
    "messageRegex": ".*ECONNREFUSED.*|.*ETIMEDOUT.*"
  },
  {
    "name": "Element not found",
    "matchedStatuses": ["failed"],
    "messageRegex": ".*locator.*resolved to 0 elements.*"
  },
  {
    "name": "API 5xx",
    "matchedStatuses": ["failed"],
    "messageRegex": ".*status code 5\\d\\d.*"
  }
]

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

Что попробовала и не зашло

  • Прикреплять скриншот к каждому шагу. Размер артефакта взрывается, время генерации репорта растёт, искать падение становится сложнее. Скриншот — только on-failure и в ключевых шагах.
  • Прикреплять полный HTML страницы при падении. 2 МБ × 30 падений = 60 МБ репорта. На больших наборах артефакт взлетает в гигабайты. Лучше Playwright trace.zip — он компактнее и информативнее.
  • Декораторы @allure.title с динамическим текстом из параметризации. На больших наборах теряется группировка: «Test for user user-1», «Test for user user-2» воспринимаются как разные тесты, хотя это один сценарий с разными данными. Лучше один title, параметры — отдельным шагом.
  • «Все тесты имеют epic/feature/story». На onboarding кажется логично, через полгода мейтенанс декораторов стоит дороже их пользы. Использую только для сложных доменов с десятками фич, на простых — обычные имена тестов.

Где Allure раздражает

Не идеален. Список претензий за пять лет работы:

  • Java под капотом. Генерация репорта тяжёлая, на больших наборах (10 000+ тестов) занимает минуты. На крупных проектах приходится разделять прогоны и собирать репорт частями.
  • Слабая интеграция с CI на новых билдерах. Хорошие плагины есть для Jenkins, для GitHub Actions всё пилишь руками.
  • Нет нормальной inline-версии без сервера. Открывать index.html через file:// ломается из-за CORS. Нужен либо allure open, либо публикация на хостинг.
  • API между мажорными версиями ломается. С Allure 2 на Allure 3 переход требовал перепрошивки всех проектов.

Чек-лист: Allure без боли

  1. Подключи allure-playwright или allure-pytest, не пиши свой репортер.
  2. Используй test.step в Playwright и with allure.step() в pytest для разбиения сценария.
  3. Декораторы epic/feature/story — только если у тебя есть реальная иерархия. На простых проектах — пропусти.
  4. Скриншоты и логи — on-failure, не на каждый шаг.
  5. Обязательно настрой копирование истории в CI.
  6. Заведи categories.json для типизации падений.
  7. Публикуй репорт на gh-pages или внутренний хостинг — не пытайся открыть локально через file://.

Allure не делает тесты лучше, но делает их видимыми для команды. На утреннем дейли можно открыть дашборд и за минуту понять, что вчерашний прогон дал, какие тесты в карантине, какие фичи покрашены. Без такого инструмента эти разговоры превращаются в «по моим ощущениям всё ок», что одинаково плохо и для QA-инженера, и для продукта.

Комментарии 1

  • Андрей Крылов

    Подсаживался на Allure для pytest на бэкенд-сервисе, и главным сюрпризом стал размер истории: на 2k тестов x 30 запусков отчёт раздувается до сотен мегабайт и UI открывается медленно. Чистите ли вы старые runs и как храните историю — в S3 или просто артефакты CI на N последних? И как у вас с привязкой шагов через @allure.step внутри fixture-ов: нашли способ, чтобы шаги фикстур не дублировались в каждом тесте?

Войдите, чтобы оставить комментарий.