fix: storefront login 403, cookie path, double-storefront URLs, and auth redirects
- 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>
This commit is contained in:
@@ -733,6 +733,115 @@ class TestStoreContextMiddleware:
|
||||
assert request.state.clean_path == "/random/path"
|
||||
call_next.assert_called_once_with(request)
|
||||
|
||||
# ========================================================================
|
||||
# Storefront API Referer Tests
|
||||
# ========================================================================
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_middleware_storefront_api_uses_referer(self):
|
||||
"""Test storefront API requests get store context from Referer header."""
|
||||
middleware = StoreContextMiddleware(app=None)
|
||||
|
||||
request = Mock(spec=Request)
|
||||
request.headers = {
|
||||
"host": "localhost",
|
||||
"referer": "http://localhost:8000/platforms/loyalty/storefront/FASHIONHUB/account/login",
|
||||
}
|
||||
request.url = Mock(path="/api/v1/storefront/auth/login")
|
||||
request.state = Mock()
|
||||
|
||||
call_next = AsyncMock(return_value=Mock())
|
||||
|
||||
mock_store = Mock()
|
||||
mock_store.id = 4
|
||||
mock_store.name = "Fashion Hub"
|
||||
mock_store.subdomain = "fashionhub"
|
||||
|
||||
referer_context = {
|
||||
"subdomain": "FASHIONHUB",
|
||||
"detection_method": "path",
|
||||
"path_prefix": "/storefront/FASHIONHUB",
|
||||
"full_prefix": "/storefront/",
|
||||
"host": "localhost",
|
||||
"referer": "http://localhost:8000/platforms/loyalty/storefront/FASHIONHUB/account/login",
|
||||
}
|
||||
|
||||
mock_db = MagicMock()
|
||||
|
||||
with (
|
||||
patch.object(
|
||||
StoreContextManager,
|
||||
"is_api_request",
|
||||
return_value=True,
|
||||
),
|
||||
patch.object(
|
||||
StoreContextManager,
|
||||
"extract_store_from_referer",
|
||||
return_value=referer_context,
|
||||
),
|
||||
patch.object(
|
||||
StoreContextManager,
|
||||
"get_store_from_context",
|
||||
return_value=mock_store,
|
||||
),
|
||||
patch("middleware.store_context.get_db", return_value=iter([mock_db])),
|
||||
):
|
||||
await middleware.dispatch(request, call_next)
|
||||
|
||||
assert request.state.store is mock_store
|
||||
assert request.state.store_context is referer_context
|
||||
call_next.assert_called_once_with(request)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_middleware_storefront_api_no_referer(self):
|
||||
"""Test storefront API request without Referer header sets store to None."""
|
||||
middleware = StoreContextMiddleware(app=None)
|
||||
|
||||
request = Mock(spec=Request)
|
||||
request.headers = {"host": "localhost"}
|
||||
request.url = Mock(path="/api/v1/storefront/auth/login")
|
||||
request.state = Mock()
|
||||
|
||||
call_next = AsyncMock(return_value=Mock())
|
||||
|
||||
with (
|
||||
patch.object(
|
||||
StoreContextManager,
|
||||
"is_api_request",
|
||||
return_value=True,
|
||||
),
|
||||
patch.object(
|
||||
StoreContextManager,
|
||||
"extract_store_from_referer",
|
||||
return_value=None,
|
||||
),
|
||||
):
|
||||
await middleware.dispatch(request, call_next)
|
||||
|
||||
assert request.state.store is None
|
||||
assert request.state.store_context is None
|
||||
call_next.assert_called_once_with(request)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_middleware_non_storefront_api_still_skips(self):
|
||||
"""Test non-storefront API requests still skip store detection."""
|
||||
middleware = StoreContextMiddleware(app=None)
|
||||
|
||||
request = Mock(spec=Request)
|
||||
request.headers = {"host": "localhost"}
|
||||
request.url = Mock(path="/api/v1/admin/stores")
|
||||
request.state = Mock()
|
||||
|
||||
call_next = AsyncMock(return_value=Mock())
|
||||
|
||||
with patch.object(
|
||||
StoreContextManager, "is_api_request", return_value=True
|
||||
):
|
||||
await middleware.dispatch(request, call_next)
|
||||
|
||||
assert request.state.store is None
|
||||
call_next.assert_called_once_with(request)
|
||||
|
||||
# ========================================================================
|
||||
# System Path Skipping Tests
|
||||
# ========================================================================
|
||||
|
||||
Reference in New Issue
Block a user