TorbatYar/backend/services/experience/app/tests/test_api.py
Mortezakoohjani 203671a7bf feat(experience): ship Experience Platform phases 11.0-11.10
Add the experience service with sites through analytics/AI hooks, migrations through 0011, and phase docs/manifests marking the track complete.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 11:43:10 +03:30

154 lines
5.4 KiB
Python

"""API foundation flow — Experience Phase 11.0."""
from __future__ import annotations
import pytest
from app.events.publisher import get_event_publisher
from app.events.types import ExperienceEventType
from app.tests.conftest import TENANT_A, TENANT_B, tenant_headers
@pytest.mark.asyncio
async def test_health(client):
resp = await client.get("/health")
assert resp.status_code == 200
body = resp.json()
assert body["service"] == "experience-service"
assert body["status"] == "ok"
assert body["version"] == "0.11.10.0"
@pytest.mark.asyncio
async def test_capabilities_and_metrics(client):
caps = await client.get("/capabilities")
assert caps.status_code == 200
body = caps.json()
assert body["phase"] == "11.10"
assert body["features"]["widgets"] is True
assert body["features"]["consumer_connectors"] is True
assert body["features"]["analytics"] is True
assert body["features"]["ai_content"] is True
assert body["commercial_product"] == "Torbat Pages"
assert body["features"]["foundation"] is True
assert body["features"]["sites"] is True
assert body["features"]["components"] is True
assert body["features"]["themes"] is True
assert body["features"]["layouts"] is True
assert body["features"]["page_builder"] is False
assert body["features"]["templates"] is True
assert body["features"]["template_versions"] is True
assert body["features"]["template_instantiation"] is True
assert body["features"]["site_locale_bindings"] is True
assert body["features"]["localizations"] is True
assert body["features"]["media_refs"] is True
assert body["features"]["forms"] is True
assert body["features"]["surveys"] is True
assert body["features"]["appointment_pages"] is True
assert body["features"]["seo_engine"] is True
assert body["independence"]["integration_mode"] == "api_and_events_only"
metrics = await client.get("/metrics")
assert metrics.status_code == 200
assert metrics.json()["metrics"]["sites"] == "tenant_scoped"
assert metrics.json()["metrics"]["components"] == "tenant_scoped"
assert metrics.json()["metrics"]["themes"] == "tenant_scoped"
assert metrics.json()["metrics"]["layouts"] == "tenant_scoped"
assert metrics.json()["metrics"]["media_refs"] == "tenant_scoped"
assert metrics.json()["metrics"]["forms"] == "tenant_scoped"
assert metrics.json()["phase"] == "11.10"
@pytest.mark.asyncio
async def test_foundation_flow_and_events(client):
ws = await client.post(
"/api/v1/workspaces",
json={"code": "main", "name": "Main Workspace", "status": "active"},
headers=tenant_headers(TENANT_A),
)
assert ws.status_code == 201, ws.text
workspace_id = ws.json()["id"]
assert ws.json()["code"] == "main"
locale = await client.post(
"/api/v1/locale-profiles",
json={
"workspace_id": workspace_id,
"code": "fa",
"name": "Persian",
"language": "fa",
"text_direction": "rtl",
},
headers=tenant_headers(TENANT_A),
)
assert locale.status_code == 201, locale.text
assert locale.json()["text_direction"] == "rtl"
provider = await client.post(
"/api/v1/external-providers",
json={
"workspace_id": workspace_id,
"code": "cdn1",
"name": "CDN",
"provider_kind": "cdn",
"adapter_key": "cdn.generic",
},
headers=tenant_headers(TENANT_A),
)
assert provider.status_code == 201, provider.text
engine = await client.post(
"/api/v1/render-engines",
json={
"workspace_id": workspace_id,
"code": "ssg",
"name": "SSG Ready",
"adapter_key": "render.ssg",
},
headers=tenant_headers(TENANT_A),
)
assert engine.status_code == 201, engine.text
cfg = await client.post(
"/api/v1/configurations",
json={
"workspace_id": workspace_id,
"code": "default",
"timezone": "Asia/Tehran",
"language": "fa",
},
headers=tenant_headers(TENANT_A),
)
assert cfg.status_code == 201, cfg.text
setting = await client.put(
"/api/v1/settings",
json={"workspace_id": workspace_id, "key": "default_locale", "value": {"code": "fa"}},
headers=tenant_headers(TENANT_A),
)
assert setting.status_code == 200, setting.text
events = get_event_publisher().published
types = {e.event_type for e in events}
assert ExperienceEventType.WORKSPACE_CREATED.value in types
assert ExperienceEventType.LOCALE_PROFILE_CREATED.value in types
assert ExperienceEventType.RENDER_ENGINE_REGISTERED.value in types
@pytest.mark.asyncio
async def test_tenant_isolation(client):
created = await client.post(
"/api/v1/workspaces",
json={"code": "iso", "name": "Iso"},
headers=tenant_headers(TENANT_A),
)
assert created.status_code == 201
workspace_id = created.json()["id"]
other = await client.get(
f"/api/v1/workspaces/{workspace_id}",
headers=tenant_headers(TENANT_B),
)
assert other.status_code == 404
missing = await client.get("/api/v1/workspaces")
assert missing.status_code in (400, 422)