4. Повертаємо traces, pytest hooks, рефакторинг дублювань у fixtures
Фінальний урок повертає Playwright tracing у кастомну систему fixtures. Спочатку trace записується для кожного тесту, потім через pytest hook визначається результат фази `call`, і ZIP зберігається лише для failed tests. Паралельно усувається дублювання створення browser contexts для звичайного й Free state та виправляється зайвий browser instance.
Примітка: конспект укладено за автоматичними українськими субтитрами; назви Playwright tracing і pytest hook API нормалізовано за контекстом відео.
Після цього уроку ви зможете
Запускати й завершувати Playwright tracing у власних test-scoped fixtures.
Отримувати результат фази call через pytest_runtest_makereport.
Зберігати окремий trace ZIP лише для failed tests і перевіряти його в Trace Viewer.
Чому вбудованої pytest-playwright fixture недостатньо
Проєкт сам контролює storage_state, авторизовані та Free contexts, відкриття й закриття page. Через це готові fixtures плагіна не покривають потрібний lifecycle, а tracing доводиться інтегрувати у власний шар.
Перед tracing виправляється побічна проблема: Free test відкривав два browser instances, бо вимагав fixture, результат якої не використовував. Видалення зайвої залежності прибирає другий запуск браузера.
Що змінилося після запису
Плагін уже має `retain-on-failure`
У відеоЧерез custom fixture architecture у відео вручну інтегровано tracing і pytest hook.
АктуальноПоточний pytest-playwright plugin підтримує --tracing retain-on-failure. Якщо тест використовує стандартні plugin fixtures, спершу варто перевірити цю option; custom hook потрібен, коли lifecycle контролюється власними fixtures.
Fixture створює context, завантажує готовий state або виконує login і записує його, після чого віддає page через yield. Код після yield є teardown і закриває page/context.
Важливо повертати вже створену page, а не викликати new_page() ще раз. Так test actions, trace і cleanup належать одному browser context.
Запис запускається через context.tracing.start(screenshots=True, snapshots=True, sources=True), а перед закриттям context завершується tracing.stop(path=...). Trace Viewer показує Playwright actions, DOM snapshots, source files і network.
Якщо вставити start/stop у кожну низькорівневу fixture, код дублюється, а один session trace змішує кілька тестів. Tracing переноситься у test-scoped app fixtures, щоб кожен тест мав окремий lifecycle.
Термін
Playwright trace
Артефакт із recorded browser actions, DOM snapshots, network і source context, який відкривається в Trace Viewer.
Built-in fixture request надає request.node.name, тому trace можна назвати ім’ям конкретного тесту й зберігати в test-results/traces/<test>.zip. Це робить артефакт однозначним і придатним для CI.
ZIP відкривається командою playwright show-trace <path>. На timeline видно переходи, clicks, fills, assertions, snapshots, network і Python sources, що дає більше діагностичної інформації, ніж відео самого браузера.
Trace для кожного успішного тесту швидко збільшує обсяг CI artifacts. Простий варіант «зберігати все» допустимий для малого набору з коротким retention, але кращий контракт — залишати ZIP лише коли тест упав.
Артефакт має жити достатньо, щоб інженер устиг провести root-cause analysis. Retention і upload налаштовуються на рівні CI; сама fixture відповідає лише за локальне створення файлу.
Термін
retain-on-failure
Поточна pytest-playwright CLI option для запису trace кожного тесту й видалення запису після успішного завершення.
Fixture не знає результат тесту напряму, тому conftest.py підключає hook pytest_runtest_makereport. Hook отримує звіт для кожної фази та записує його в атрибут node, наприклад rep_setup, rep_call, rep_teardown.
Для assertion failure самого тесту перевіряється request.node.rep_call.failed. setup охоплює код до yield, call — тіло тесту, teardown — код після yield. Якщо потрібно зберігати trace також при fixture setup failure, це окреме розширення контракту; демонстрація фокусується на call.
Що змінилося після запису
Актуальний pytest pattern використовує `item.stash`
У відеоУ відео phase reports записуються як динамічні attributes на test node, наприклад rep_call.
АктуальноПоточний official pytest example використовує typed StashKey та item.stash. Manual Playwright tracing також не записує pytest assertion як traced action; він показує browser context навколо failure.
Перевірено 2026-07-31
Термін
pytest_runtest_makereport
pytest hook, який формує TestReport для фаз setup, call і teardown; custom fixture може використати report для рішення про artifact retention.
Приклад коду
Збереження reports на pytest node
from typing import Dict
import pytest
from _pytest.reports import TestReport
from _pytest.stash import StashKey
phase_reports_key = StashKey[Dict[str, TestReport]]()
@pytest.hookimpl(wrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
report = yield
item.stash.setdefault(phase_reports_key, {})[report.when] = report
Зберігає reports фаз у typed pytest stash, щоб teardown fixture могла перевірити failure потрібної фази.
Очікуваний результат: Після фази callitem.stash[phase_reports_key]["call"] містить відповідний TestReport.
Звичайний і Free flows дублювали перевірку state path, options для new_context, login та повернення page. Спільна функція get_or_create_context будує context і повідомляє, чи потрібна авторизація.
Верхні fixtures залишають предметні кроки: звичайна зберігає авторизований state; Free додатково перемикає проєкт і зберігає Free state. Спільний helper не повинен поглинати ці відмінності лише заради меншої кількості рядків.
Tracing helpers приймають page.context, тому app fixture не мусить окремо повертати context. start_tracing() централізує options, а stop_tracing_on_failure() або записує ZIP, або зупиняє tracing без path.
Після рефакторингу запускаються Free та Enterprise тести. Вони проходять, а папка traces залишається порожньою — це позитивна перевірка, що successful tests не створюють артефакт.
Увага
Перевірте обидві гілки retention
Green test не повинен залишати ZIP, а навмисний assertion failure має створити один trace з назвою конкретного тесту.
Практика
Red/green перевірка trace retention
Запустіть один green test і переконайтеся, що ZIP не створено.
Тимчасово зробіть його assertion неправильним і повторіть запуск.
Відкрийте єдиний ZIP через playwright show-trace, після чого поверніть тест у green state.
Результат: Green path не створює trace; failure path створює один читабельний artifact для потрібного test ID.
Один locator навмисно змінюється на неправильний. Тест падає, з’являється ZIP із назвою тесту, а Trace Viewer показує останній успішний крок і assertion, який не знайшов очікуваний елемент.
Після доказу failure path тимчасову помилку треба прибрати й повернути suite у green state. Завершена зміна комітиться в окремій гілці; у командній роботі вона проходить pull request, а не пряме злиття без review.