diff --git a/README.md b/README.md index dc95638..1ea4d08 100644 --- a/README.md +++ b/README.md @@ -135,3 +135,315 @@ result = runner.run() print(result.passed) # True/False ``` + +--- + +# YAML Readers (yamlreaders/) + +## Обзор + +Модуль для парсинга тест-спецификаций из различных форматов и конвертации их во внутреннюю модель `TestModel`. + +Поддерживаемые форматы: +- **Кастомный YAML** — собственный формат проекта +- **Postman Collection v2.1** — экспорт из Postman +- **OpenAPI 3.0/3.1** — спецификация API + +## Архитектура + +``` +┌─────────────────────────────────────────────────┐ +│ YAML Readers │ +│ ┌─────────────┐ ┌─────────────┐ ┌──────────┐│ +│ │ YamlReader │ │ PostmanReader│ │OpenAPIReader│ +│ └──────┬──────┘ └──────┬──────┘ └─────┬────┘│ +│ └────────────────┼────────────────┘ │ +│ ▼ │ +│ TestModel (ITM) │ +└─────────────────────────────────────────────────┘ +``` + +## Классы + +### BaseReader (yamlreaders/base.py) + +Абстрактный базовый класс для всех парсеров. + +| Метод | Возвращаемое значение | Описание | +|-------|----------------------|----------| +| validate(source) | bool | Проверяет валидность файла | +| parse(source) | TestModel | Конвертирует файл в TestModel | +| load_yaml(source) | dict | Загружает YAML файл | + +**Параметры:** +- `source: str | Path` — путь к YAML файлу + +**Исключения:** +- `FileNotFoundError` — файл не найден +- `ParseError` — ошибка парсинга YAML + +--- + +### YamlReader (yamlreaders/yaml_reader.py) + +Парсер для кастомного формата YAML проекта. + +**Формат входного файла:** + +```yaml +name: "Test Name" +base_url: http://localhost:8080 +variables: + email: test@example.com + password: Test123! + +steps: + - name: "Step Name" + request: + method: POST + url: /api/endpoint + headers: + Content-Type: application/json + body: + key: value + timeout: 30 + extract: + - name: variable_name + json_path: "$.field" + source: body + assert: + - type: status + value: 200 + - type: json + path: "$.id" + operator: exists +``` + +**Методы:** + +| Метод | Возвращаемое значение | Описание | +|-------|----------------------|----------| +| validate(source) | bool | Проверяет наличие steps, request, method | +| parse(source) | TestModel | Парсит YAML в TestModel | + +**Пример использования:** + +```python +from yamlreaders import YamlReader + +reader = YamlReader() + +# Проверка валидности +if reader.validate("tests/api.yaml"): + model = reader.parse("tests/api.yaml") + print(model.name, len(model.steps)) +``` + +--- + +### PostmanReader (yamlreaders/postman_reader.py) + +Парсер для Postman Collection v2/v2.1. + +**Формат входного файла (YAML):** + +```yaml +info: + name: "Collection Name" + schema: "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + +variable: + - key: base_url + value: http://localhost:8080 + - key: email + value: test@example.com + +item: + - name: "Request Name" + request: + method: POST + url: + raw: "{{base_url}}/api/login" + host: + - "{{base_url}}" + path: + - api + - login + header: + - key: Content-Type + value: application/json + body: + mode: raw + raw: '{"email": "{{email}}"}' + event: + - listen: test + script: + exec: + - "pm.environment.set('token', pm.response.json().token);" +``` + +**Методы:** + +| Метод | Возвращаемое значение | Описание | +|-------|----------------------|----------| +| validate(source) | bool | Проверяет наличие info и item | +| parse(source) | TestModel | Парсит Postman Collection в TestModel | + +**Особенности парсинга:** + +| Функция | Описание | +|---------|----------| +| Extract variables | Извлекает переменные из `variable[]` | +| Extract base_url | Ищет переменную `base_url` | +| Parse nested items | Рекурсивно обходит вложенные папки | +| Parse request body | Конвертирует `raw`, `urlencoded`, `formdata` | +| Parse test scripts | Извлекает `pm.environment.set()` для extraction | + +**Пример использования:** + +```python +from yamlreaders import PostmanReader + +reader = PostmanReader() + +if reader.validate("exports/collection.yaml"): + model = reader.parse("exports/collection.yaml") + print(model.name, len(model.steps)) +``` + +--- + +### OpenAPIReader (yamlreaders/openapi_reader.py) + +Парсер для OpenAPI 3.0/3.1 спецификаций. + +**Формат входного файла (YAML):** + +```yaml +openapi: "3.0.0" +info: + title: "API Name" + version: "1.0.0" + +servers: + - url: http://localhost:8080 + +paths: + /api/login: + post: + operationId: "loginUser" + summary: "Login user" + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + type: string + password: + type: string + responses: + "200": + description: "Success" + content: + application/json: + schema: + type: object + properties: + token: + type: string +``` + +**Методы:** + +| Метод | Возвращаемое значение | Описание | +|-------|----------------------|----------| +| validate(source) | bool | Проверяет наличие openapi и paths | +| parse(source) | TestModel | Парсит OpenAPI в TestModel | + +**Особенности парсинга:** + +| Функция | Описание | +|---------|----------| +| Extract base_url | Берёт URL из `servers[0]` | +| Extract auth | Парсит `securitySchemes` (basic, bearer, apiKey, oauth2) | +| Parse paths | Конвертирует все methods (GET, POST, PUT...) в шаги | +| Generate request body | Создаёт example body из `schema` | +| Generate asserts | Автоматически добавляет проверку status code | +| Generate extracts | Извлекает поля из response schema | + +**Пример использования:** + +```python +from yamlreaders import OpenAPIReader + +reader = OpenAPIReader() + +if reader.validate("docs/openapi.yaml"): + model = reader.parse("docs/openapi.yaml") + print(model.name, len(model.steps)) +``` + +--- + +## Автоопределение формата + +Функция `get_reader()` автоматически определяет формат файла и возвращаетappropriate reader. + +```python +from yamlreaders import get_reader + +reader = get_reader("tests/api.yaml") +model = reader.parse("tests/api.yaml") +``` + +**Логика определения:** + +| Признак | Формат | Reader | +|---------|--------|--------| +| `openapi:` в первой строке | OpenAPI | OpenAPIReader | +| `"info"` и `"item"` в JSON | Postman | PostmanReader | +| Иначе | Кастомный YAML | YamlReader | + +--- + +## Исключения + +### ParseError + +Выбрасывается при ошибке парсинга YAML. + +```python +from yamlreaders.base import ParseError + +try: + model = reader.parse("invalid.yaml") +except ParseError as e: + print(f"Error at line {e.line}: {e}") +``` + +--- + +## Полный пример + +```python +from yamlreaders import get_reader +from models import Context, TestRunner + +# Определяем формат и парсим +reader = get_reader("tests/api.yaml") +model = reader.parse("tests/api.yaml") + +# Создаём контекст и запускаем +context = Context(model) +runner = TestRunner(context) +result = runner.run() + +# Выводим результат +for step in result.steps: + status = "✓" if step.passed else "✗" + print(f"{status} {step.name}") + +print(f"\n{'PASSED' if result.passed else 'FAILED'}") +```