From 3df40240e74617fd584620de5b6efde0a917f3c8 Mon Sep 17 00:00:00 2001 From: VolandSZ <{E-MAIL}> Date: Tue, 1 Sep 2026 22:46:27 +0300 Subject: [PATCH] feat: add vetstation role tests (BP01 Dashboard navigation) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Создана структура тестов для роли 'Ветеринарная станция' по той же архитектуре что и 01_vetdept. tests/02_vetstation/ conftest.py — fixtures_dir, shared_state fixtures/images/.gitkeep — папка для фото артефактов fixtures/docs/.gitkeep — папка для документов BP01_dashboard/ test_bp01_dashboard.py — class TestBP01Dashboard (7 шагов) BP01 покрывает: s01 — Открыть главную страницу (Статистика) s02 — Проверить заголовок организации s03 — Проверить блок статистики регистрации животных s04 — Проверить таблицу последних зарегистрированных особей s05 — Перейти в раздел Животные s06 — Перейти в раздел Владельцы животных (URL с regex: /owners?type=individual) s07 — Перейти в раздел Единый реестр Удалён старый CodeGen-тест 002_login_test.py --- tests/02_vetstation/002_login_test.py | 13 --- .../02_vetstation/BP01_dashboard/__init__.py | 1 + .../BP01_dashboard/test_bp01_dashboard.py | 85 +++++++++++++++++++ tests/02_vetstation/conftest.py | 47 ++++++++++ tests/02_vetstation/fixtures/docs/.gitkeep | 1 + tests/02_vetstation/fixtures/images/.gitkeep | 1 + tests/testdata/generators.py | 1 + 7 files changed, 136 insertions(+), 13 deletions(-) delete mode 100644 tests/02_vetstation/002_login_test.py create mode 100644 tests/02_vetstation/BP01_dashboard/__init__.py create mode 100644 tests/02_vetstation/BP01_dashboard/test_bp01_dashboard.py create mode 100644 tests/02_vetstation/conftest.py create mode 100644 tests/02_vetstation/fixtures/docs/.gitkeep create mode 100644 tests/02_vetstation/fixtures/images/.gitkeep diff --git a/tests/02_vetstation/002_login_test.py b/tests/02_vetstation/002_login_test.py deleted file mode 100644 index ef3e91c..0000000 --- a/tests/02_vetstation/002_login_test.py +++ /dev/null @@ -1,13 +0,0 @@ -import re -from playwright.sync_api import Page, expect - - -def test_example(page: Page) -> None: - page.goto("https://vet.goznak.ru/auth") - page.get_by_role("textbox", name="Email").click() - page.get_by_role("textbox", name="Email").click() - page.get_by_role("textbox", name="Email").fill("gz_vetstation@vet.goznak.ru") - page.get_by_role("textbox", name="Введите пароль").click() - page.get_by_role("textbox", name="Введите пароль").fill("A6wrpzpD5T") - page.get_by_role("button", name="Войти в аккаунт").click() - expect(page.locator("#app")).to_match_aria_snapshot("- text: Ветеринарная станция \"ГОЗНАК\" - Демо\n- combobox: /\\d+\\.\\d+\\.\\d+ - \\d+\\.\\d+\\.\\d+/\n- button \"Создать отчет\":\n - img\n - text: \"\"\n- text: Статистика регистрации домашних животных\n- img\n- text: 0 всего особей Всего особей\n- paragraph: \"0\"\n- list:\n - listitem:\n - img\n - text: \"0\"\n - img\n - text: \"0\"\n- text: Из них с биометрией\n- paragraph: \"0\"\n- list:\n - listitem:\n - img\n - text: \"0\"\n - img\n - text: \"0\"\n- text: Динамика регистраций в ветстанции\n- img\n- text: Последние зарегистрированные особи\n- button \"Перейти к списку\"\n- table:\n - rowgroup:\n - row \"ID особи Дата № регистрации Тип маркировки № маркировки Кличка Тип владелеца\":\n - columnheader \"ID особи\"\n - columnheader \"Дата\"\n - columnheader \"№ регистрации\"\n - columnheader \"Тип маркировки\"\n - columnheader \"№ маркировки\"\n - columnheader \"Кличка\"\n - columnheader \"Тип владелеца\"\n - columnheader\n - rowgroup:\n - row /homeless \\d+ \\d+\\.\\d+\\.\\d+ \\d+ С \\d+ \\d+ \\d+ Нет информации о маркировке Без номера Кличко Юридическое лицо/:\n - cell /homeless \\d+/:\n - img \"homeless\"\n - img\n - img\n - text: \"\"\n - cell /\\d+\\.\\d+\\.\\d+/\n - cell /\\d+ С \\d+ \\d+ \\d+/\n - cell \"Нет информации о маркировке\"\n - cell \"Без номера\"\n - cell \"Кличко\"\n - cell \"Юридическое лицо\"\n - cell:\n - button:\n - img\n - row /homeless \\d+ \\d+\\.\\d+\\.\\d+ \\d+ К \\d+ \\d+ \\d+ Нет информации о маркировке Без номера Звезда Юридическое лицо/:\n - cell /homeless \\d+/:\n - img \"homeless\"\n - img\n - img\n - text: \"\"\n - cell /\\d+\\.\\d+\\.\\d+/\n - cell /\\d+ К \\d+ \\d+ \\d+/\n - cell \"Нет информации о маркировке\"\n - cell \"Без номера\"\n - cell \"Звезда\"\n - cell \"Юридическое лицо\"\n - cell:\n - button:\n - img\n - row /homeless \\d+ \\d+\\.\\d+\\.\\d+ \\d+ К \\d+ \\d+ \\d+ Клеймо К-\\d+ Симба Физическое лицо/:\n - cell /homeless \\d+/:\n - img \"homeless\"\n - img\n - img\n - text: \"\"\n - cell /\\d+\\.\\d+\\.\\d+/\n - cell /\\d+ К \\d+ \\d+ \\d+/\n - cell \"Клеймо\"\n - cell /К-\\d+/\n - cell \"Симба\"\n - cell \"Физическое лицо\"\n - cell:\n - button:\n - img\n - row /homeless \\d+ \\d+\\.\\d+\\.\\d+ \\d+ С \\d+ \\d+ \\d+ Микрочип Ч-\\d+ Жорик Юридическое лицо/:\n - cell /homeless \\d+/:\n - img \"homeless\"\n - img\n - img\n - text: \"\"\n - cell /\\d+\\.\\d+\\.\\d+/\n - cell /\\d+ С \\d+ \\d+ \\d+/\n - cell \"Микрочип\"\n - cell /Ч-\\d+/\n - cell \"Жорик\"\n - cell \"Юридическое лицо\"\n - cell:\n - button:\n - img\n - row /homeless \\d+ \\d+\\.\\d+\\.\\d+ \\d+ С \\d+ \\d+ \\d+ Нет информации о маркировке Без номера Дружок Физическое лицо/:\n - cell /homeless \\d+/:\n - img \"homeless\"\n - img\n - img\n - text: \"\"\n - cell /\\d+\\.\\d+\\.\\d+/\n - cell /\\d+ С \\d+ \\d+ \\d+/\n - cell \"Нет информации о маркировке\"\n - cell \"Без номера\"\n - cell \"Дружок\"\n - cell \"Физическое лицо\"\n - cell:\n - button:\n - img") diff --git a/tests/02_vetstation/BP01_dashboard/__init__.py b/tests/02_vetstation/BP01_dashboard/__init__.py new file mode 100644 index 0000000..481308e --- /dev/null +++ b/tests/02_vetstation/BP01_dashboard/__init__.py @@ -0,0 +1 @@ +# BP01: Навигация по разделам ЛК ветеринарной станции diff --git a/tests/02_vetstation/BP01_dashboard/test_bp01_dashboard.py b/tests/02_vetstation/BP01_dashboard/test_bp01_dashboard.py new file mode 100644 index 0000000..e31425a --- /dev/null +++ b/tests/02_vetstation/BP01_dashboard/test_bp01_dashboard.py @@ -0,0 +1,85 @@ +import os +# pyrefly: ignore [missing-import] +import pytest +# pyrefly: ignore [missing-import] +from playwright.sync_api import Page, expect + +BASE_URL = os.getenv("BASE_URL", "https://vet.goznak.ru") + + +@pytest.mark.vetstation +@pytest.mark.usefixtures("browser_page") +class TestBP01Dashboard: + """ + BP01: Навигация по разделам личного кабинета ветеринарной станции + + Проверяет что пользователь с ролью 'Ветеринарная станция' может: + - Открыть главную страницу (Статистика/Dashboard) + - Видеть заголовок своей организации + - Видеть блок статистики регистрации животных + - Видеть таблицу последних зарегистрированных особей + - Перейти в раздел Животные + - Перейти в раздел Владельцы животных + - Перейти в раздел Единый реестр + """ + + @pytest.mark.dependency(name="VSBP01::s01") + def test_s01_open_dashboard(self, browser_page: Page, bp_state: dict): + """Шаг 1: Открыть главную страницу (Статистика)""" + browser_page.goto(BASE_URL + "/dashboard") + expect(browser_page).to_have_url(BASE_URL + "/dashboard") + + @pytest.mark.dependency(name="VSBP01::s02", depends=["VSBP01::s01"]) + def test_s02_check_org_header(self, browser_page: Page, bp_state: dict): + """Шаг 2: Проверить заголовок организации""" + expect(browser_page.locator("#app")).to_contain_text( + "Ветеринарная станция" + ) + + @pytest.mark.dependency(name="VSBP01::s03", depends=["VSBP01::s02"]) + def test_s03_check_stats_block(self, browser_page: Page, bp_state: dict): + """Шаг 3: Проверить блок статистики регистрации животных""" + expect( + browser_page.get_by_text("Статистика регистрации домашних животных") + ).to_be_visible(timeout=10000) + expect( + browser_page.get_by_text("Всего особей").first + ).to_be_visible(timeout=10000) + + + @pytest.mark.dependency(name="VSBP01::s04", depends=["VSBP01::s03"]) + def test_s04_check_animals_table(self, browser_page: Page, bp_state: dict): + """Шаг 4: Проверить таблицу последних зарегистрированных особей""" + expect( + browser_page.get_by_text("Последние зарегистрированные особи") + ).to_be_visible(timeout=10000) + # Проверяем наличие колонок таблицы + expect(browser_page.get_by_role("columnheader", name="Кличка")).to_be_visible() + expect(browser_page.get_by_role("columnheader", name="Дата")).to_be_visible() + + @pytest.mark.dependency(name="VSBP01::s05", depends=["VSBP01::s04"]) + def test_s05_go_to_animals(self, browser_page: Page, bp_state: dict): + """Шаг 5: Перейти в раздел Животные""" + browser_page.get_by_role("link", name="Животные").click() + expect(browser_page).to_have_url(BASE_URL + "/animals", timeout=10000) + expect(browser_page.locator("#app")).to_be_visible(timeout=10000) + + @pytest.mark.dependency(name="VSBP01::s06", depends=["VSBP01::s05"]) + def test_s06_go_to_owners(self, browser_page: Page, bp_state: dict): + """Шаг 6: Перейти в раздел Владельцы животных""" + import re + browser_page.get_by_role("link", name="Владельцы животных").click() + # Страница открывается с query-параметром (?type=individual), поэтому regex + expect(browser_page).to_have_url( + re.compile(r".*/owners.*"), timeout=10000 + ) + expect(browser_page.locator("#app")).to_be_visible(timeout=10000) + + + + @pytest.mark.dependency(name="VSBP01::s07", depends=["VSBP01::s06"]) + def test_s07_go_to_registry(self, browser_page: Page, bp_state: dict): + """Шаг 7: Перейти в раздел Единый реестр""" + browser_page.get_by_role("link", name="Единый реестр").click() + expect(browser_page).to_have_url(BASE_URL + "/registry", timeout=10000) + expect(browser_page.locator("#app")).to_be_visible(timeout=10000) diff --git a/tests/02_vetstation/conftest.py b/tests/02_vetstation/conftest.py new file mode 100644 index 0000000..4dcd5ba --- /dev/null +++ b/tests/02_vetstation/conftest.py @@ -0,0 +1,47 @@ +# pyrefly: ignore [missing-import] +import pytest +from pathlib import Path + + +# --------------------------------------------------------------------------- +# Пути к статическим артефактам роли (фото, документы, файлы) +# --------------------------------------------------------------------------- + +@pytest.fixture(scope="session") +def fixtures_dir() -> Path: + """ + Путь к папке со статическими артефактами роли vetstation. + Структура папки: + fixtures/ + ├── images/ ← фотографии животных, документы-сканы + └── docs/ ← PDF, сертификаты и прочие документы + """ + return Path(__file__).parent / "fixtures" + + +# --------------------------------------------------------------------------- +# Готовые фикстуры для конкретных артефактов +# Добавляй новые по мере появления новых файлов в папке fixtures/ +# --------------------------------------------------------------------------- + +# @pytest.fixture(scope="session") +# def animal_photo(fixtures_dir) -> Path: +# """Фото животного для теста регистрации.""" +# return fixtures_dir / "images" / "animal_photo.jpg" + + +# --------------------------------------------------------------------------- +# Контейнер для передачи данных между разными БП одной роли (scope=session) +# --------------------------------------------------------------------------- + +@pytest.fixture(scope="session") +def shared_state() -> dict: + """ + Словарь для передачи данных между разными бизнес-процессами + в рамках одной тестовой сессии для роли vetstation. + + Пример: + # В BP02 создаём животное → BP03 проверяет его в реестре + shared_state["animal_id"] = "96416" + """ + return {} diff --git a/tests/02_vetstation/fixtures/docs/.gitkeep b/tests/02_vetstation/fixtures/docs/.gitkeep new file mode 100644 index 0000000..c5774ed --- /dev/null +++ b/tests/02_vetstation/fixtures/docs/.gitkeep @@ -0,0 +1 @@ +# PDF, сертификаты, ветпаспорта для роли vetstation diff --git a/tests/02_vetstation/fixtures/images/.gitkeep b/tests/02_vetstation/fixtures/images/.gitkeep new file mode 100644 index 0000000..1779a9b --- /dev/null +++ b/tests/02_vetstation/fixtures/images/.gitkeep @@ -0,0 +1 @@ +# Фотографии животных и документы-сканы для роли vetstation diff --git a/tests/testdata/generators.py b/tests/testdata/generators.py index aa5180b..50fc765 100644 --- a/tests/testdata/generators.py +++ b/tests/testdata/generators.py @@ -61,6 +61,7 @@ import random import string from datetime import date, timedelta +# pyrefly: ignore [missing-import] from faker import Faker # Единственный экземпляр Faker на весь модуль — не создавай новые в функциях