Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm
Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)
Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability
Migration completed: $(date)
🤖 Clean migration with full functionality preserved
614 lines
25 KiB
Python
614 lines
25 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
DSS Admin UI - Phase 3: API Integration Testing
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
|
|
Framework: Pytest-Playwright + httpx (Python-based)
|
|
Purpose: Validate all 79+ API endpoints are working correctly
|
|
Coverage: Endpoint availability, response validation, error handling
|
|
|
|
Test Strategy:
|
|
- Test each of 79+ endpoints
|
|
- Validate response schemas
|
|
- Check error handling paths
|
|
- Confirm CORS/auth configuration
|
|
|
|
Generated: 2025-12-08
|
|
Author: Gemini 3 Pro Expert Analysis
|
|
Status: Ready for Implementation
|
|
"""
|
|
|
|
import pytest
|
|
import httpx
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Dict, List, Any, Optional
|
|
from datetime import datetime
|
|
import re
|
|
|
|
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
# API Client Configuration
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
|
|
API_BASE_URL = "http://localhost:8002" # FastAPI backend
|
|
DEV_CLIENT_URL = "http://localhost:5173" # Vite dev client
|
|
|
|
|
|
# API Endpoints grouped by category (from FastAPI /openapi.json)
|
|
API_ENDPOINTS = {
|
|
"Authentication": [
|
|
("POST", "/api/auth/login", {"username": "test", "password": "test"}),
|
|
("GET", "/api/auth/me", None),
|
|
("POST", "/api/auth/logout", None),
|
|
],
|
|
|
|
"Projects": [
|
|
("GET", "/api/projects", None),
|
|
("POST", "/api/projects", {
|
|
"name": "test-project",
|
|
"description": "Test project for validation"
|
|
}),
|
|
("GET", "/api/projects/{id}", None),
|
|
("PUT", "/api/projects/{id}", {
|
|
"name": "updated-project",
|
|
"description": "Updated test project"
|
|
}),
|
|
("DELETE", "/api/projects/{id}", None),
|
|
],
|
|
|
|
"Browser Logs": [
|
|
("GET", "/api/logs/browser", None),
|
|
("POST", "/api/logs/browser", {
|
|
"level": "info",
|
|
"message": "Test log entry",
|
|
"timestamp": datetime.now().isoformat()
|
|
}),
|
|
("GET", "/api/browser-logs", None),
|
|
("DELETE", "/api/browser-logs", None),
|
|
],
|
|
|
|
"Design Tokens": [
|
|
("GET", "/api/tokens", None),
|
|
("GET", "/api/tokens/current", None),
|
|
("POST", "/api/tokens", {
|
|
"name": "test-token",
|
|
"value": "#FF0000"
|
|
}),
|
|
("PUT", "/api/tokens/{id}", {
|
|
"value": "#00FF00"
|
|
}),
|
|
],
|
|
|
|
"Figma Integration": [
|
|
("GET", "/api/figma/status", None),
|
|
("POST", "/api/figma/extract", {
|
|
"file_key": "test-file-key"
|
|
}),
|
|
("POST", "/api/figma/sync", {
|
|
"file_key": "test-file-key"
|
|
}),
|
|
("GET", "/api/figma/files", None),
|
|
("POST", "/api/figma/components/extract", {
|
|
"file_key": "test-file-key"
|
|
}),
|
|
("POST", "/api/figma/validate", {
|
|
"file_key": "test-file-key"
|
|
}),
|
|
("GET", "/api/figma/components", None),
|
|
("POST", "/api/figma/audit", {
|
|
"file_key": "test-file-key"
|
|
}),
|
|
],
|
|
|
|
"MCP Tools": [
|
|
("GET", "/api/mcp/tools", None),
|
|
("GET", "/api/mcp/tools/{tool_id}", None),
|
|
("POST", "/api/mcp/tools/{tool_id}/execute", {
|
|
"params": {}
|
|
}),
|
|
("GET", "/api/mcp/resources", None),
|
|
("POST", "/api/mcp/resources/{resource_id}", None),
|
|
],
|
|
|
|
"System & Admin": [
|
|
("GET", "/api/system/status", None),
|
|
("POST", "/api/system/reset", None),
|
|
("GET", "/api/admin/teams", None),
|
|
("POST", "/api/admin/teams", {
|
|
"name": "test-team"
|
|
}),
|
|
("GET", "/api/admin/config", None),
|
|
("PUT", "/api/admin/config", {
|
|
"key": "test-key",
|
|
"value": "test-value"
|
|
}),
|
|
],
|
|
|
|
"Audit & Discovery": [
|
|
("GET", "/api/audit/logs", None),
|
|
("GET", "/api/audit/trail", None),
|
|
("POST", "/api/discovery/ports", None),
|
|
("GET", "/api/discovery/services", None),
|
|
],
|
|
|
|
"Services": [
|
|
("GET", "/api/services/storybook", None),
|
|
("GET", "/api/services/health", None),
|
|
("POST", "/api/services/restart", None),
|
|
],
|
|
}
|
|
|
|
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
# Test Fixtures & Utilities
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
|
|
@pytest.fixture(scope="session")
|
|
def http_client():
|
|
"""Create HTTP client for API testing"""
|
|
with httpx.Client(base_url=API_BASE_URL, timeout=10.0) as client:
|
|
yield client
|
|
|
|
|
|
class APIValidator:
|
|
"""Validate API responses"""
|
|
|
|
@staticmethod
|
|
def is_valid_json_response(response: httpx.Response) -> bool:
|
|
"""Check if response is valid JSON"""
|
|
try:
|
|
response.json()
|
|
return True
|
|
except json.JSONDecodeError:
|
|
return False
|
|
|
|
@staticmethod
|
|
def has_required_cors_headers(response: httpx.Response) -> bool:
|
|
"""Check if response has CORS headers"""
|
|
required_headers = [
|
|
"access-control-allow-origin",
|
|
"access-control-allow-methods",
|
|
]
|
|
return any(
|
|
header.lower() in [h.lower() for h in response.headers]
|
|
for header in required_headers
|
|
)
|
|
|
|
@staticmethod
|
|
def is_error_response(status_code: int) -> bool:
|
|
"""Check if status code indicates an error"""
|
|
return status_code >= 400
|
|
|
|
@staticmethod
|
|
def validate_endpoint(
|
|
method: str,
|
|
path: str,
|
|
response: httpx.Response,
|
|
strict: bool = False
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Comprehensive endpoint validation
|
|
|
|
Returns validation result with status and details
|
|
"""
|
|
is_error = APIValidator.is_error_response(response.status_code)
|
|
is_json = APIValidator.is_valid_json_response(response)
|
|
has_cors = APIValidator.has_required_cors_headers(response)
|
|
|
|
return {
|
|
"endpoint": f"{method} {path}",
|
|
"status_code": response.status_code,
|
|
"success": response.status_code < 500, # Accept 4xx errors (endpoint exists)
|
|
"is_json": is_json,
|
|
"has_cors": has_cors,
|
|
"is_error": is_error,
|
|
"error_message": response.text if is_error else None,
|
|
"response_size": len(response.content),
|
|
"headers": dict(response.headers),
|
|
}
|
|
|
|
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
# Test Classes - Grouped by API Category
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
|
|
class TestAuthenticationEndpoints:
|
|
"""Test authentication endpoints"""
|
|
|
|
def test_login_endpoint_exists(self, http_client):
|
|
"""Test: /api/auth/login endpoint exists"""
|
|
response = http_client.post("/api/auth/login", json={
|
|
"username": "test",
|
|
"password": "test"
|
|
})
|
|
result = APIValidator.validate_endpoint("POST", "/api/auth/login", response)
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
def test_me_endpoint_exists(self, http_client):
|
|
"""Test: /api/auth/me endpoint exists"""
|
|
response = http_client.get("/api/auth/me")
|
|
result = APIValidator.validate_endpoint("GET", "/api/auth/me", response)
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
def test_auth_returns_json(self, http_client):
|
|
"""Test: Auth endpoints return JSON"""
|
|
response = http_client.post("/api/auth/login", json={
|
|
"username": "test",
|
|
"password": "test"
|
|
})
|
|
assert response.status_code < 500, "Auth endpoint returned 5xx error"
|
|
|
|
|
|
class TestProjectEndpoints:
|
|
"""Test project management endpoints"""
|
|
|
|
def test_list_projects_endpoint(self, http_client):
|
|
"""Test: GET /api/projects returns project list"""
|
|
response = http_client.get("/api/projects")
|
|
result = APIValidator.validate_endpoint("GET", "/api/projects", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
assert result['is_json'], "Response is not valid JSON"
|
|
|
|
# Check response structure
|
|
if result['status_code'] == 200:
|
|
data = response.json()
|
|
assert isinstance(data, (list, dict)), "Response should be list or dict"
|
|
|
|
def test_create_project_endpoint(self, http_client):
|
|
"""Test: POST /api/projects creates new project"""
|
|
response = http_client.post("/api/projects", json={
|
|
"name": "test-project",
|
|
"description": "Test project"
|
|
})
|
|
result = APIValidator.validate_endpoint("POST", "/api/projects", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
# 201 Created or 200 OK or 400 Bad Request (missing auth) all acceptable
|
|
assert result['status_code'] in [200, 201, 400, 401, 403], \
|
|
f"Unexpected status code: {result['status_code']}"
|
|
|
|
def test_get_single_project_endpoint(self, http_client):
|
|
"""Test: GET /api/projects/:id endpoint exists"""
|
|
response = http_client.get("/api/projects/test-id")
|
|
result = APIValidator.validate_endpoint("GET", "/api/projects/test-id", response)
|
|
|
|
# Endpoint should exist (even if 404 for specific ID)
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
|
|
class TestBrowserLogsEndpoints:
|
|
"""Test browser logging endpoints"""
|
|
|
|
def test_get_browser_logs(self, http_client):
|
|
"""Test: GET /api/logs/browser returns logs"""
|
|
response = http_client.get("/api/logs/browser")
|
|
result = APIValidator.validate_endpoint("GET", "/api/logs/browser", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
assert result['is_json'], "Response is not valid JSON"
|
|
|
|
def test_post_browser_log(self, http_client):
|
|
"""Test: POST /api/logs/browser accepts log entry"""
|
|
response = http_client.post("/api/logs/browser", json={
|
|
"level": "info",
|
|
"message": "Test log",
|
|
"timestamp": datetime.now().isoformat()
|
|
})
|
|
result = APIValidator.validate_endpoint("POST", "/api/logs/browser", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
def test_browser_logs_route_variant(self, http_client):
|
|
"""Test: GET /api/browser-logs endpoint (variant)"""
|
|
response = http_client.get("/api/browser-logs")
|
|
result = APIValidator.validate_endpoint("GET", "/api/browser-logs", response)
|
|
|
|
# Either /api/logs/browser or /api/browser-logs should work
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
|
|
class TestFigmaEndpoints:
|
|
"""Test Figma integration endpoints"""
|
|
|
|
def test_figma_status_endpoint(self, http_client):
|
|
"""Test: GET /api/figma/status endpoint"""
|
|
response = http_client.get("/api/figma/status")
|
|
result = APIValidator.validate_endpoint("GET", "/api/figma/status", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
def test_figma_files_endpoint(self, http_client):
|
|
"""Test: GET /api/figma/files endpoint"""
|
|
response = http_client.get("/api/figma/files")
|
|
result = APIValidator.validate_endpoint("GET", "/api/figma/files", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
def test_figma_extract_endpoint(self, http_client):
|
|
"""Test: POST /api/figma/extract endpoint"""
|
|
response = http_client.post("/api/figma/extract", json={
|
|
"file_key": "test-key"
|
|
})
|
|
result = APIValidator.validate_endpoint("POST", "/api/figma/extract", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
def test_figma_components_endpoint(self, http_client):
|
|
"""Test: GET /api/figma/components endpoint"""
|
|
response = http_client.get("/api/figma/components")
|
|
result = APIValidator.validate_endpoint("GET", "/api/figma/components", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
|
|
class TestMCPToolsEndpoints:
|
|
"""Test MCP tool integration endpoints"""
|
|
|
|
def test_list_mcp_tools(self, http_client):
|
|
"""Test: GET /api/mcp/tools returns tool list"""
|
|
response = http_client.get("/api/mcp/tools")
|
|
result = APIValidator.validate_endpoint("GET", "/api/mcp/tools", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
assert result['is_json'], "Response is not valid JSON"
|
|
|
|
def test_list_mcp_resources(self, http_client):
|
|
"""Test: GET /api/mcp/resources returns resources"""
|
|
response = http_client.get("/api/mcp/resources")
|
|
result = APIValidator.validate_endpoint("GET", "/api/mcp/resources", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
def test_execute_mcp_tool(self, http_client):
|
|
"""Test: POST /api/mcp/tools/:id/execute endpoint exists"""
|
|
response = http_client.post("/api/mcp/tools/test-tool/execute", json={
|
|
"params": {}
|
|
})
|
|
result = APIValidator.validate_endpoint(
|
|
"POST", "/api/mcp/tools/test-tool/execute", response
|
|
)
|
|
|
|
# Endpoint should exist (even if 404 for specific tool)
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
|
|
class TestSystemAdminEndpoints:
|
|
"""Test system and admin endpoints"""
|
|
|
|
def test_system_status_endpoint(self, http_client):
|
|
"""Test: GET /api/system/status endpoint"""
|
|
response = http_client.get("/api/system/status")
|
|
result = APIValidator.validate_endpoint("GET", "/api/system/status", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
def test_list_teams_endpoint(self, http_client):
|
|
"""Test: GET /api/admin/teams endpoint"""
|
|
response = http_client.get("/api/admin/teams")
|
|
result = APIValidator.validate_endpoint("GET", "/api/admin/teams", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
def test_get_admin_config_endpoint(self, http_client):
|
|
"""Test: GET /api/admin/config endpoint"""
|
|
response = http_client.get("/api/admin/config")
|
|
result = APIValidator.validate_endpoint("GET", "/api/admin/config", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
|
|
class TestAuditDiscoveryEndpoints:
|
|
"""Test audit and discovery endpoints"""
|
|
|
|
def test_audit_logs_endpoint(self, http_client):
|
|
"""Test: GET /api/audit/logs endpoint"""
|
|
response = http_client.get("/api/audit/logs")
|
|
result = APIValidator.validate_endpoint("GET", "/api/audit/logs", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
def test_audit_trail_endpoint(self, http_client):
|
|
"""Test: GET /api/audit/trail endpoint"""
|
|
response = http_client.get("/api/audit/trail")
|
|
result = APIValidator.validate_endpoint("GET", "/api/audit/trail", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
def test_discovery_services_endpoint(self, http_client):
|
|
"""Test: GET /api/discovery/services endpoint"""
|
|
response = http_client.get("/api/discovery/services")
|
|
result = APIValidator.validate_endpoint("GET", "/api/discovery/services", response)
|
|
|
|
assert result['status_code'] < 500, f"Server error: {result['error_message']}"
|
|
|
|
|
|
class TestCORSConfiguration:
|
|
"""Test CORS configuration across endpoints"""
|
|
|
|
def test_cors_headers_on_projects_endpoint(self, http_client):
|
|
"""Test: /api/projects has CORS headers"""
|
|
response = http_client.get("/api/projects")
|
|
|
|
# Check for CORS headers
|
|
has_allow_origin = "access-control-allow-origin" in [
|
|
h.lower() for h in response.headers
|
|
]
|
|
# CORS might not be required if same-origin, but document if present
|
|
print(f"CORS headers present: {has_allow_origin}")
|
|
|
|
def test_cors_headers_on_logs_endpoint(self, http_client):
|
|
"""Test: /api/logs/browser has CORS headers"""
|
|
response = http_client.post("/api/logs/browser", json={
|
|
"level": "info",
|
|
"message": "test"
|
|
})
|
|
|
|
# Check response
|
|
assert response.status_code < 500, f"Server error on logs endpoint"
|
|
|
|
|
|
class TestErrorHandling:
|
|
"""Test error handling and edge cases"""
|
|
|
|
def test_404_on_nonexistent_resource(self, http_client):
|
|
"""Test: Non-existent resources return 404"""
|
|
response = http_client.get("/api/projects/nonexistent-id")
|
|
|
|
# Should return 404, not 500
|
|
assert response.status_code in [404, 401, 403], \
|
|
f"Expected 4xx error, got {response.status_code}"
|
|
|
|
def test_method_not_allowed(self, http_client):
|
|
"""Test: Invalid HTTP methods return 405"""
|
|
response = http_client.request("PATCH", "/api/projects")
|
|
|
|
# Should return 405 or 404, not 500
|
|
assert response.status_code in [405, 404, 500], \
|
|
f"Response for invalid method: {response.status_code}"
|
|
|
|
def test_invalid_json_body(self, http_client):
|
|
"""Test: Invalid JSON body is handled gracefully"""
|
|
response = httpx.post(
|
|
f"{API_BASE_URL}/api/projects",
|
|
content=b"invalid json {",
|
|
headers={"Content-Type": "application/json"}
|
|
)
|
|
|
|
# Should return 400, not 500
|
|
assert response.status_code != 500, "Server error on invalid JSON"
|
|
|
|
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
# Comprehensive API Scan Test
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
|
|
def test_comprehensive_api_scan(http_client):
|
|
"""
|
|
Test: Scan all known API endpoints and report health
|
|
|
|
This comprehensive test hits all endpoints and generates a report
|
|
"""
|
|
|
|
results = {
|
|
"timestamp": datetime.now().isoformat(),
|
|
"total_endpoints": 0,
|
|
"successful": 0,
|
|
"errors": 0,
|
|
"categories": {}
|
|
}
|
|
|
|
for category, endpoints in API_ENDPOINTS.items():
|
|
results["categories"][category] = {
|
|
"endpoints": len(endpoints),
|
|
"passed": 0,
|
|
"failed": 0,
|
|
"details": []
|
|
}
|
|
|
|
for method, path, payload in endpoints:
|
|
results["total_endpoints"] += 1
|
|
|
|
try:
|
|
if method == "GET":
|
|
response = http_client.get(path)
|
|
elif method == "POST":
|
|
response = http_client.post(path, json=payload or {})
|
|
elif method == "PUT":
|
|
response = http_client.put(path, json=payload or {})
|
|
elif method == "DELETE":
|
|
response = http_client.delete(path)
|
|
else:
|
|
continue
|
|
|
|
validation = APIValidator.validate_endpoint(method, path, response)
|
|
|
|
if validation['success']:
|
|
results["successful"] += 1
|
|
results["categories"][category]["passed"] += 1
|
|
else:
|
|
results["errors"] += 1
|
|
results["categories"][category]["failed"] += 1
|
|
|
|
results["categories"][category]["details"].append({
|
|
"endpoint": f"{method} {path}",
|
|
"status": validation['status_code'],
|
|
"success": validation['success'],
|
|
"json": validation['is_json']
|
|
})
|
|
|
|
except Exception as e:
|
|
results["errors"] += 1
|
|
results["categories"][category]["failed"] += 1
|
|
results["categories"][category]["details"].append({
|
|
"endpoint": f"{method} {path}",
|
|
"error": str(e)
|
|
})
|
|
|
|
# Print report
|
|
print("\n" + "="*80)
|
|
print("API ENDPOINT HEALTH REPORT")
|
|
print("="*80)
|
|
print(f"Timestamp: {results['timestamp']}")
|
|
print(f"Total Endpoints: {results['total_endpoints']}")
|
|
print(f"Successful: {results['successful']} ({results['successful']*100//results['total_endpoints']}%)")
|
|
print(f"Errors: {results['errors']}")
|
|
print("\nBy Category:")
|
|
for category, cat_results in results["categories"].items():
|
|
print(f" {category}: {cat_results['passed']}/{cat_results['endpoints']}")
|
|
|
|
print("="*80)
|
|
|
|
# Assert at least 80% of endpoints are working
|
|
success_rate = results['successful'] / results['total_endpoints']
|
|
assert success_rate >= 0.8, \
|
|
f"API health below 80%: {success_rate*100:.1f}% working endpoints"
|
|
|
|
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
# Test Configuration
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
|
|
@pytest.fixture(scope="session", autouse=True)
|
|
def print_test_header():
|
|
"""Print header with test information"""
|
|
print("\n" + "="*80)
|
|
print("DSS Admin UI - Phase 3: API Integration Testing")
|
|
print("="*80)
|
|
print(f"API Base URL: {API_BASE_URL}")
|
|
print(f"Endpoints to test: {sum(len(e) for e in API_ENDPOINTS.values())}")
|
|
print("="*80)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("""
|
|
╔═══════════════════════════════════════════════════════════════════════════╗
|
|
║ ║
|
|
║ DSS Admin UI - Phase 3 API Testing ║
|
|
║ pytest-playwright API Endpoint Validation ║
|
|
║ ║
|
|
║ Prerequisites: ║
|
|
║ $ pip install pytest playwright httpx ║
|
|
║ $ playwright install ║
|
|
║ ║
|
|
║ To run all API tests: ║
|
|
║ $ pytest .dss/test_api_phase3.py -v ║
|
|
║ ║
|
|
║ To run specific category: ║
|
|
║ $ pytest .dss/test_api_phase3.py::TestProjectEndpoints -v ║
|
|
║ $ pytest .dss/test_api_phase3.py::TestFigmaEndpoints -v ║
|
|
║ $ pytest .dss/test_api_phase3.py::TestMCPToolsEndpoints -v ║
|
|
║ ║
|
|
║ To run comprehensive scan: ║
|
|
║ $ pytest .dss/test_api_phase3.py::test_comprehensive_api_scan -v ║
|
|
║ ║
|
|
║ To run with detailed output: ║
|
|
║ $ pytest .dss/test_api_phase3.py -vv --tb=short ║
|
|
║ ║
|
|
║ To run in CI/CD environment: ║
|
|
║ $ HEADLESS=1 pytest .dss/test_api_phase3.py -v --tb=short ║
|
|
║ ║
|
|
╚═══════════════════════════════════════════════════════════════════════════╝
|
|
""")
|