Files
e2e_Pets/tests/conftest.py
VolandSZ 02176b5ccd feat: show step docstrings in pytest-html report Test column
Добавлен хук pytest_runtest_makereport в tests/conftest.py.
Заменяет технический nodeid (путь к файлу::класс::метод[chromium])
на первую строку docstring тестового метода.

Результат в отчёте:
  До:  tests/01_vetdept/BP01_navigation/test_bp01_navigation.py::TestBP01Navigation::test_s01_open_dashboard[chromium]
  После: Шаг 1: Открыть главную страницу (Dashboard)

Правило: что написано в docstring метода — то отображается в отчёте.
2026-09-01 21:11:52 +03:00

133 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
# pyrefly: ignore [missing-import]
import pytest
# pyrefly: ignore [missing-import]
from dotenv import load_dotenv
# pyrefly: ignore [missing-import]
from playwright.sync_api import Page
# Загружаем переменные из .env (файл находится в корне проекта)
load_dotenv()
# Базовый URL портала — берётся из .env или дефолт
BASE_URL = os.getenv("BASE_URL", "https://vet.goznak.ru")
# Учётные данные для разных ролей — берутся из .env
CREDENTIALS = {
"vetdept": {
"login": os.getenv("VETDEPT_LOGIN"),
"password": os.getenv("VETDEPT_PASSWORD"),
},
"vetstation": {
"login": os.getenv("VETSTATION_LOGIN"),
"password": os.getenv("VETSTATION_PASSWORD"),
},
"prefecture": {
"login": os.getenv("PREFECTURE_LOGIN"),
"password": os.getenv("PREFECTURE_PASSWORD"),
},
}
def _get_role(request) -> str:
"""Определяет роль теста по pytest-маркеру."""
for marker in request.node.iter_markers():
if marker.name in CREDENTIALS:
return marker.name
pytest.fail("ОШИБКА: У теста нет маркера роли (например, @pytest.mark.vetdept)!")
def _login(page: Page, role: str) -> None:
"""Выполняет авторизацию на портале под указанной ролью."""
creds = CREDENTIALS[role]
if not creds["login"] or not creds["password"]:
pytest.fail(
f"ОШИБКА: Переменные окружения для роли '{role}' не заданы. "
f"Скопируй .env.example в .env и заполни данные."
)
print(f"\n[АВТОЛОГИН] Вход под ролью: {role}")
page.goto(BASE_URL)
page.get_by_role("textbox", name="Email").fill(creds["login"])
page.get_by_role("textbox", name="Введите пароль").fill(creds["password"])
page.get_by_role("button", name="Войти в аккаунт").click()
page.wait_for_selector("#app", timeout=10000)
# ---------------------------------------------------------------------------
# Фикстура для бизнес-процессов (scope=class)
# Один браузер на весь класс — авторизация выполняется один раз.
# Создаёт собственный context и page, чтобы избежать ScopeMismatch
# с function-scoped page фикстурой pytest-playwright.
# ---------------------------------------------------------------------------
@pytest.fixture(scope="class")
def browser_page(browser, request):
"""
Авторизованная страница с жизненным циклом на весь класс (бизнес-процесс).
Все шаги внутри класса работают в одной вкладке браузера.
"""
role = _get_role(request)
context = browser.new_context()
page = context.new_page()
_login(page, role)
yield page
context.close()
# ---------------------------------------------------------------------------
# Контейнер для передачи данных между шагами одного БП (scope=class)
# ---------------------------------------------------------------------------
@pytest.fixture(scope="class")
def bp_state() -> dict:
"""
Словарь для передачи данных между шагами одного бизнес-процесса.
Создаётся при старте класса, уничтожается после его завершения.
Пример:
def test_s01_create(self, browser_page, bp_state):
bp_state["claim_id"] = "12345"
def test_s02_verify(self, browser_page, bp_state):
assert bp_state["claim_id"] == "12345"
"""
return {}
# ---------------------------------------------------------------------------
# Устаревшая фикстура — оставлена для обратной совместимости
# Используй browser_page для новых тестов
# ---------------------------------------------------------------------------
@pytest.fixture(scope="function")
def role_page(page: Page, request):
"""
[DEPRECATED] Авторизованная страница с жизненным циклом на один тест.
Для новых тестов используй browser_page (scope=class).
"""
role = _get_role(request)
_login(page, role)
yield page
page.context.clear_cookies()
# ---------------------------------------------------------------------------
# Хук для отображения читаемых имён шагов в pytest-html отчёте
# ---------------------------------------------------------------------------
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
"""
Заменяет технический путь к тесту в колонке Test отчёта pytest-html
на docstring метода (например, 'Шаг 1: Открыть главную страницу').
Если docstring отсутствует — оставляет оригинальный nodeid.
"""
outcome = yield
report = outcome.get_result()
# Берём docstring тестовой функции
doc = getattr(item.function, "__doc__", None)
if doc:
description = doc.strip().splitlines()[0] # только первая строка
report.nodeid = description