Spaces:
Running
Running
| from __future__ import annotations | |
| import ast | |
| import re | |
| from pathlib import Path | |
| import unittest | |
| ROUTES = { | |
| "brand_api": Path("app/brand/api.py"), | |
| "projects_api": Path("app/projects/api.py"), | |
| } | |
| FRONTEND_CALLS = { | |
| "brand_api": Path("frontend/features/brand-kits/api/index.ts"), | |
| "collaboration_api": Path("frontend/features/workspace/collaboration/api/collaboration.ts"), | |
| } | |
| BRAND_ROUTES = { | |
| "router.post('', response_model=BrandKitResponse, status_code=status.HTTP_201_CREATED)": "/v1/brand POST", | |
| "router.get('', response_model=list[BrandKitResponse])": "/v1/brand GET", | |
| "router.patch('/{brand_kit_id}', response_model=BrandKitResponse)": "/v1/brand PATCH", | |
| "router.delete('/{brand_kit_id}', status_code=status.HTTP_204_NO_CONTENT)": "/v1/brand DELETE", | |
| } | |
| EXPECTED_BRAND_FRONTEND_CALLS = [ | |
| "await apiClient.get('/v1/brand');", | |
| "await apiClient.post('/v1/brand', payload);", | |
| ] | |
| EXPECTED_COLLABORATION_FRONTEND_CALLS = [ | |
| "await apiClient.get('/v1/projects/workspace/teams');", | |
| "await apiClient.post('/v1/projects/workspace/teams', payload);", | |
| "await apiClient.post('/v1/projects/workspace/invitations', payload);", | |
| "await apiClient.get('/v1/projects/workspace/members');", | |
| "await apiClient.delete(`/v1/projects/workspace/members/${userId}`);", | |
| "await apiClient.patch(`/v1/projects/workspace/members/${userId}/role?new_role=${newRole}`);", | |
| "await apiClient.get(`/v1/projects/workspace/workflows/${workflowId}/requests`);", | |
| "await apiClient.post(`/v1/projects/workspace/workflows/${workflowId}/requests`, { project_id: projectId });", | |
| "await apiClient.post(`/v1/projects/workspace/requests/${requestId}/approve`);", | |
| "await apiClient.post(`/v1/projects/workspace/requests/${requestId}/reject`);", | |
| "await apiClient.post(`/v1/projects/workspace/requests/${requestId}/comments?content=${encodeURIComponent(content)}`);", | |
| "await apiClient.get(`/v1/projects/${encodeURIComponent(projectId)}/collaborators`);", | |
| "await apiClient.post(`/v1/projects/${encodeURIComponent(projectId)}/collaborators?user_id=${encodeURIComponent(userId)}&role=${encodeURIComponent(role)}`);", | |
| "await apiClient.delete(`/v1/projects/${encodeURIComponent(projectId)}/collaborators/${encodeURIComponent(userId)}`);", | |
| ] | |
| def _route_decorators(path: Path) -> list[str]: | |
| tree = ast.parse(path.read_text()) | |
| calls = [] | |
| for node in tree.body: | |
| if not isinstance(node, ast.AsyncFunctionDef): | |
| continue | |
| for decorator in node.decorator_list: | |
| if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute) and decorator.func.attr in {"get", "post", "patch", "delete"}: | |
| calls.append(ast.unparse(decorator)) | |
| return calls | |
| def _frontend_calls(path: Path) -> list[str]: | |
| return [re.sub(r"^\s*const\s+\{[^}]*\}\s+=\s+", "", line.strip()) for line in path.read_text().splitlines() if "apiClient." in line] | |
| def test_brand_kit_routes_match_expected_contract() -> None: | |
| assert _route_decorators(ROUTES["brand_api"]) == list(BRAND_ROUTES.keys()) | |
| def test_approval_request_create_route_is_exposed() -> None: | |
| decorators = _route_decorators(ROUTES["projects_api"]) | |
| assert any( | |
| decorator == "router.post('/workspace/workflows/{workflow_id}/requests', response_model=ApprovalRequest, status_code=status.HTTP_201_CREATED)" | |
| for decorator in decorators | |
| ) | |
| def test_brand_kit_frontend_uses_expected_backend_routes() -> None: | |
| assert _frontend_calls(FRONTEND_CALLS["brand_api"]) == EXPECTED_BRAND_FRONTEND_CALLS | |
| def test_collaboration_frontend_uses_expected_backend_routes() -> None: | |
| assert _frontend_calls(FRONTEND_CALLS["collaboration_api"]) == EXPECTED_COLLABORATION_FRONTEND_CALLS | |
| class ApiContractRegressionTests(unittest.TestCase): | |
| def test_brand_kit_routes_match_expected_contract(self) -> None: | |
| test_brand_kit_routes_match_expected_contract() | |
| def test_brand_kit_frontend_uses_expected_backend_routes(self) -> None: | |
| test_brand_kit_frontend_uses_expected_backend_routes() | |
| def test_collaboration_frontend_uses_expected_backend_routes(self) -> None: | |
| test_collaboration_frontend_uses_expected_backend_routes() | |
| def test_approval_request_create_route_is_exposed(self) -> None: | |
| test_approval_request_create_route_is_exposed() | |
| if __name__ == "__main__": | |
| unittest.main() | |