TorbatYar/backend/services/experience/app/tests/test_sites.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

170 lines
5.4 KiB
Python

"""Sites & pages API tests — Phase 11.1."""
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
async def _workspace(client, code="ws1"):
resp = await client.post(
"/api/v1/workspaces",
json={"code": code, "name": "Workspace", "status": "active"},
headers=tenant_headers(TENANT_A),
)
assert resp.status_code == 201, resp.text
return resp.json()
@pytest.mark.asyncio
async def test_health_phase_111(client):
resp = await client.get("/health")
assert resp.status_code == 200
# Health version tracks current service version (forward-compatible).
assert resp.json()["version"].startswith("0.11.")
caps = await client.get("/capabilities")
body = caps.json()
assert body["features"]["sites"] is True
assert body["features"]["pages"] is True
assert body["features"]["page_builder"] is False
assert "landing" in body["page_types"]
assert "digital_menu" in body["page_types"]
@pytest.mark.asyncio
async def test_sites_pages_domains_publish_flow(client):
ws = await _workspace(client)
workspace_id = ws["id"]
site = await client.post(
"/api/v1/sites",
json={
"workspace_id": workspace_id,
"code": "main",
"name": "Main Site",
"default_locale": "fa",
"default_direction": "rtl",
},
headers=tenant_headers(TENANT_A),
)
assert site.status_code == 201, site.text
site_id = site.json()["id"]
assert site.json()["publish_status"] == "draft"
page = await client.post(
"/api/v1/pages",
json={
"workspace_id": workspace_id,
"site_id": site_id,
"code": "home",
"slug": "home",
"title": "Home",
"page_type": "landing",
"is_home": True,
},
headers=tenant_headers(TENANT_A),
)
assert page.status_code == 201, page.text
page_id = page.json()["id"]
assert page.json()["page_type"] == "landing"
menu = await client.post(
"/api/v1/pages",
json={
"workspace_id": workspace_id,
"site_id": site_id,
"code": "menu",
"slug": "menu",
"title": "Digital Menu",
"page_type": "digital_menu",
"external_refs": {"hospitality_menu_ref": "menu-1"},
},
headers=tenant_headers(TENANT_A),
)
assert menu.status_code == 201, menu.text
domain = await client.post(
"/api/v1/site-domains",
json={
"workspace_id": workspace_id,
"site_id": site_id,
"host": "pages.example.local",
"domain_kind": "subdomain",
"is_primary": True,
},
headers=tenant_headers(TENANT_A),
)
assert domain.status_code == 201, domain.text
assert domain.json()["is_primary"] is True
published_page = await client.post(
f"/api/v1/pages/{page_id}/publish",
headers=tenant_headers(TENANT_A),
)
assert published_page.status_code == 200
assert published_page.json()["publish_status"] == "published"
published_site = await client.post(
f"/api/v1/sites/{site_id}/publish",
headers=tenant_headers(TENANT_A),
)
assert published_site.status_code == 200
assert published_site.json()["publish_status"] == "published"
assert published_site.json()["primary_domain"] == "pages.example.local"
archived = await client.post(
f"/api/v1/sites/{site_id}/archive",
headers=tenant_headers(TENANT_A),
)
assert archived.status_code == 200
assert archived.json()["publish_status"] == "archived"
events = {e.event_type for e in get_event_publisher().published}
assert ExperienceEventType.SITE_CREATED.value in events
assert ExperienceEventType.PAGE_CREATED.value in events
assert ExperienceEventType.PAGE_PUBLISHED.value in events
assert ExperienceEventType.SITE_PUBLISHED.value in events
assert ExperienceEventType.SITE_DOMAIN_BOUND.value in events
assert ExperienceEventType.SITE_ARCHIVED.value in events
@pytest.mark.asyncio
async def test_site_tenant_isolation(client):
ws = await _workspace(client, code="iso")
site = await client.post(
"/api/v1/sites",
json={"workspace_id": ws["id"], "code": "s1", "name": "S1"},
headers=tenant_headers(TENANT_A),
)
assert site.status_code == 201
site_id = site.json()["id"]
other = await client.get(
f"/api/v1/sites/{site_id}",
headers=tenant_headers(TENANT_B),
)
assert other.status_code == 404
@pytest.mark.asyncio
async def test_archive_blocks_publish(client):
ws = await _workspace(client, code="arch")
site = await client.post(
"/api/v1/sites",
json={"workspace_id": ws["id"], "code": "s2", "name": "S2"},
headers=tenant_headers(TENANT_A),
)
site_id = site.json()["id"]
await client.post(
f"/api/v1/sites/{site_id}/archive",
headers=tenant_headers(TENANT_A),
)
again = await client.post(
f"/api/v1/sites/{site_id}/publish",
headers=tenant_headers(TENANT_A),
)
assert again.status_code == 409