1086 lines
19 KiB
Markdown
1086 lines
19 KiB
Markdown
# Контекст проекта
|
||
|
||
Мы разрабатываем стартап/проект для **автоматизированного end-to-end тестирования пользовательских API через GitHub Actions**.
|
||
|
||
## Главная идея
|
||
|
||
Продукт должен позволять разработчику проверить, что его backend-приложение действительно работает целиком с точки зрения пользователя.
|
||
|
||
Это НЕ API monitoring и НЕ сервис, который постоянно проверяет API.
|
||
|
||
Тест запускается **один раз** в рамках CI/CD pipeline.
|
||
|
||
Основной сценарий:
|
||
|
||
```text
|
||
GitHub Actions Job
|
||
│
|
||
├── Checkout repository
|
||
│
|
||
├── Build application
|
||
│
|
||
├── Start application
|
||
│
|
||
├── Wait until application is ready
|
||
│
|
||
├── Run API E2E tests
|
||
│
|
||
├── Generate report
|
||
│
|
||
└── Cleanup
|
||
```
|
||
|
||
Например:
|
||
|
||
```text
|
||
POST /register
|
||
↓
|
||
POST /login
|
||
↓
|
||
GET /profile
|
||
↓
|
||
POST /posts
|
||
↓
|
||
GET /posts/{id}
|
||
↓
|
||
DELETE /posts/{id}
|
||
```
|
||
|
||
Если любой шаг ломается, GitHub Actions Job должен завершиться с ошибкой.
|
||
|
||
---
|
||
|
||
# Главная ценность продукта
|
||
|
||
Продукт должен проверять не отдельные endpoints, а **полноценные пользовательские сценарии**.
|
||
|
||
Например:
|
||
|
||
```text
|
||
Register user
|
||
↓
|
||
получить user_id
|
||
↓
|
||
Login
|
||
↓
|
||
получить JWT
|
||
↓
|
||
Get profile с JWT
|
||
↓
|
||
Create post
|
||
↓
|
||
получить post_id
|
||
↓
|
||
Get post
|
||
↓
|
||
Delete post
|
||
```
|
||
|
||
Данные между запросами должны автоматически передаваться.
|
||
|
||
Пример:
|
||
|
||
```text
|
||
login.response.token
|
||
↓
|
||
Authorization: Bearer {{token}}
|
||
|
||
create.response.id
|
||
↓
|
||
GET /posts/{{post_id}}
|
||
```
|
||
|
||
---
|
||
|
||
# Важное отличие от обычного API monitoring
|
||
|
||
Не нужно постоянно проверять:
|
||
|
||
```text
|
||
GET /health
|
||
GET /health
|
||
GET /health
|
||
```
|
||
|
||
Нас интересует одноразовая проверка:
|
||
|
||
> "Я только что поднял приложение. Может ли реальный пользователь пройти через основной сценарий и работает ли API целиком?"
|
||
|
||
---
|
||
|
||
# Основной execution environment
|
||
|
||
Основной execution environment — **GitHub Actions**.
|
||
|
||
Очень важно:
|
||
|
||
Тестируемое приложение должно запускаться **в рамках того же GitHub Actions Job**, в котором выполняется API E2E test.
|
||
|
||
Например:
|
||
|
||
```yaml
|
||
jobs:
|
||
e2e:
|
||
runs-on: ubuntu-latest
|
||
|
||
steps:
|
||
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Start application
|
||
run: docker compose -f docker-compose.test.yml up -d
|
||
|
||
- name: API E2E
|
||
uses: our-org/api-e2e@v1
|
||
with:
|
||
spec: tests/api.yaml
|
||
base-url: http://localhost:8080
|
||
|
||
- name: Cleanup
|
||
if: always()
|
||
run: docker compose -f docker-compose.test.yml down -v
|
||
```
|
||
|
||
В будущем желательно, чтобы сам Action мог запускать Docker Compose и выполнять cleanup автоматически.
|
||
|
||
---
|
||
|
||
# Требование к Docker
|
||
|
||
Основной вариант для MVP:
|
||
|
||
```text
|
||
Docker
|
||
Docker Compose
|
||
```
|
||
|
||
Типичное приложение:
|
||
|
||
```text
|
||
docker-compose.test.yml
|
||
|
||
api
|
||
postgres
|
||
redis
|
||
etc.
|
||
```
|
||
|
||
Продукт должен уметь:
|
||
|
||
1. запустить приложение;
|
||
2. дождаться readiness;
|
||
3. проверить healthcheck;
|
||
4. выполнить тесты;
|
||
5. собрать результаты;
|
||
6. удалить контейнеры;
|
||
7. выполнить cleanup даже при падении тестов.
|
||
|
||
---
|
||
|
||
# API Test Engine
|
||
|
||
Главное ядро проекта — собственный API Test Engine.
|
||
|
||
Он должен поддерживать:
|
||
|
||
```text
|
||
GET
|
||
POST
|
||
PUT
|
||
PATCH
|
||
DELETE
|
||
HEAD
|
||
OPTIONS
|
||
```
|
||
|
||
Каждый request должен иметь:
|
||
|
||
```text
|
||
Method
|
||
URL
|
||
Headers
|
||
Query parameters
|
||
Body
|
||
Timeout
|
||
Variables
|
||
Assertions
|
||
Extraction
|
||
```
|
||
|
||
---
|
||
|
||
# Variables
|
||
|
||
Нужны обычные переменные:
|
||
|
||
```yaml
|
||
variables:
|
||
email: test@example.com
|
||
password: Test123!
|
||
```
|
||
|
||
Использование:
|
||
|
||
```yaml
|
||
url: /api/users/{{user_id}}
|
||
```
|
||
|
||
---
|
||
|
||
# Dynamic variables
|
||
|
||
Нужна генерация тестовых данных:
|
||
|
||
```text
|
||
{{random.uuid}}
|
||
{{random.email}}
|
||
{{random.username}}
|
||
{{random.string}}
|
||
{{random.number}}
|
||
{{timestamp}}
|
||
```
|
||
|
||
Это необходимо для сценариев регистрации и создания ресурсов.
|
||
|
||
---
|
||
|
||
# Extraction
|
||
|
||
Один request должен уметь извлекать данные из response и передавать их следующим request.
|
||
|
||
Например:
|
||
|
||
```yaml
|
||
- name: Login
|
||
|
||
request:
|
||
method: POST
|
||
url: /api/login
|
||
|
||
extract:
|
||
token: "$.token"
|
||
```
|
||
|
||
Следующий request:
|
||
|
||
```yaml
|
||
- name: Profile
|
||
|
||
request:
|
||
method: GET
|
||
url: /api/profile
|
||
|
||
headers:
|
||
Authorization: "Bearer {{token}}"
|
||
```
|
||
|
||
Для JSON желательно использовать JSONPath или совместимый механизм.
|
||
|
||
---
|
||
|
||
# Assertions
|
||
|
||
Минимально необходимы:
|
||
|
||
```text
|
||
HTTP status
|
||
JSON field exists
|
||
JSON value
|
||
Header
|
||
Response time
|
||
Regex
|
||
Contains
|
||
Equals
|
||
Not equals
|
||
Exists
|
||
```
|
||
|
||
Например:
|
||
|
||
```yaml
|
||
expect:
|
||
status: 200
|
||
|
||
json:
|
||
user.id:
|
||
exists: true
|
||
|
||
user.email:
|
||
equals: "{{email}}"
|
||
```
|
||
|
||
---
|
||
|
||
# OpenAPI
|
||
|
||
Продукт обязательно должен поддерживать:
|
||
|
||
```text
|
||
OpenAPI 3.0
|
||
OpenAPI 3.1
|
||
YAML
|
||
JSON
|
||
```
|
||
|
||
OpenAPI должен использоваться для:
|
||
|
||
* импорта API;
|
||
* обнаружения endpoints;
|
||
* определения HTTP methods;
|
||
* определения parameters;
|
||
* определения request body;
|
||
* определения response schemas;
|
||
* генерации базовых тестов;
|
||
* schema validation.
|
||
|
||
Например:
|
||
|
||
```text
|
||
OpenAPI
|
||
↓
|
||
Parser
|
||
↓
|
||
Internal Test Model
|
||
↓
|
||
API Test Engine
|
||
```
|
||
|
||
---
|
||
|
||
# Postman
|
||
|
||
Продукт должен поддерживать импорт:
|
||
|
||
```text
|
||
Postman Collection v2
|
||
Postman Collection v2.1
|
||
```
|
||
|
||
Нужно поддержать:
|
||
|
||
* requests;
|
||
* methods;
|
||
* URLs;
|
||
* headers;
|
||
* query parameters;
|
||
* body;
|
||
* variables;
|
||
* environments;
|
||
* authentication;
|
||
* request chains;
|
||
* basic assertions;
|
||
* extracted variables.
|
||
|
||
Очень важно:
|
||
|
||
OpenAPI и Postman **не должны напрямую использоваться Test Engine**.
|
||
|
||
Оба формата должны преобразовываться во внутреннюю модель.
|
||
|
||
```text
|
||
Postman ────────┐
|
||
↓
|
||
Internal Test Model
|
||
↑
|
||
OpenAPI ────────┘
|
||
↓
|
||
Test Engine
|
||
```
|
||
|
||
Это позволит позже добавлять другие форматы.
|
||
|
||
---
|
||
|
||
# Authentication
|
||
|
||
Минимально:
|
||
|
||
```text
|
||
None
|
||
Basic Auth
|
||
Bearer Token
|
||
API Key
|
||
OAuth 2.0
|
||
```
|
||
|
||
Особенно важен сценарий:
|
||
|
||
```text
|
||
POST /login
|
||
↓
|
||
extract JWT
|
||
↓
|
||
Bearer {{token}}
|
||
↓
|
||
GET /profile
|
||
```
|
||
|
||
---
|
||
|
||
# Reporting
|
||
|
||
После теста должны создаваться:
|
||
|
||
```text
|
||
Console report
|
||
JUnit XML
|
||
JSON
|
||
HTML
|
||
GitHub Step Summary
|
||
```
|
||
|
||
Пример:
|
||
|
||
```text
|
||
API E2E Tests
|
||
|
||
✓ Register 184ms
|
||
✓ Login 92ms
|
||
✓ Profile 61ms
|
||
✓ Create post 142ms
|
||
✗ Delete post 83ms
|
||
|
||
5 / 6 passed
|
||
|
||
FAILED:
|
||
Delete post
|
||
|
||
Expected: 204
|
||
Received: 500
|
||
```
|
||
|
||
GitHub Actions должен получать корректный exit code:
|
||
|
||
```text
|
||
0 = success
|
||
1 = failure
|
||
```
|
||
|
||
Также нужны GitHub annotations:
|
||
|
||
```text
|
||
::error
|
||
::warning
|
||
::notice
|
||
::group
|
||
```
|
||
|
||
---
|
||
|
||
# Local CLI
|
||
|
||
Хотя основное выполнение происходит через GitHub Actions, Test Engine должен работать локально.
|
||
|
||
Например:
|
||
|
||
```bash
|
||
api-e2e run tests/api.yaml
|
||
```
|
||
|
||
или:
|
||
|
||
```bash
|
||
api-e2e run \
|
||
--spec tests/api.yaml \
|
||
--base-url http://localhost:8080
|
||
```
|
||
|
||
Также нужны:
|
||
|
||
```bash
|
||
api-e2e validate
|
||
api-e2e import
|
||
api-e2e report
|
||
```
|
||
|
||
Локальный запуск нужен для debugging.
|
||
|
||
Один и тот же тест должен работать:
|
||
|
||
```text
|
||
Local
|
||
↓
|
||
api-e2e CLI
|
||
|
||
CI
|
||
↓
|
||
GitHub Action
|
||
```
|
||
|
||
---
|
||
|
||
# Будущая SaaS-часть
|
||
|
||
После создания рабочего Test Engine можно сделать веб-платформу.
|
||
|
||
Frontend:
|
||
|
||
```text
|
||
Dashboard
|
||
Projects
|
||
Test scenarios
|
||
Scenario editor
|
||
Request editor
|
||
Assertions editor
|
||
Run history
|
||
Test results
|
||
Logs
|
||
Reports
|
||
GitHub integration
|
||
```
|
||
|
||
Backend:
|
||
|
||
```text
|
||
Users
|
||
Projects
|
||
Repositories
|
||
Test scenarios
|
||
Test runs
|
||
Results
|
||
GitHub integrations
|
||
```
|
||
|
||
Backend НЕ должен выполнять пользовательские API-тесты напрямую.
|
||
|
||
Основное выполнение должно происходить в GitHub Actions.
|
||
|
||
---
|
||
|
||
# GitHub App
|
||
|
||
В дальнейшем желательно сделать полноценный GitHub App вместо ручного PAT.
|
||
|
||
Пользователь:
|
||
|
||
```text
|
||
Connect GitHub
|
||
↓
|
||
Install GitHub App
|
||
↓
|
||
Select repository
|
||
↓
|
||
Select tests
|
||
```
|
||
|
||
GitHub integration должна позволять запускать тесты:
|
||
|
||
```text
|
||
Pull Request
|
||
Push
|
||
Manual
|
||
Release
|
||
Schedule
|
||
```
|
||
|
||
---
|
||
|
||
# Рекомендуемый стек
|
||
|
||
Мы остановились на TypeScript.
|
||
|
||
## Test Engine
|
||
|
||
```text
|
||
TypeScript
|
||
Node.js
|
||
```
|
||
|
||
## CLI
|
||
|
||
```text
|
||
TypeScript
|
||
Commander или аналог
|
||
```
|
||
|
||
## GitHub Action
|
||
|
||
```text
|
||
TypeScript
|
||
Node.js
|
||
```
|
||
|
||
## Backend
|
||
|
||
```text
|
||
TypeScript
|
||
Node.js
|
||
Fastify
|
||
```
|
||
|
||
## Database
|
||
|
||
```text
|
||
PostgreSQL
|
||
```
|
||
|
||
## ORM
|
||
|
||
```text
|
||
Drizzle или Prisma
|
||
```
|
||
|
||
## Frontend
|
||
|
||
```text
|
||
Next.js
|
||
React
|
||
TypeScript
|
||
Tailwind
|
||
```
|
||
|
||
## Infrastructure
|
||
|
||
```text
|
||
Docker
|
||
Docker Compose
|
||
GitHub Actions
|
||
```
|
||
|
||
---
|
||
|
||
# Предполагаемая архитектура
|
||
|
||
```text
|
||
GitHub Actions
|
||
│
|
||
▼
|
||
┌─────────────────┐
|
||
│ API E2E CLI │
|
||
│ / Action │
|
||
└────────┬────────┘
|
||
│
|
||
┌──────────────┼──────────────┐
|
||
▼ ▼ ▼
|
||
OpenAPI Parser Postman Parser Config
|
||
│ │ │
|
||
└──────────────┼──────────────┘
|
||
▼
|
||
Internal Test Model
|
||
│
|
||
▼
|
||
Test Engine
|
||
│
|
||
┌──────────────┼──────────────┐
|
||
▼ ▼ ▼
|
||
HTTP Variables Assertions
|
||
│ │ │
|
||
└──────────────┼──────────────┘
|
||
▼
|
||
Reports
|
||
```
|
||
|
||
---
|
||
|
||
# Структура репозитория
|
||
|
||
Предполагаемая структура:
|
||
|
||
```text
|
||
api-e2e/
|
||
│
|
||
├── packages/
|
||
│ ├── engine/
|
||
│ │ ├── http/
|
||
│ │ ├── assertions/
|
||
│ │ ├── variables/
|
||
│ │ ├── extraction/
|
||
│ │ ├── runner/
|
||
│ │ └── reports/
|
||
│ │
|
||
│ ├── openapi/
|
||
│ │ └── parser/
|
||
│ │
|
||
│ ├── postman/
|
||
│ │ └── parser/
|
||
│ │
|
||
│ ├── config/
|
||
│ └── cli/
|
||
│
|
||
├── action/
|
||
│ ├── action.yml
|
||
│ └── src/
|
||
│
|
||
├── backend/
|
||
├── frontend/
|
||
│
|
||
├── examples/
|
||
│ ├── basic/
|
||
│ ├── docker-compose/
|
||
│ ├── openapi/
|
||
│ └── postman/
|
||
│
|
||
├── tests/
|
||
│
|
||
├── docker-compose.yml
|
||
├── package.json
|
||
└── README.md
|
||
```
|
||
|
||
---
|
||
|
||
# Очередность разработки
|
||
|
||
Очень важно: **не начинать сразу с SaaS/frontend/backend**.
|
||
|
||
Разработка должна идти в следующем порядке.
|
||
|
||
## Phase 1 — Test Engine
|
||
|
||
Сначала сделать полностью автономный CLI.
|
||
|
||
Цель:
|
||
|
||
```bash
|
||
api-e2e run tests/api.yaml
|
||
```
|
||
|
||
Он должен:
|
||
|
||
```text
|
||
Load config
|
||
↓
|
||
Execute requests
|
||
↓
|
||
Pass variables
|
||
↓
|
||
Extract values
|
||
↓
|
||
Run assertions
|
||
↓
|
||
Return result
|
||
↓
|
||
Exit code
|
||
```
|
||
|
||
После этой фазы можно локально протестировать полноценный E2E workflow.
|
||
|
||
---
|
||
|
||
## Phase 2 — Variables + Extraction + Assertions
|
||
|
||
Добавить:
|
||
|
||
* static variables;
|
||
* environment variables;
|
||
* random data;
|
||
* JSON extraction;
|
||
* JSONPath;
|
||
* status assertions;
|
||
* JSON assertions;
|
||
* header assertions;
|
||
* response-time assertions;
|
||
* regex;
|
||
* contains;
|
||
* equals;
|
||
* exists.
|
||
|
||
---
|
||
|
||
## Phase 3 — Docker
|
||
|
||
Добавить:
|
||
|
||
* Docker Compose;
|
||
* startup;
|
||
* readiness;
|
||
* healthcheck;
|
||
* timeout;
|
||
* logs;
|
||
* cleanup;
|
||
* cleanup on failure.
|
||
|
||
Цель:
|
||
|
||
```bash
|
||
api-e2e run \
|
||
--compose docker-compose.test.yml \
|
||
--spec tests/api.yaml
|
||
```
|
||
|
||
Должно происходить:
|
||
|
||
```text
|
||
Start containers
|
||
↓
|
||
Wait for API
|
||
↓
|
||
Run tests
|
||
↓
|
||
Generate report
|
||
↓
|
||
Cleanup
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 4 — GitHub Action
|
||
|
||
После того как CLI работает локально:
|
||
|
||
* action.yml;
|
||
* inputs;
|
||
* outputs;
|
||
* exit codes;
|
||
* GitHub annotations;
|
||
* GitHub Step Summary;
|
||
* JUnit;
|
||
* artifacts.
|
||
|
||
Цель:
|
||
|
||
```yaml
|
||
- uses: our-org/api-e2e@v1
|
||
with:
|
||
spec: tests/api.yaml
|
||
compose: docker-compose.test.yml
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 5 — OpenAPI
|
||
|
||
Добавить:
|
||
|
||
* OpenAPI 3.0;
|
||
* OpenAPI 3.1;
|
||
* YAML;
|
||
* JSON;
|
||
* endpoint discovery;
|
||
* request generation;
|
||
* response schema validation;
|
||
* authentication;
|
||
* test generation.
|
||
|
||
---
|
||
|
||
## Phase 6 — Postman
|
||
|
||
Добавить:
|
||
|
||
* Collection v2;
|
||
* Collection v2.1;
|
||
* environments;
|
||
* variables;
|
||
* headers;
|
||
* authentication;
|
||
* body;
|
||
* assertions;
|
||
* extracted variables;
|
||
* chained requests.
|
||
|
||
---
|
||
|
||
## Phase 7 — Web UI
|
||
|
||
Только после рабочего CLI и GitHub Action.
|
||
|
||
Добавить:
|
||
|
||
* authentication;
|
||
* projects;
|
||
* GitHub integration;
|
||
* test scenario editor;
|
||
* request editor;
|
||
* assertions editor;
|
||
* run history;
|
||
* results;
|
||
* logs;
|
||
* reports.
|
||
|
||
---
|
||
|
||
## Phase 8 — GitHub App
|
||
|
||
Добавить:
|
||
|
||
* GitHub App;
|
||
* repository selection;
|
||
* workflow integration;
|
||
* permissions;
|
||
* webhooks;
|
||
* automatic PR integration.
|
||
|
||
---
|
||
|
||
## Phase 9 — SaaS
|
||
|
||
После появления рабочего продукта:
|
||
|
||
* accounts;
|
||
* teams;
|
||
* projects;
|
||
* usage limits;
|
||
* billing;
|
||
* plans;
|
||
* cloud storage;
|
||
* test history.
|
||
|
||
---
|
||
|
||
# MVP
|
||
|
||
Первый MVP должен содержать только:
|
||
|
||
* GitHub Action;
|
||
* CLI;
|
||
* YAML test specification;
|
||
* HTTP requests;
|
||
* variables;
|
||
* extraction;
|
||
* assertions;
|
||
* Docker Compose;
|
||
* startup;
|
||
* readiness;
|
||
* cleanup;
|
||
* JUnit;
|
||
* GitHub Summary;
|
||
* OpenAPI import;
|
||
* Postman import.
|
||
|
||
Не делать в MVP:
|
||
|
||
* API monitoring;
|
||
* browser testing;
|
||
* load testing;
|
||
* Kubernetes;
|
||
* собственные CI runners;
|
||
* AI;
|
||
* десятки интеграций;
|
||
* сложную SaaS-платформу.
|
||
|
||
---
|
||
|
||
# Безопасность
|
||
|
||
Это критически важная часть.
|
||
|
||
Тесты могут содержать:
|
||
|
||
```text
|
||
API keys
|
||
Passwords
|
||
JWT
|
||
Cookies
|
||
Database credentials
|
||
Production secrets
|
||
```
|
||
|
||
Поэтому:
|
||
|
||
* secrets нельзя писать в logs;
|
||
* Authorization headers должны маскироваться;
|
||
* passwords нельзя сохранять;
|
||
* secrets должны передаваться через GitHub Secrets;
|
||
* response body не должен отправляться на наш сервер без явного разрешения;
|
||
* необходимо ограничивать размеры response;
|
||
* необходимо ограничивать timeout;
|
||
* необходимо валидировать URLs;
|
||
* необходимо предотвращать SSRF;
|
||
* нельзя выполнять произвольные shell-команды из пользовательской конфигурации;
|
||
* выполнение тестов должно происходить в изолированном GitHub Actions environment.
|
||
|
||
Особенно важно:
|
||
|
||
**Backend SaaS не должен напрямую выполнять произвольные HTTP-запросы пользователей.**
|
||
|
||
---
|
||
|
||
# Главный принцип разработки
|
||
|
||
Не пытаться сразу создать огромную платформу.
|
||
|
||
Сначала должно работать:
|
||
|
||
```text
|
||
Docker Compose
|
||
↓
|
||
Application
|
||
↓
|
||
API E2E Engine
|
||
↓
|
||
Assertions
|
||
↓
|
||
Report
|
||
↓
|
||
Cleanup
|
||
```
|
||
|
||
Потом:
|
||
|
||
```text
|
||
CLI
|
||
↓
|
||
GitHub Action
|
||
```
|
||
|
||
Потом:
|
||
|
||
```text
|
||
OpenAPI
|
||
+
|
||
Postman
|
||
```
|
||
|
||
И только потом:
|
||
|
||
```text
|
||
Frontend
|
||
+
|
||
Backend
|
||
+
|
||
GitHub App
|
||
+
|
||
SaaS
|
||
```
|
||
|
||
---
|
||
|
||
# Конечная концепция продукта
|
||
|
||
Продукт должен отвечать на простой вопрос:
|
||
|
||
> **«Если я только что поднял своё приложение, может ли реальный пользователь пройти через основной API-сценарий от начала до конца?»**
|
||
|
||
Пример:
|
||
|
||
```text
|
||
Application started
|
||
↓
|
||
Healthcheck
|
||
↓
|
||
Register
|
||
↓
|
||
Login
|
||
↓
|
||
Get profile
|
||
↓
|
||
Create resource
|
||
↓
|
||
Get resource
|
||
↓
|
||
Update resource
|
||
↓
|
||
Delete resource
|
||
↓
|
||
PASS
|
||
```
|
||
|
||
В идеале пользователь должен иметь возможность взять существующий:
|
||
|
||
```text
|
||
OpenAPI
|
||
```
|
||
|
||
или:
|
||
|
||
```text
|
||
Postman Collection
|
||
```
|
||
|
||
и практически сразу получить готовый E2E-тест, который можно запускать локально и в GitHub Actions.
|
||
|
||
Главная конкурентная идея продукта:
|
||
|
||
> **Не заменять Postman или OpenAPI, а превращать существующие API-описания в воспроизводимые E2E CI-тесты, которые проверяют реальный пользовательский сценарий на только что запущенном приложении.**
|