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()