- Extract store/platform context from Referer header for storefront API requests
(StoreContextMiddleware and PlatformContextMiddleware) so login POST works in
dev mode where API paths lack /platforms/{code}/ prefix
- Set customer token cookie path to "/" for cross-route compatibility
- Fix double storefront in URLs: replace {{ base_url }}storefront/ with {{ base_url }}
across all 24 storefront templates
- Fix auth error redirect to include platform prefix and use store_code
- Update seed script to output correct storefront login URLs
- Add 20 new unit tests covering all fixes; fix 9 pre-existing test failures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
126 lines
4.0 KiB
Python
126 lines
4.0 KiB
Python
# tests/unit/test_exception_handler.py
|
|
"""
|
|
Unit tests for exception handler login redirect.
|
|
|
|
Tests the _redirect_to_login function to ensure correct URL generation
|
|
for storefront contexts, preventing double 'storefront/' in redirects.
|
|
"""
|
|
|
|
from unittest.mock import Mock
|
|
|
|
import pytest
|
|
from fastapi import Request
|
|
|
|
from app.exceptions.handler import _redirect_to_login
|
|
from app.modules.enums import FrontendType
|
|
|
|
|
|
def _make_request(
|
|
path="/storefront/FASHIONHUB/account/dashboard",
|
|
frontend_type=FrontendType.STOREFRONT,
|
|
store=None,
|
|
store_context=None,
|
|
platform=None,
|
|
platform_original_path=None,
|
|
):
|
|
request = Mock(spec=Request)
|
|
request.url = Mock(path=path)
|
|
request.method = "GET"
|
|
request.headers = {"accept": "text/html"}
|
|
request.state = Mock()
|
|
request.state.frontend_type = frontend_type
|
|
request.state.store = store
|
|
request.state.store_context = store_context
|
|
request.state.platform = platform
|
|
request.state.platform_original_path = platform_original_path
|
|
return request
|
|
|
|
|
|
def _make_store(store_code="FASHIONHUB", subdomain="fashionhub"):
|
|
store = Mock()
|
|
store.store_code = store_code
|
|
store.subdomain = subdomain
|
|
return store
|
|
|
|
|
|
def _make_platform(code="loyalty"):
|
|
platform = Mock()
|
|
platform.code = code
|
|
return platform
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestRedirectToLogin:
|
|
"""Tests for _redirect_to_login storefront URL generation."""
|
|
|
|
def test_storefront_redirect_dev_mode_no_double_storefront(self):
|
|
"""Dev mode redirect should not have double 'storefront/' in URL."""
|
|
store = _make_store(store_code="FASHIONHUB")
|
|
platform = _make_platform(code="loyalty")
|
|
store_context = {"detection_method": "path", "full_prefix": "/storefront/"}
|
|
|
|
request = _make_request(
|
|
store=store,
|
|
store_context=store_context,
|
|
platform=platform,
|
|
platform_original_path="/platforms/loyalty/storefront/FASHIONHUB/account/dashboard",
|
|
)
|
|
|
|
response = _redirect_to_login(request)
|
|
|
|
assert response.status_code == 302
|
|
location = response.headers["location"]
|
|
assert location == "/platforms/loyalty/storefront/FASHIONHUB/account/login"
|
|
assert "/storefront/storefront/" not in location
|
|
|
|
def test_storefront_redirect_prod_mode(self):
|
|
"""Prod mode redirect should use /account/login."""
|
|
store = _make_store()
|
|
store_context = {"detection_method": "subdomain", "subdomain": "fashionhub"}
|
|
|
|
request = _make_request(
|
|
store=store,
|
|
store_context=store_context,
|
|
)
|
|
|
|
response = _redirect_to_login(request)
|
|
|
|
assert response.status_code == 302
|
|
location = response.headers["location"]
|
|
assert location == "/account/login"
|
|
|
|
def test_storefront_redirect_uses_store_code_not_subdomain(self):
|
|
"""Redirect URL should use store_code (uppercase), not subdomain (lowercase)."""
|
|
store = _make_store(store_code="FASHIONHUB", subdomain="fashionhub")
|
|
platform = _make_platform(code="loyalty")
|
|
store_context = {"detection_method": "path", "full_prefix": "/storefront/"}
|
|
|
|
request = _make_request(
|
|
store=store,
|
|
store_context=store_context,
|
|
platform=platform,
|
|
platform_original_path="/platforms/loyalty/storefront/FASHIONHUB/dashboard",
|
|
)
|
|
|
|
response = _redirect_to_login(request)
|
|
|
|
location = response.headers["location"]
|
|
assert "FASHIONHUB" in location
|
|
assert "fashionhub" not in location
|
|
|
|
def test_admin_redirect(self):
|
|
"""Admin requests redirect to /admin/login."""
|
|
request = _make_request(frontend_type=FrontendType.ADMIN)
|
|
|
|
response = _redirect_to_login(request)
|
|
|
|
assert response.headers["location"] == "/admin/login"
|
|
|
|
def test_merchant_redirect(self):
|
|
"""Merchant requests redirect to /merchants/login."""
|
|
request = _make_request(frontend_type=FrontendType.MERCHANT)
|
|
|
|
response = _redirect_to_login(request)
|
|
|
|
assert response.headers["location"] == "/merchants/login"
|