Files
orion/tests/integration/api/v1/platform/test_pricing.py
Samir Boulahtit fb8cb14506 refactor: rename public routes and templates to platform
Complete the public -> platform naming migration across the codebase.
This aligns with the naming convention where "platform" refers to
the marketing/public-facing pages of the platform itself.

Changes:
- Update all imports from public to platform modules
- Update template references from public/ to platform/
- Update route registrations to use platform prefix
- Update documentation to reflect new naming
- Update test files for platform API endpoints

Files affected:
- app/api/main.py - router imports
- app/modules/*/routes/*/platform.py - route definitions
- app/modules/*/templates/*/platform/ - template files
- app/modules/routes.py - route discovery
- docs/* - documentation updates
- tests/integration/api/v1/platform/ - test files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 18:49:39 +01:00

286 lines
9.9 KiB
Python

# tests/integration/api/v1/platform/test_pricing.py
"""Integration tests for platform pricing API endpoints.
Tests the /api/v1/platform/pricing/* endpoints.
"""
import pytest
from app.modules.billing.models import (
AddOnProduct,
SubscriptionTier,
TierCode,
TIER_LIMITS,
)
@pytest.mark.integration
@pytest.mark.api
@pytest.mark.platform
class TestPlatformPricingAPI:
"""Test platform pricing endpoints at /api/v1/platform/*."""
# =========================================================================
# GET /api/v1/platform/pricing/tiers
# =========================================================================
def test_get_tiers_returns_all_public_tiers(self, client):
"""Test getting all subscription tiers."""
response = client.get("/api/v1/platform/pricing/tiers")
assert response.status_code == 200
data = response.json()
assert isinstance(data, list)
assert len(data) >= 4 # Essential, Professional, Business, Enterprise
def test_get_tiers_has_expected_fields(self, client):
"""Test that tier response has all expected fields."""
response = client.get("/api/v1/platform/pricing/tiers")
assert response.status_code == 200
data = response.json()
assert len(data) > 0
tier = data[0]
assert "code" in tier
assert "name" in tier
assert "price_monthly" in tier
assert "price_monthly_cents" in tier
assert "orders_per_month" in tier
assert "products_limit" in tier
assert "team_members" in tier
assert "features" in tier
assert "is_popular" in tier
assert "is_enterprise" in tier
def test_get_tiers_includes_essential(self, client):
"""Test that Essential tier is included."""
response = client.get("/api/v1/platform/pricing/tiers")
assert response.status_code == 200
data = response.json()
tier_codes = [t["code"] for t in data]
assert TierCode.ESSENTIAL.value in tier_codes
def test_get_tiers_includes_professional(self, client):
"""Test that Professional tier is included and marked as popular."""
response = client.get("/api/v1/platform/pricing/tiers")
assert response.status_code == 200
data = response.json()
professional = next(
(t for t in data if t["code"] == TierCode.PROFESSIONAL.value), None
)
assert professional is not None
assert professional["is_popular"] is True
def test_get_tiers_includes_enterprise(self, client):
"""Test that Enterprise tier is included and marked appropriately."""
response = client.get("/api/v1/platform/pricing/tiers")
assert response.status_code == 200
data = response.json()
enterprise = next(
(t for t in data if t["code"] == TierCode.ENTERPRISE.value), None
)
assert enterprise is not None
assert enterprise["is_enterprise"] is True
def test_get_tiers_from_database(self, client, db):
"""Test getting tiers from database when available."""
# Create a tier in the database
tier = SubscriptionTier(
code="test_tier",
name="Test Tier",
description="A test tier",
price_monthly_cents=9900,
price_annual_cents=99000,
orders_per_month=1000,
products_limit=500,
team_members=5,
features=["feature1", "feature2"],
is_active=True,
is_public=True,
display_order=99,
)
db.add(tier)
db.commit()
response = client.get("/api/v1/platform/pricing/tiers")
assert response.status_code == 200
data = response.json()
tier_codes = [t["code"] for t in data]
assert "test_tier" in tier_codes
# =========================================================================
# GET /api/v1/platform/pricing/tiers/{tier_code}
# =========================================================================
def test_get_tier_by_code_success(self, client):
"""Test getting a specific tier by code."""
response = client.get(f"/api/v1/platform/pricing/tiers/{TierCode.PROFESSIONAL.value}")
assert response.status_code == 200
data = response.json()
assert data["code"] == TierCode.PROFESSIONAL.value
assert data["name"] == TIER_LIMITS[TierCode.PROFESSIONAL]["name"]
def test_get_tier_by_code_essential(self, client):
"""Test getting Essential tier details."""
response = client.get(f"/api/v1/platform/pricing/tiers/{TierCode.ESSENTIAL.value}")
assert response.status_code == 200
data = response.json()
assert data["code"] == TierCode.ESSENTIAL.value
assert data["price_monthly"] == TIER_LIMITS[TierCode.ESSENTIAL]["price_monthly_cents"] / 100
def test_get_tier_by_code_not_found(self, client):
"""Test getting a non-existent tier returns 404."""
response = client.get("/api/v1/platform/pricing/tiers/nonexistent_tier")
assert response.status_code == 404
data = response.json()
assert "not found" in data["message"].lower()
# =========================================================================
# GET /api/v1/platform/pricing/addons
# =========================================================================
def test_get_addons_empty_when_none_configured(self, client):
"""Test getting add-ons when none are configured."""
response = client.get("/api/v1/platform/pricing/addons")
assert response.status_code == 200
data = response.json()
assert isinstance(data, list)
def test_get_addons_returns_configured_addons(self, client, db):
"""Test getting add-ons when configured in database."""
# Create test add-on
addon = AddOnProduct(
code="test_domain",
name="Custom Domain",
description="Use your own domain",
category="domain",
price_cents=1500,
billing_period="annual",
is_active=True,
display_order=1,
)
db.add(addon)
db.commit()
response = client.get("/api/v1/platform/pricing/addons")
assert response.status_code == 200
data = response.json()
assert len(data) >= 1
addon_codes = [a["code"] for a in data]
assert "test_domain" in addon_codes
def test_get_addons_has_expected_fields(self, client, db):
"""Test that addon response has all expected fields."""
addon = AddOnProduct(
code="test_ssl",
name="Premium SSL",
description="EV certificate",
category="security",
price_cents=4900,
billing_period="annual",
is_active=True,
display_order=1,
)
db.add(addon)
db.commit()
response = client.get("/api/v1/platform/pricing/addons")
assert response.status_code == 200
data = response.json()
assert len(data) > 0
addon_response = data[0]
assert "code" in addon_response
assert "name" in addon_response
assert "description" in addon_response
assert "category" in addon_response
assert "price" in addon_response
assert "price_cents" in addon_response
assert "billing_period" in addon_response
def test_get_addons_excludes_inactive(self, client, db):
"""Test that inactive add-ons are excluded."""
# Create active and inactive add-ons
active_addon = AddOnProduct(
code="active_addon",
name="Active Addon",
category="test",
price_cents=1000,
billing_period="monthly",
is_active=True,
display_order=1,
)
inactive_addon = AddOnProduct(
code="inactive_addon",
name="Inactive Addon",
category="test",
price_cents=1000,
billing_period="monthly",
is_active=False,
display_order=2,
)
db.add_all([active_addon, inactive_addon])
db.commit()
response = client.get("/api/v1/platform/pricing/addons")
assert response.status_code == 200
data = response.json()
addon_codes = [a["code"] for a in data]
assert "active_addon" in addon_codes
assert "inactive_addon" not in addon_codes
# =========================================================================
# GET /api/v1/platform/pricing
# =========================================================================
def test_get_pricing_returns_complete_info(self, client):
"""Test getting complete pricing information."""
response = client.get("/api/v1/platform/pricing")
assert response.status_code == 200
data = response.json()
assert "tiers" in data
assert "addons" in data
assert "trial_days" in data
assert "annual_discount_months" in data
def test_get_pricing_includes_trial_days(self, client):
"""Test that pricing includes correct trial period."""
response = client.get("/api/v1/platform/pricing")
assert response.status_code == 200
data = response.json()
assert data["trial_days"] == 30 # Updated from 14 to 30
def test_get_pricing_includes_annual_discount(self, client):
"""Test that pricing includes annual discount info."""
response = client.get("/api/v1/platform/pricing")
assert response.status_code == 200
data = response.json()
assert data["annual_discount_months"] == 2 # 2 months free
def test_get_pricing_tiers_not_empty(self, client):
"""Test that pricing always includes tiers."""
response = client.get("/api/v1/platform/pricing")
assert response.status_code == 200
data = response.json()
assert len(data["tiers"]) >= 4