persona-dsl 26.1.20.9__tar.gz → 26.1.20.10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- persona_dsl-26.1.20.10/PKG-INFO +185 -0
- persona_dsl-26.1.20.10/README.md +148 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/pyproject.toml +1 -1
- persona_dsl-26.1.20.10/src/persona_dsl.egg-info/PKG-INFO +185 -0
- persona_dsl-26.1.20.9/PKG-INFO +0 -222
- persona_dsl-26.1.20.9/README.md +0 -185
- persona_dsl-26.1.20.9/src/persona_dsl.egg-info/PKG-INFO +0 -222
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/MANIFEST.in +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/setup.cfg +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/__init__.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/components/action.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/components/base_step.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/components/combined_step.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/components/expectation.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/components/fact.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/components/goal.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/components/ops.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/components/step.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/expectations/generic/__init__.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/expectations/generic/contains_item.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/expectations/generic/contains_the_text.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/expectations/generic/has_entries.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/expectations/generic/is_equal.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/expectations/generic/is_greater_than.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/expectations/generic/path_equal.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/expectations/web/__init__.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/expectations/web/is_displayed.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/expectations/web/matches_aria_snapshot.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/expectations/web/matches_screenshot.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/generators/__init__.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/generators/api_generator.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/generators/cli.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/generators/page_generator.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/api/__init__.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/api/json_as.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/api/json_response.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/api/send_request.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/db/__init__.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/db/execute_sql.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/db/fetch_all.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/db/fetch_one.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/kafka/__init__.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/kafka/message_in_topic.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/kafka/send_message.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/soap/__init__.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/soap/call_operation.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/soap/operation_result.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/__init__.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/aria_snapshot.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/click.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/current_path.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/element_attribute.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/element_is_visible.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/element_text.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/elements_count.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/fill.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/generate_page_object.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/input_value.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/navigate.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/press_key.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/rich_aria_snapshot.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/screenshot.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/table_data.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/ops/web/wait_for_navigation.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/pages/__init__.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/pages/elements.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/pages/page.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/pages/virtual_page.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/persona.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/pytest_plugin.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/runtime/dist/persona_bundle.js +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/skills/__init__.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/skills/core/base.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/skills/core/skill_definition.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/skills/use_api.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/skills/use_browser.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/skills/use_database.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/skills/use_kafka.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/skills/use_soap.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/utils/__init__.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/utils/artifacts.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/utils/config.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/utils/data_providers.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/utils/decorators.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/utils/metrics.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/utils/naming.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/utils/path.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/utils/retry.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/utils/taas_integration.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl/utils/waits.py +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl.egg-info/SOURCES.txt +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl.egg-info/dependency_links.txt +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl.egg-info/entry_points.txt +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl.egg-info/requires.txt +0 -0
- {persona_dsl-26.1.20.9 → persona_dsl-26.1.20.10}/src/persona_dsl.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: persona-dsl
|
|
3
|
+
Version: 26.1.20.10
|
|
4
|
+
Summary: DSL для реализации паттерна Screenplay в Python-тестах.
|
|
5
|
+
Requires-Python: >=3.9
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: playwright==1.55.0
|
|
8
|
+
Requires-Dist: pytest
|
|
9
|
+
Requires-Dist: pytest-cov
|
|
10
|
+
Requires-Dist: allure-pytest
|
|
11
|
+
Requires-Dist: python-dotenv
|
|
12
|
+
Requires-Dist: pyyaml
|
|
13
|
+
Requires-Dist: pydantic<3,>=2
|
|
14
|
+
Requires-Dist: requests
|
|
15
|
+
Requires-Dist: pyhamcrest
|
|
16
|
+
Requires-Dist: redis
|
|
17
|
+
Requires-Dist: Faker
|
|
18
|
+
Requires-Dist: pillow
|
|
19
|
+
Requires-Dist: zeep
|
|
20
|
+
Requires-Dist: pg8000
|
|
21
|
+
Requires-Dist: oracledb
|
|
22
|
+
Requires-Dist: kafka-python
|
|
23
|
+
Requires-Dist: Unidecode>=1.3
|
|
24
|
+
Requires-Dist: black
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: black; extra == "dev"
|
|
27
|
+
Requires-Dist: ruff; extra == "dev"
|
|
28
|
+
Requires-Dist: mypy; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
30
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
31
|
+
Requires-Dist: types-requests; extra == "dev"
|
|
32
|
+
Requires-Dist: types-PyYAML; extra == "dev"
|
|
33
|
+
Requires-Dist: types-redis; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-timeout; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-xdist; extra == "dev"
|
|
37
|
+
|
|
38
|
+
# persona-dsl: Фреймворк для автотестов на Python
|
|
39
|
+
|
|
40
|
+
`persona-dsl` — это современная библиотека для написания **E2E** и **API** автотестов, реализующая паттерн **Screenplay**.
|
|
41
|
+
Она предоставляет выразительный язык для описания сценариев, управляет браузером (через Playwright) и автоматически генерирует детальные отчеты Allure.
|
|
42
|
+
|
|
43
|
+
## 📦 Установка
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install persona-dsl
|
|
47
|
+
python -m playwright install --with-deps
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 🚀 Быстрый старт
|
|
53
|
+
|
|
54
|
+
### 1. Описание страницы (Page Object)
|
|
55
|
+
|
|
56
|
+
В `persona-dsl` используется **Универсальная Архитектура Элементов**.
|
|
57
|
+
Основной класс `Page` сам является элементом-контейнером. Вложенные элементы добавляются через `add_element`.
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
# pages/login_page.py
|
|
61
|
+
from persona_dsl.pages import Page
|
|
62
|
+
from persona_dsl.pages.elements import Input, Button
|
|
63
|
+
|
|
64
|
+
class LoginPage(Page):
|
|
65
|
+
def __init__(self):
|
|
66
|
+
super().__init__()
|
|
67
|
+
# Имя атрибута (self.username) будет использовано как имя элемента в отчетах
|
|
68
|
+
self.username = self.add_element(Input(xpath="//input[@id='user']", name="Логин"))
|
|
69
|
+
self.password = self.add_element(Input(xpath="//input[@id='pass']", name="Пароль"))
|
|
70
|
+
self.submit = self.add_element(Button(xpath="//button[@type='submit']", name="Вход"))
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 2. Написание теста
|
|
74
|
+
|
|
75
|
+
Тесты пишутся в стиле "Persona делает действия":
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
# tests/test_login.py
|
|
79
|
+
import pytest
|
|
80
|
+
from persona_dsl.ops.web import NavigateTo, Fill, Click
|
|
81
|
+
from persona_dsl.facts.web import CurrentPath
|
|
82
|
+
from persona_dsl.expectations.web import IsEqualTo
|
|
83
|
+
from pages.login_page import LoginPage
|
|
84
|
+
|
|
85
|
+
def test_login_flow(persona):
|
|
86
|
+
login_page = LoginPage()
|
|
87
|
+
|
|
88
|
+
# 1. Действия (Actions)
|
|
89
|
+
persona.make(
|
|
90
|
+
NavigateTo("/login"),
|
|
91
|
+
Fill(login_page.username, "admin"),
|
|
92
|
+
Fill(login_page.password, "secret"),
|
|
93
|
+
Click(login_page.submit)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# 2. Проверка (Verification)
|
|
97
|
+
# Получаем Факт (CurrentPath) и проверяем Ожидание (IsEqualTo)
|
|
98
|
+
current_path = persona.get(CurrentPath())
|
|
99
|
+
persona.check(current_path, IsEqualTo("/dashboard"))
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 🏗 Архитектура
|
|
105
|
+
|
|
106
|
+
### 1. Ключевые компоненты (Persona Core)
|
|
107
|
+
|
|
108
|
+
| Компонент | Назначение | Пример |
|
|
109
|
+
|-----------|------------|--------|
|
|
110
|
+
| **Persona** | Исполнитель. Хранит состояние и навыки. | `persona.make(...)` |
|
|
111
|
+
| **Skill** | "Навык". Дает доступ к инструментам. | `UseBrowser`, `UseAPI`, `UseDB` |
|
|
112
|
+
| **Ops** | Атомарная операция. Работает со Skill. | `Click`, `HttpRequest`, `ExecuteSQL` |
|
|
113
|
+
| **Step** | Бизнес-шаг. Группирует Ops. | `LoginStep`, `CreateOrder` |
|
|
114
|
+
| **Fact** | Запрос состояния (без изменений). | `CurrentPath`, `ElementText` |
|
|
115
|
+
| **Expectation** | Проверка значения. | `IsEqualTo`, `ContainsText` |
|
|
116
|
+
|
|
117
|
+
### 2. Универсальные Элементы (New!)
|
|
118
|
+
|
|
119
|
+
Больше нет разделения на `Element` и `ElementContainer`. Любой элемент может содержать другие элементы.
|
|
120
|
+
|
|
121
|
+
* **`element.add_element(...)`**: Регистрирует дочерний элемент.
|
|
122
|
+
* **Иерархия**: `Page -> Container -> Element`.
|
|
123
|
+
* **Локаторы**: Строятся автоматически по цепочке родителей.
|
|
124
|
+
|
|
125
|
+
### 3. Генераторный подход
|
|
126
|
+
Все шаги (`Step`, `CombinedStep`) — это генераторы, которые "выдают" (`yield`) операции для исполнения Персоной. Это позволяет `persona-dsl` перехватывать каждый шаг, логировать его в Allure и обрабатывать ошибки.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 🛠 Инструменты и Утилиты
|
|
131
|
+
|
|
132
|
+
### Генерация Page Objects
|
|
133
|
+
Не пишите селекторы вручную. Используйте генератор:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Снять ARIA-снапшот и сгенерировать класс страницы
|
|
137
|
+
persona-page-gen --url http://localhost:8080 --output pages/home.py
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Генерация API клиентов
|
|
141
|
+
```bash
|
|
142
|
+
# Генерация из OpenAPI/Swagger
|
|
143
|
+
persona-api-gen --url http://api.example.com/openapi.json --output skills/my_api.py
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Запуск тестов
|
|
147
|
+
|
|
148
|
+
Тесты запускаются стандартной командой pytest:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pytest --env=dev tests/
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## ⚙️ Конфигурация
|
|
157
|
+
|
|
158
|
+
### `conftest.py`
|
|
159
|
+
Декларативное описание навыков и ролей:
|
|
160
|
+
```python
|
|
161
|
+
PERSONA_SKILLS = [BaseSkill.BROWSER, BaseSkill.API]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### `config/{env}.yaml`
|
|
165
|
+
Параметры окружения (dev, test, prod). Выбирается через `--env=test`.
|
|
166
|
+
|
|
167
|
+
```yaml
|
|
168
|
+
base_url: "https://my-app.test"
|
|
169
|
+
browser:
|
|
170
|
+
headless: true
|
|
171
|
+
viewport: { width: 1920, height: 1080 }
|
|
172
|
+
reporting:
|
|
173
|
+
screenshot_on_fail: true
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## 📊 Отчетность (Allure + TaaS)
|
|
179
|
+
|
|
180
|
+
Фреймворк автоматически:
|
|
181
|
+
1. Создает вложенные **Allure Steps** для каждого действия.
|
|
182
|
+
2. Прикрепляет **Скриншоты** и **Page Source** при падении.
|
|
183
|
+
3. Логирует **HTTP запросы/ответы** (если включено).
|
|
184
|
+
4. Интегрируется с платформой **TaaS** (Test as a Service) для аналитики.
|
|
185
|
+
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# persona-dsl: Фреймворк для автотестов на Python
|
|
2
|
+
|
|
3
|
+
`persona-dsl` — это современная библиотека для написания **E2E** и **API** автотестов, реализующая паттерн **Screenplay**.
|
|
4
|
+
Она предоставляет выразительный язык для описания сценариев, управляет браузером (через Playwright) и автоматически генерирует детальные отчеты Allure.
|
|
5
|
+
|
|
6
|
+
## 📦 Установка
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install persona-dsl
|
|
10
|
+
python -m playwright install --with-deps
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 🚀 Быстрый старт
|
|
16
|
+
|
|
17
|
+
### 1. Описание страницы (Page Object)
|
|
18
|
+
|
|
19
|
+
В `persona-dsl` используется **Универсальная Архитектура Элементов**.
|
|
20
|
+
Основной класс `Page` сам является элементом-контейнером. Вложенные элементы добавляются через `add_element`.
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
# pages/login_page.py
|
|
24
|
+
from persona_dsl.pages import Page
|
|
25
|
+
from persona_dsl.pages.elements import Input, Button
|
|
26
|
+
|
|
27
|
+
class LoginPage(Page):
|
|
28
|
+
def __init__(self):
|
|
29
|
+
super().__init__()
|
|
30
|
+
# Имя атрибута (self.username) будет использовано как имя элемента в отчетах
|
|
31
|
+
self.username = self.add_element(Input(xpath="//input[@id='user']", name="Логин"))
|
|
32
|
+
self.password = self.add_element(Input(xpath="//input[@id='pass']", name="Пароль"))
|
|
33
|
+
self.submit = self.add_element(Button(xpath="//button[@type='submit']", name="Вход"))
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 2. Написание теста
|
|
37
|
+
|
|
38
|
+
Тесты пишутся в стиле "Persona делает действия":
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
# tests/test_login.py
|
|
42
|
+
import pytest
|
|
43
|
+
from persona_dsl.ops.web import NavigateTo, Fill, Click
|
|
44
|
+
from persona_dsl.facts.web import CurrentPath
|
|
45
|
+
from persona_dsl.expectations.web import IsEqualTo
|
|
46
|
+
from pages.login_page import LoginPage
|
|
47
|
+
|
|
48
|
+
def test_login_flow(persona):
|
|
49
|
+
login_page = LoginPage()
|
|
50
|
+
|
|
51
|
+
# 1. Действия (Actions)
|
|
52
|
+
persona.make(
|
|
53
|
+
NavigateTo("/login"),
|
|
54
|
+
Fill(login_page.username, "admin"),
|
|
55
|
+
Fill(login_page.password, "secret"),
|
|
56
|
+
Click(login_page.submit)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# 2. Проверка (Verification)
|
|
60
|
+
# Получаем Факт (CurrentPath) и проверяем Ожидание (IsEqualTo)
|
|
61
|
+
current_path = persona.get(CurrentPath())
|
|
62
|
+
persona.check(current_path, IsEqualTo("/dashboard"))
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 🏗 Архитектура
|
|
68
|
+
|
|
69
|
+
### 1. Ключевые компоненты (Persona Core)
|
|
70
|
+
|
|
71
|
+
| Компонент | Назначение | Пример |
|
|
72
|
+
|-----------|------------|--------|
|
|
73
|
+
| **Persona** | Исполнитель. Хранит состояние и навыки. | `persona.make(...)` |
|
|
74
|
+
| **Skill** | "Навык". Дает доступ к инструментам. | `UseBrowser`, `UseAPI`, `UseDB` |
|
|
75
|
+
| **Ops** | Атомарная операция. Работает со Skill. | `Click`, `HttpRequest`, `ExecuteSQL` |
|
|
76
|
+
| **Step** | Бизнес-шаг. Группирует Ops. | `LoginStep`, `CreateOrder` |
|
|
77
|
+
| **Fact** | Запрос состояния (без изменений). | `CurrentPath`, `ElementText` |
|
|
78
|
+
| **Expectation** | Проверка значения. | `IsEqualTo`, `ContainsText` |
|
|
79
|
+
|
|
80
|
+
### 2. Универсальные Элементы (New!)
|
|
81
|
+
|
|
82
|
+
Больше нет разделения на `Element` и `ElementContainer`. Любой элемент может содержать другие элементы.
|
|
83
|
+
|
|
84
|
+
* **`element.add_element(...)`**: Регистрирует дочерний элемент.
|
|
85
|
+
* **Иерархия**: `Page -> Container -> Element`.
|
|
86
|
+
* **Локаторы**: Строятся автоматически по цепочке родителей.
|
|
87
|
+
|
|
88
|
+
### 3. Генераторный подход
|
|
89
|
+
Все шаги (`Step`, `CombinedStep`) — это генераторы, которые "выдают" (`yield`) операции для исполнения Персоной. Это позволяет `persona-dsl` перехватывать каждый шаг, логировать его в Allure и обрабатывать ошибки.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 🛠 Инструменты и Утилиты
|
|
94
|
+
|
|
95
|
+
### Генерация Page Objects
|
|
96
|
+
Не пишите селекторы вручную. Используйте генератор:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Снять ARIA-снапшот и сгенерировать класс страницы
|
|
100
|
+
persona-page-gen --url http://localhost:8080 --output pages/home.py
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Генерация API клиентов
|
|
104
|
+
```bash
|
|
105
|
+
# Генерация из OpenAPI/Swagger
|
|
106
|
+
persona-api-gen --url http://api.example.com/openapi.json --output skills/my_api.py
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Запуск тестов
|
|
110
|
+
|
|
111
|
+
Тесты запускаются стандартной командой pytest:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
pytest --env=dev tests/
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## ⚙️ Конфигурация
|
|
120
|
+
|
|
121
|
+
### `conftest.py`
|
|
122
|
+
Декларативное описание навыков и ролей:
|
|
123
|
+
```python
|
|
124
|
+
PERSONA_SKILLS = [BaseSkill.BROWSER, BaseSkill.API]
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `config/{env}.yaml`
|
|
128
|
+
Параметры окружения (dev, test, prod). Выбирается через `--env=test`.
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
base_url: "https://my-app.test"
|
|
132
|
+
browser:
|
|
133
|
+
headless: true
|
|
134
|
+
viewport: { width: 1920, height: 1080 }
|
|
135
|
+
reporting:
|
|
136
|
+
screenshot_on_fail: true
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 📊 Отчетность (Allure + TaaS)
|
|
142
|
+
|
|
143
|
+
Фреймворк автоматически:
|
|
144
|
+
1. Создает вложенные **Allure Steps** для каждого действия.
|
|
145
|
+
2. Прикрепляет **Скриншоты** и **Page Source** при падении.
|
|
146
|
+
3. Логирует **HTTP запросы/ответы** (если включено).
|
|
147
|
+
4. Интегрируется с платформой **TaaS** (Test as a Service) для аналитики.
|
|
148
|
+
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: persona-dsl
|
|
3
|
+
Version: 26.1.20.10
|
|
4
|
+
Summary: DSL для реализации паттерна Screenplay в Python-тестах.
|
|
5
|
+
Requires-Python: >=3.9
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: playwright==1.55.0
|
|
8
|
+
Requires-Dist: pytest
|
|
9
|
+
Requires-Dist: pytest-cov
|
|
10
|
+
Requires-Dist: allure-pytest
|
|
11
|
+
Requires-Dist: python-dotenv
|
|
12
|
+
Requires-Dist: pyyaml
|
|
13
|
+
Requires-Dist: pydantic<3,>=2
|
|
14
|
+
Requires-Dist: requests
|
|
15
|
+
Requires-Dist: pyhamcrest
|
|
16
|
+
Requires-Dist: redis
|
|
17
|
+
Requires-Dist: Faker
|
|
18
|
+
Requires-Dist: pillow
|
|
19
|
+
Requires-Dist: zeep
|
|
20
|
+
Requires-Dist: pg8000
|
|
21
|
+
Requires-Dist: oracledb
|
|
22
|
+
Requires-Dist: kafka-python
|
|
23
|
+
Requires-Dist: Unidecode>=1.3
|
|
24
|
+
Requires-Dist: black
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: black; extra == "dev"
|
|
27
|
+
Requires-Dist: ruff; extra == "dev"
|
|
28
|
+
Requires-Dist: mypy; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
30
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
31
|
+
Requires-Dist: types-requests; extra == "dev"
|
|
32
|
+
Requires-Dist: types-PyYAML; extra == "dev"
|
|
33
|
+
Requires-Dist: types-redis; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-timeout; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-xdist; extra == "dev"
|
|
37
|
+
|
|
38
|
+
# persona-dsl: Фреймворк для автотестов на Python
|
|
39
|
+
|
|
40
|
+
`persona-dsl` — это современная библиотека для написания **E2E** и **API** автотестов, реализующая паттерн **Screenplay**.
|
|
41
|
+
Она предоставляет выразительный язык для описания сценариев, управляет браузером (через Playwright) и автоматически генерирует детальные отчеты Allure.
|
|
42
|
+
|
|
43
|
+
## 📦 Установка
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install persona-dsl
|
|
47
|
+
python -m playwright install --with-deps
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 🚀 Быстрый старт
|
|
53
|
+
|
|
54
|
+
### 1. Описание страницы (Page Object)
|
|
55
|
+
|
|
56
|
+
В `persona-dsl` используется **Универсальная Архитектура Элементов**.
|
|
57
|
+
Основной класс `Page` сам является элементом-контейнером. Вложенные элементы добавляются через `add_element`.
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
# pages/login_page.py
|
|
61
|
+
from persona_dsl.pages import Page
|
|
62
|
+
from persona_dsl.pages.elements import Input, Button
|
|
63
|
+
|
|
64
|
+
class LoginPage(Page):
|
|
65
|
+
def __init__(self):
|
|
66
|
+
super().__init__()
|
|
67
|
+
# Имя атрибута (self.username) будет использовано как имя элемента в отчетах
|
|
68
|
+
self.username = self.add_element(Input(xpath="//input[@id='user']", name="Логин"))
|
|
69
|
+
self.password = self.add_element(Input(xpath="//input[@id='pass']", name="Пароль"))
|
|
70
|
+
self.submit = self.add_element(Button(xpath="//button[@type='submit']", name="Вход"))
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 2. Написание теста
|
|
74
|
+
|
|
75
|
+
Тесты пишутся в стиле "Persona делает действия":
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
# tests/test_login.py
|
|
79
|
+
import pytest
|
|
80
|
+
from persona_dsl.ops.web import NavigateTo, Fill, Click
|
|
81
|
+
from persona_dsl.facts.web import CurrentPath
|
|
82
|
+
from persona_dsl.expectations.web import IsEqualTo
|
|
83
|
+
from pages.login_page import LoginPage
|
|
84
|
+
|
|
85
|
+
def test_login_flow(persona):
|
|
86
|
+
login_page = LoginPage()
|
|
87
|
+
|
|
88
|
+
# 1. Действия (Actions)
|
|
89
|
+
persona.make(
|
|
90
|
+
NavigateTo("/login"),
|
|
91
|
+
Fill(login_page.username, "admin"),
|
|
92
|
+
Fill(login_page.password, "secret"),
|
|
93
|
+
Click(login_page.submit)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# 2. Проверка (Verification)
|
|
97
|
+
# Получаем Факт (CurrentPath) и проверяем Ожидание (IsEqualTo)
|
|
98
|
+
current_path = persona.get(CurrentPath())
|
|
99
|
+
persona.check(current_path, IsEqualTo("/dashboard"))
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 🏗 Архитектура
|
|
105
|
+
|
|
106
|
+
### 1. Ключевые компоненты (Persona Core)
|
|
107
|
+
|
|
108
|
+
| Компонент | Назначение | Пример |
|
|
109
|
+
|-----------|------------|--------|
|
|
110
|
+
| **Persona** | Исполнитель. Хранит состояние и навыки. | `persona.make(...)` |
|
|
111
|
+
| **Skill** | "Навык". Дает доступ к инструментам. | `UseBrowser`, `UseAPI`, `UseDB` |
|
|
112
|
+
| **Ops** | Атомарная операция. Работает со Skill. | `Click`, `HttpRequest`, `ExecuteSQL` |
|
|
113
|
+
| **Step** | Бизнес-шаг. Группирует Ops. | `LoginStep`, `CreateOrder` |
|
|
114
|
+
| **Fact** | Запрос состояния (без изменений). | `CurrentPath`, `ElementText` |
|
|
115
|
+
| **Expectation** | Проверка значения. | `IsEqualTo`, `ContainsText` |
|
|
116
|
+
|
|
117
|
+
### 2. Универсальные Элементы (New!)
|
|
118
|
+
|
|
119
|
+
Больше нет разделения на `Element` и `ElementContainer`. Любой элемент может содержать другие элементы.
|
|
120
|
+
|
|
121
|
+
* **`element.add_element(...)`**: Регистрирует дочерний элемент.
|
|
122
|
+
* **Иерархия**: `Page -> Container -> Element`.
|
|
123
|
+
* **Локаторы**: Строятся автоматически по цепочке родителей.
|
|
124
|
+
|
|
125
|
+
### 3. Генераторный подход
|
|
126
|
+
Все шаги (`Step`, `CombinedStep`) — это генераторы, которые "выдают" (`yield`) операции для исполнения Персоной. Это позволяет `persona-dsl` перехватывать каждый шаг, логировать его в Allure и обрабатывать ошибки.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 🛠 Инструменты и Утилиты
|
|
131
|
+
|
|
132
|
+
### Генерация Page Objects
|
|
133
|
+
Не пишите селекторы вручную. Используйте генератор:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Снять ARIA-снапшот и сгенерировать класс страницы
|
|
137
|
+
persona-page-gen --url http://localhost:8080 --output pages/home.py
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Генерация API клиентов
|
|
141
|
+
```bash
|
|
142
|
+
# Генерация из OpenAPI/Swagger
|
|
143
|
+
persona-api-gen --url http://api.example.com/openapi.json --output skills/my_api.py
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Запуск тестов
|
|
147
|
+
|
|
148
|
+
Тесты запускаются стандартной командой pytest:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pytest --env=dev tests/
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## ⚙️ Конфигурация
|
|
157
|
+
|
|
158
|
+
### `conftest.py`
|
|
159
|
+
Декларативное описание навыков и ролей:
|
|
160
|
+
```python
|
|
161
|
+
PERSONA_SKILLS = [BaseSkill.BROWSER, BaseSkill.API]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### `config/{env}.yaml`
|
|
165
|
+
Параметры окружения (dev, test, prod). Выбирается через `--env=test`.
|
|
166
|
+
|
|
167
|
+
```yaml
|
|
168
|
+
base_url: "https://my-app.test"
|
|
169
|
+
browser:
|
|
170
|
+
headless: true
|
|
171
|
+
viewport: { width: 1920, height: 1080 }
|
|
172
|
+
reporting:
|
|
173
|
+
screenshot_on_fail: true
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## 📊 Отчетность (Allure + TaaS)
|
|
179
|
+
|
|
180
|
+
Фреймворк автоматически:
|
|
181
|
+
1. Создает вложенные **Allure Steps** для каждого действия.
|
|
182
|
+
2. Прикрепляет **Скриншоты** и **Page Source** при падении.
|
|
183
|
+
3. Логирует **HTTP запросы/ответы** (если включено).
|
|
184
|
+
4. Интегрируется с платформой **TaaS** (Test as a Service) для аналитики.
|
|
185
|
+
|