Files
e2e_Pets/README.md
VolandSZ d156fa0664 docs: add Playwright Codegen section to README
Описан workflow визуальной записи тестов:
- Команды запуска codegen (с сохранением в файл и без)
- Порядок работы: запуск → авторизация → запись → адаптация
- Полный пример: сырой вывод Codegen → класс с шагами
- Таблица преобразований: что убирается и что добавляется
2026-09-01 23:58:41 +03:00

418 lines
16 KiB
Markdown
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.

# e2e_Pets — End-to-End тесты портала учёта животных
Автоматизированное тестирование портала [vet.goznak.ru](https://vet.goznak.ru)
на базе **Playwright + pytest**.
---
## Содержание
- [Структура проекта](#структура-проекта)
- [Быстрый старт](#быстрый-старт)
- [Запуск тестов](#запуск-тестов)
- [Создание нового теста](#создание-нового-теста)
- [Добавление генератора данных (ФЛК)](#добавление-генератора-данных-флк)
- [Добавление статического артефакта](#добавление-статического-артефакта)
---
## Структура проекта
```
e2e_Pets/
├── .env # Учётные данные (не в git)
├── .env.example # Шаблон .env
├── pytest.ini # Конфигурация pytest
├── requirements.txt # Зависимости
└── tests/
├── conftest.py # Глобальные фикстуры (browser_page, bp_state)
├── testdata/
│ └── generators.py # Генераторы случайных данных по ФЛК
├── 01_vetdept/ # ЛК: Управление ветеринарии
│ ├── conftest.py # fixtures_dir, shared_state
│ ├── fixtures/ # Статические артефакты (фото, PDF)
│ └── BP01_navigation/ # Бизнес-процесс 01
│ └── test_bp01_navigation.py
└── 02_vetstation/ # ЛК: Ветеринарная станция
├── conftest.py
├── fixtures/
└── BP01_dashboard/ # Бизнес-процесс 01
└── test_bp01_dashboard.py
```
**Иерархия тестов:** Проект → ЛК (роль) → БП (`BP01_...`) → Шаги (`test_s01_...`, `test_s02_...`)
---
## Быстрый старт
### 1. Клонировать репозиторий
```powershell
git clone <url>
cd e2e_Pets
```
### 2. Создать виртуальное окружение и установить зависимости
```powershell
python -m venv venv
.\venv\Scripts\pip.exe install -r requirements.txt
.\venv\Scripts\playwright.exe install chromium
```
### 3. Настроить учётные данные
```powershell
Copy-Item .env.example .env
# Открыть .env и заполнить логины/пароли
```
---
## Запуск тестов
> Все команды выполняются из корня проекта (`e2e_Pets/`).
> HTML-отчёт автоматически создаётся в `html-report/report.html`.
---
### Запустить ВСЕ тесты
```powershell
.\venv\Scripts\pytest.exe
```
---
### Запустить тесты конкретного ЛК (роли)
```powershell
# ЛК Управление ветеринарии
.\venv\Scripts\pytest.exe tests/01_vetdept/
# ЛК Ветеринарная станция
.\venv\Scripts\pytest.exe tests/02_vetstation/
```
---
### Запустить конкретный бизнес-процесс
```powershell
# BP01 навигации в ЛК Управление ветеринарии
.\venv\Scripts\pytest.exe tests/01_vetdept/BP01_navigation/
# BP01 дашборда в ЛК Ветеринарная станция
.\venv\Scripts\pytest.exe tests/02_vetstation/BP01_dashboard/
```
---
### Запустить конкретный шаг
```powershell
# Только шаг 3 из BP01 ветстанции
.\venv\Scripts\pytest.exe tests/02_vetstation/BP01_dashboard/ -k "s03"
# Только шаги 1 и 2
.\venv\Scripts\pytest.exe tests/02_vetstation/BP01_dashboard/ -k "s01 or s02"
```
---
### Полезные флаги
| Флаг | Описание |
|---|---|
| `-v` | Подробный вывод с именами шагов |
| `--headed` | Показывать браузер (по умолчанию включён в `pytest.ini`) |
| `--headless` | Запустить без браузера (быстрее) |
| `--slowmo 500` | Замедление действий на 500мс (для отладки) |
| `-k "BP01"` | Запустить только тесты содержащие "BP01" в имени |
| `--co -q` | Только показать список тестов без запуска |
```powershell
# Показать список всех тестов (без запуска)
.\venv\Scripts\pytest.exe --co -q
# Запустить без браузера и без замедления
.\venv\Scripts\pytest.exe --headless --slowmo 0
# Запустить в headless-режиме только vetdept
.\venv\Scripts\pytest.exe tests/01_vetdept/ --headless --slowmo 0
```
---
## Создание нового теста
### Нужен новый бизнес-процесс?
Опиши его в свободной форме — например:
> *«Нужен тест для ветстанции: открыть список животных, применить фильтр
> по кошкам, убедиться что список отфильтровался, открыть карточку
> первого животного, проверить наличие кнопки редактирования»*
ИИ-ассистент создаст файл в нужном месте, следуя архитектуре проекта.
---
### Если хочешь создать вручную — шаблон:
#### 1. Создать папку бизнес-процесса
```powershell
# Для роли vetstation, новый бизнес-процесс BP02
mkdir tests\02_vetstation\BP02_animals
New-Item tests\02_vetstation\BP02_animals\__init__.py
```
#### 2. Создать файл теста
Имя файла: `test_bp02_<название>.py`
```python
import os
import pytest
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 TestBP02Animals:
"""
BP02: Краткое описание бизнес-процесса
Проверяет что пользователь может:
- Шаг 1: ...
- Шаг 2: ...
"""
@pytest.mark.dependency(name="BP02::s01")
def test_s01_<название>(self, browser_page: Page, bp_state: dict):
"""Шаг 1: Описание шага — именно это появится в отчёте"""
# ... код теста ...
bp_state["key"] = "value" # передать данные следующему шагу
@pytest.mark.dependency(name="BP02::s02", depends=["BP02::s01"])
def test_s02_<название>(self, browser_page: Page, bp_state: dict):
"""Шаг 2: Описание шага"""
value = bp_state["key"] # получить данные от предыдущего шага
# ... код теста ...
```
#### 3. Правила именования
| Элемент | Формат | Пример |
|---|---|---|
| Папка БП | `BP<NN>_<описание>` | `BP02_animals` |
| Файл теста | `test_bp<NN>_<описание>.py` | `test_bp02_animals.py` |
| Класс | `TestBP<NN><Описание>` | `TestBP02Animals` |
| Метод (шаг) | `test_s<NN>_<описание>` | `test_s01_open_list` |
| Зависимость | `BP<NN>::s<NN>` | `BP02::s01` |
#### 4. Маркеры ролей
| Маркер | Роль |
|---|---|
| `@pytest.mark.vetdept` | Управление ветеринарии |
| `@pytest.mark.vetstation` | Ветеринарная станция |
| `@pytest.mark.prefecture` | Администрация (префектура) |
---
## Добавление генератора данных (ФЛК)
Файл: [`tests/testdata/generators.py`](tests/testdata/generators.py)
Содержит пошаговое руководство по добавлению нового генератора прямо в начале файла. Коротко:
```python
# Шаблон новой функции-генератора:
def gen_<сущность>_<поле>() -> str:
"""
Краткое описание.
ФЛК:
- Правило 1
- Правило 2
Пример вывода: 'AB1234'
"""
# ... реализация ...
```
Использование в тесте:
```python
from tests.testdata.generators import gen_microchip, gen_animal_name
def test_s01_fill_form(self, browser_page, bp_state):
name = gen_animal_name()
chip = gen_microchip()
browser_page.fill("#name", name)
browser_page.fill("#chip", chip)
bp_state["name"] = name # передаём следующему шагу
```
---
## Добавление статического артефакта
1. Положи файл в папку `fixtures/` нужной роли:
```
tests/01_vetdept/fixtures/images/cat_photo.jpg
```
2. Раскомментируй шаблон фикстуры в `tests/<роль>/conftest.py`:
```python
@pytest.fixture(scope="session")
def cat_photo(fixtures_dir) -> Path:
"""Фото кошки для теста загрузки."""
return fixtures_dir / "images" / "cat_photo.jpg"
```
3. Используй в тесте:
```python
def test_s02_upload(self, browser_page, bp_state, cat_photo):
browser_page.set_input_files("input[type=file]", str(cat_photo))
```
---
## Создание теста через визуальный рекордер (Codegen)
Playwright Codegen — встроенный инструмент записи действий в браузере.
Ты кликаешь, вводишь текст и переходишь по страницам — Codegen генерирует
Python-код, который воспроизводит твои действия.
### Запуск рекордера
```powershell
# Открыть браузер с рекордером (без авторизации)
.\venv\Scripts\playwright.exe codegen https://vet.goznak.ru
# Открыть браузер с рекордером и сохранить результат в файл
.\venv\Scripts\playwright.exe codegen https://vet.goznak.ru --output tests\codegen_draft.py
```
Откроются два окна:
- **Браузер** — управляй им как обычно: кликай, заполняй формы, переходи по разделам
- **Playwright Inspector** — в реальном времени показывает сгенерированный код
### Порядок работы
1. **Запусти рекордер** командой выше
2. **Авторизуйся** под нужной ролью (введи логин/пароль из `.env`)
3. **Выполни нужный бизнес-процесс** — все действия записываются автоматически
4. **Скопируй сгенерированный код** из Playwright Inspector
5. **Адаптируй код** под архитектуру проекта (см. ниже)
---
### Как адаптировать код из Codegen в архитектуру проекта
Codegen генерирует **плоский скрипт**, проект использует **класс с шагами**.
Ниже показано как преобразовать одно в другое.
#### До (вывод Codegen):
```python
from playwright.sync_api import Playwright, sync_playwright, expect
def run(playwright: Playwright) -> None:
browser = playwright.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("https://vet.goznak.ru/auth")
page.get_by_role("textbox", name="Email").fill("gz_vetstation@vet.goznak.ru")
page.get_by_role("textbox", name="Введите пароль").fill("A6wrpzpD5T")
page.get_by_role("button", name="Войти в аккаунт").click()
page.get_by_role("link", name="Животные").click()
expect(page).to_have_url("https://vet.goznak.ru/animals")
page.get_by_role("button", name="Добавить животное").click()
page.get_by_label("Кличка").fill("Мурка")
page.get_by_role("button", name="Сохранить").click()
expect(page.get_by_text("Мурка")).to_be_visible()
context.close()
browser.close()
with sync_playwright() as playwright:
run(playwright)
```
#### После (архитектура проекта):
```python
import os
import pytest
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 TestBP02AddAnimal:
"""
BP02: Добавление нового животного
Проверяет что пользователь может:
- Перейти в раздел Животные
- Открыть форму добавления
- Заполнить кличку и сохранить
- Убедиться что животное появилось в списке
"""
# Авторизация и логин/пароль — убраны полностью:
# этим занимается фикстура browser_page (см. tests/conftest.py)
@pytest.mark.dependency(name="BP02::s01")
def test_s01_go_to_animals(self, browser_page: Page, bp_state: dict):
"""Шаг 1: Перейти в раздел Животные"""
browser_page.get_by_role("link", name="Животные").click()
expect(browser_page).to_have_url(BASE_URL + "/animals", timeout=10000)
@pytest.mark.dependency(name="BP02::s02", depends=["BP02::s01"])
def test_s02_open_add_form(self, browser_page: Page, bp_state: dict):
"""Шаг 2: Открыть форму добавления животного"""
browser_page.get_by_role("button", name="Добавить животное").click()
expect(browser_page.get_by_label("Кличка")).to_be_visible(timeout=10000)
@pytest.mark.dependency(name="BP02::s03", depends=["BP02::s02"])
def test_s03_fill_and_save(self, browser_page: Page, bp_state: dict):
"""Шаг 3: Заполнить кличку и сохранить"""
from tests.testdata.generators import gen_animal_name
name = gen_animal_name() # случайное имя по ФЛК
browser_page.get_by_label("Кличка").fill(name)
browser_page.get_by_role("button", name="Сохранить").click()
bp_state["animal_name"] = name # передаём шагу 4
@pytest.mark.dependency(name="BP02::s04", depends=["BP02::s03"])
def test_s04_verify_in_list(self, browser_page: Page, bp_state: dict):
"""Шаг 4: Проверить что животное появилось в списке"""
expect(
browser_page.get_by_text(bp_state["animal_name"])
).to_be_visible(timeout=10000)
```
### Что изменилось при адаптации
| Было в Codegen | Стало в проекте |
|---|---|
| `browser.launch()` + `context.new_page()` | Фикстура `browser_page` (авто) |
| Явный логин/пароль в коде | Берётся из `.env` через фикстуру |
| Один плоский `def run()` | Класс с методами-шагами |
| Нет зависимостей между шагами | `@pytest.mark.dependency(depends=[...])` |
| Хардкод данных (`"Мурка"`) | Генераторы ФЛК (`gen_animal_name()`) |
| Нет передачи данных между шагами | `bp_state["key"] = value` |
| Нет отображения в отчёте | Docstring шага → колонка Test в отчёте |