Files
orion/tests/integration/api/v1/store/test_dashboard.py
Samir Boulahtit cb9a829684
All checks were successful
CI / ruff (push) Successful in 11s
CI / pytest (push) Successful in 49m59s
CI / validate (push) Successful in 24s
CI / dependency-scanning (push) Successful in 30s
CI / docs (push) Successful in 44s
CI / deploy (push) Successful in 1m2s
fix(tests): add main platform fixture to store dashboard tests
The store dashboard endpoint uses require_platform which needs the
PlatformContextMiddleware to resolve a platform. TestClient uses
'testserver' as Host, which the middleware maps to the 'main' platform.
Added _ensure_main_platform fixture to create it in the test DB.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:28:46 +01:00

214 lines
7.0 KiB
Python

# tests/integration/api/v1/test_store_api_dashboard.py
"""
Integration tests for store dashboard API endpoints.
Tests cover:
1. Dashboard stats retrieval
2. Store-specific data isolation
3. Permission checks
4. Data accuracy
"""
import pytest
from app.modules.tenancy.models import Platform
@pytest.fixture
def _ensure_main_platform(db):
"""Ensure a 'main' platform exists for the PlatformContextMiddleware.
The TestClient uses 'testserver' as Host, which the middleware treats as
localhost and resolves to the 'main' platform via path_prefix lookup.
"""
platform = db.query(Platform).filter(Platform.code == "main").first()
if not platform:
platform = Platform(
code="main",
name="Main Platform",
path_prefix="main",
is_active=True,
is_public=True,
default_language="en",
supported_languages=["en"],
)
db.add(platform)
db.commit()
return platform
@pytest.mark.integration
@pytest.mark.api
@pytest.mark.store
@pytest.mark.usefixtures("_ensure_main_platform")
class TestStoreDashboardAPI:
"""Test store dashboard stats endpoint"""
def test_get_dashboard_stats_structure(
self, client, store_user_headers, test_store_with_store_user, db
):
"""Test dashboard stats returns correct data structure"""
response = client.get(
"/api/v1/store/dashboard/stats", headers=store_user_headers
)
assert response.status_code == 200
data = response.json()
# Verify top-level structure
assert "store" in data
assert "products" in data
assert "orders" in data
assert "customers" in data
assert "revenue" in data
# Verify store info
assert "id" in data["store"]
assert "name" in data["store"]
assert "store_code" in data["store"]
assert data["store"]["id"] == test_store_with_store_user.id
# Verify products stats
assert "total" in data["products"]
assert "active" in data["products"]
assert isinstance(data["products"]["total"], int)
assert isinstance(data["products"]["active"], int)
# Verify orders stats
assert "total" in data["orders"]
assert "pending" in data["orders"]
assert "completed" in data["orders"]
# Verify customers stats
assert "total" in data["customers"]
assert "active" in data["customers"]
# Verify revenue stats
assert "total" in data["revenue"]
assert "this_month" in data["revenue"]
def test_dashboard_stats_without_store_association(self, client, db, auth_manager):
"""Test dashboard stats for user not associated with any store"""
import uuid
from app.modules.tenancy.models import User
# Create store user without store association
hashed_password = auth_manager.hash_password("testpass123")
orphan_user = User(
email=f"orphan_{uuid.uuid4().hex[:8]}@example.com",
username=f"orphanstore_{uuid.uuid4().hex[:8]}",
hashed_password=hashed_password,
role="merchant_owner",
is_active=True,
)
db.add(orphan_user)
db.commit()
db.refresh(orphan_user)
# Get token
token_data = auth_manager.create_access_token(orphan_user)
headers = {"Authorization": f"Bearer {token_data['access_token']}"}
# Try to get dashboard stats
response = client.get("/api/v1/store/dashboard/stats", headers=headers)
# Should fail - user not associated with store (401 if no store context, 403 if forbidden)
assert response.status_code in [401, 403, 404]
def test_dashboard_stats_with_inactive_store(
self, client, db, test_store_user, test_merchant, auth_manager
):
"""Test dashboard stats for inactive store"""
import uuid
from app.modules.tenancy.models import Store, StoreUser
# Create inactive store
unique_code = f"INACTIVE_{uuid.uuid4().hex[:8].upper()}"
store = Store(
store_code=unique_code,
subdomain=f"inactive-{uuid.uuid4().hex[:8]}",
name="Inactive Store",
merchant_id=test_merchant.id,
is_active=False, # Inactive
is_verified=True,
)
db.add(store)
db.commit()
# Associate with user (ownership determined via Merchant.owner_user_id)
store_user = StoreUser(
store_id=store.id,
user_id=test_store_user.id,
is_active=True,
)
db.add(store_user)
db.commit()
# Get token
token_data = auth_manager.create_access_token(test_store_user)
headers = {"Authorization": f"Bearer {token_data['access_token']}"}
# Try to get dashboard stats
response = client.get("/api/v1/store/dashboard/stats", headers=headers)
# Should fail - store is inactive (could be 401, 403 or 404 depending on implementation)
assert response.status_code in [401, 403, 404]
def test_dashboard_stats_empty_store(
self, client, store_user_headers, test_store_with_store_user
):
"""Test dashboard stats for store with no data"""
response = client.get(
"/api/v1/store/dashboard/stats", headers=store_user_headers
)
assert response.status_code == 200
data = response.json()
# Should return zeros for empty store
assert data["products"]["total"] == 0
assert data["products"]["active"] == 0
assert data["orders"]["total"] == 0
assert data["customers"]["total"] == 0
assert data["revenue"]["total"] == 0
def test_dashboard_stats_response_time(
self, client, store_user_headers, test_store_with_store_user
):
"""Test that dashboard stats responds quickly"""
import time
start_time = time.time()
response = client.get(
"/api/v1/store/dashboard/stats", headers=store_user_headers
)
end_time = time.time()
assert response.status_code == 200
# Should respond in less than 2 seconds
assert (end_time - start_time) < 2.0
def test_dashboard_stats_caching_behavior(
self, client, store_user_headers, test_store_with_store_user
):
"""Test that dashboard stats can be called multiple times"""
# Make multiple requests
responses = []
for _ in range(3):
response = client.get(
"/api/v1/store/dashboard/stats", headers=store_user_headers
)
responses.append(response)
# All should succeed
for response in responses:
assert response.status_code == 200
# All should return consistent data
data_list = [r.json() for r in responses]
for data in data_list[1:]:
assert data["store"]["id"] == data_list[0]["store"]["id"]
assert data["products"]["total"] == data_list[0]["products"]["total"]