Files
orion/tests/integration/api/v1/store/test_onboarding.py
Samir Boulahtit 35d1559162
Some checks failed
CI / ruff (push) Successful in 10s
CI / pytest (push) Failing after 47m30s
CI / validate (push) Successful in 24s
CI / dependency-scanning (push) Successful in 29s
CI / docs (push) Has been skipped
CI / deploy (push) Has been skipped
feat(monitoring): add Redis exporter + Sentry docs to deployment guide
- Add redis-exporter container to docker-compose (oliver006/redis_exporter, 32MB)
- Add Redis scrape target to Prometheus config
- Add 4 Redis alert rules: RedisDown, HighMemory, HighConnections, RejectedConnections
- Document Step 19b (Sentry Error Tracking) in Hetzner deployment guide
- Document Step 19c (Redis Monitoring) in Hetzner deployment guide
- Update resource budget and port reference tables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 23:30:18 +01:00

334 lines
11 KiB
Python

# tests/integration/api/v1/store/test_onboarding.py
"""
Integration tests for store onboarding API endpoints.
Tests cover:
1. Onboarding status retrieval
2. Step 1: Merchant profile setup
3. Step 2: Letzshop API configuration
4. Step 3: Product import configuration
5. Step 4: Order sync (mocked)
6. Step order validation (can't skip ahead)
7. Onboarding completion flow
"""
import pytest
from app.modules.marketplace.models import (
OnboardingStatus,
OnboardingStep,
StoreOnboarding,
)
@pytest.mark.integration
@pytest.mark.api
@pytest.mark.store
class TestStoreOnboardingStatusAPI:
"""Test onboarding status endpoint"""
def test_get_status_creates_onboarding_if_missing(
self, client, store_user_headers, test_store_with_store_user, db
):
"""Test that getting status creates onboarding record if none exists"""
# First ensure no onboarding exists
existing = (
db.query(StoreOnboarding)
.filter(StoreOnboarding.store_id == test_store_with_store_user.id)
.first()
)
if existing:
db.delete(existing)
db.commit()
response = client.get(
"/api/v1/store/onboarding/status", headers=store_user_headers
)
assert response.status_code == 200
data = response.json()
assert data["store_id"] == test_store_with_store_user.id
assert data["status"] == OnboardingStatus.NOT_STARTED.value
assert data["current_step"] == OnboardingStep.MERCHANT_PROFILE.value
assert data["completed_steps_count"] == 0
assert data["total_steps"] == 4
assert data["is_completed"] is False
def test_get_status_structure(
self, client, store_user_headers, test_store_with_store_user, db
):
"""Test status response has correct structure"""
response = client.get(
"/api/v1/store/onboarding/status", headers=store_user_headers
)
assert response.status_code == 200
data = response.json()
# Verify structure
assert "id" in data
assert "store_id" in data
assert "status" in data
assert "current_step" in data
assert "merchant_profile" in data
assert "letzshop_api" in data
assert "product_import" in data
assert "order_sync" in data
assert "completion_percentage" in data
assert "completed_steps_count" in data
assert "total_steps" in data
assert "is_completed" in data
def test_get_status_requires_auth(self, client):
"""Test that onboarding status requires authentication"""
response = client.get("/api/v1/store/onboarding/status")
assert response.status_code == 401
@pytest.mark.integration
@pytest.mark.api
@pytest.mark.store
class TestStoreOnboardingStep1API:
"""Test Step 1: Merchant Profile endpoints"""
def test_get_merchant_profile_data(
self, client, store_user_headers, test_store_with_store_user, db
):
"""Test getting merchant profile data"""
response = client.get(
"/api/v1/store/onboarding/step/merchant-profile",
headers=store_user_headers,
)
assert response.status_code == 200
data = response.json()
# Should return pre-filled data
assert "brand_name" in data
assert "contact_email" in data
assert "default_language" in data
def test_save_merchant_profile_success(
self, client, store_user_headers, test_store_with_store_user, db
):
"""Test saving merchant profile completes step 1"""
# First ensure clean state
existing = (
db.query(StoreOnboarding)
.filter(StoreOnboarding.store_id == test_store_with_store_user.id)
.first()
)
if existing:
db.delete(existing)
db.commit()
response = client.post(
"/api/v1/store/onboarding/step/merchant-profile",
headers=store_user_headers,
json={
"merchant_name": "Test Merchant Ltd",
"brand_name": "Test Brand",
"description": "A test merchant for testing",
"contact_email": "test@example.com",
"contact_phone": "+352123456789",
"website": "https://test.example.com",
"business_address": "123 Test Street, Luxembourg",
"tax_number": "LU12345678",
"default_language": "fr",
"dashboard_language": "en",
},
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
assert data["step_completed"] is True
assert data["next_step"] == OnboardingStep.LETZSHOP_API.value
# Verify onboarding was updated
onboarding = (
db.query(StoreOnboarding)
.filter(StoreOnboarding.store_id == test_store_with_store_user.id)
.first()
)
db.refresh(onboarding)
assert onboarding.step_merchant_profile_completed is True
assert onboarding.status == OnboardingStatus.IN_PROGRESS.value
def test_save_merchant_profile_with_minimal_data(
self, client, store_user_headers, test_store_with_store_user, db
):
"""Test saving merchant profile with minimal data"""
# Clear existing onboarding
existing = (
db.query(StoreOnboarding)
.filter(StoreOnboarding.store_id == test_store_with_store_user.id)
.first()
)
if existing:
db.delete(existing)
db.commit()
response = client.post(
"/api/v1/store/onboarding/step/merchant-profile",
headers=store_user_headers,
json={
"default_language": "fr",
"dashboard_language": "fr",
},
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
@pytest.mark.integration
@pytest.mark.api
@pytest.mark.store
class TestStoreOnboardingStep2API:
"""Test Step 2: Letzshop API Configuration endpoints"""
def test_letzshop_api_test_endpoint(
self, client, store_user_headers, test_store_with_store_user
):
"""Test the Letzshop API test endpoint"""
response = client.post(
"/api/v1/store/onboarding/step/letzshop-api/test",
headers=store_user_headers,
json={
"api_key": "test_invalid_key_12345",
"shop_slug": "test-shop",
},
)
assert response.status_code == 200
data = response.json()
# Response should indicate success or failure
assert "success" in data
assert "message" in data
def test_letzshop_api_requires_step1_complete(
self, client, store_user_headers, test_store_with_store_user, db
):
"""Test that step 2 requires step 1 to be completed"""
# Ensure fresh state with no steps completed
existing = (
db.query(StoreOnboarding)
.filter(StoreOnboarding.store_id == test_store_with_store_user.id)
.first()
)
if existing:
db.delete(existing)
db.commit()
# Try to save step 2 directly
response = client.post(
"/api/v1/store/onboarding/step/letzshop-api",
headers=store_user_headers,
json={
"api_key": "test_api_key_12345678901234567890",
"shop_slug": "test-shop",
},
)
# Should fail because step 1 is not complete
assert response.status_code == 422 # Validation error
data = response.json()
assert "step" in str(data).lower() or "complete" in str(data).lower()
@pytest.mark.integration
@pytest.mark.api
@pytest.mark.store
class TestStoreOnboardingStep3API:
"""Test Step 3: Product Import Configuration endpoints"""
def test_get_product_import_config(
self, client, store_user_headers, test_store_with_store_user
):
"""Test getting product import configuration"""
response = client.get(
"/api/v1/store/onboarding/step/product-import",
headers=store_user_headers,
)
assert response.status_code == 200
data = response.json()
assert "csv_url_fr" in data
assert "csv_url_en" in data
assert "csv_url_de" in data
assert "default_tax_rate" in data
assert "delivery_method" in data
def test_product_import_requires_csv_url(
self, client, store_user_headers, test_store_with_store_user, db
):
"""Test that product import requires at least one CSV URL"""
# Set up: complete steps 1 and 2 first
onboarding = (
db.query(StoreOnboarding)
.filter(StoreOnboarding.store_id == test_store_with_store_user.id)
.first()
)
if not onboarding:
onboarding = StoreOnboarding(
store_id=test_store_with_store_user.id,
status=OnboardingStatus.IN_PROGRESS.value,
current_step=OnboardingStep.PRODUCT_IMPORT.value,
)
db.add(onboarding)
onboarding.step_merchant_profile_completed = True
onboarding.step_letzshop_api_completed = True
onboarding.current_step = OnboardingStep.PRODUCT_IMPORT.value
db.commit()
# Try to save without any CSV URL
response = client.post(
"/api/v1/store/onboarding/step/product-import",
headers=store_user_headers,
json={
"default_tax_rate": 17,
"delivery_method": "package_delivery",
"preorder_days": 1,
},
)
# Should fail with validation error
assert response.status_code == 422
@pytest.mark.integration
@pytest.mark.api
@pytest.mark.store
class TestStoreOnboardingStep4API:
"""Test Step 4: Order Sync endpoints"""
def test_order_sync_progress_endpoint(
self, client, store_user_headers, test_store_with_store_user
):
"""Test getting order sync progress for non-existent job"""
response = client.get(
"/api/v1/store/onboarding/step/order-sync/progress/99999",
headers=store_user_headers,
)
assert response.status_code == 200
data = response.json()
# Should return not_found status for non-existent job
assert data["status"] == "not_found"
assert data["job_id"] == 99999
@pytest.mark.integration
@pytest.mark.api
@pytest.mark.store
class TestStoreOnboardingFlowAPI:
"""Test complete onboarding flow"""