"""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