Files
orion/app/modules/tenancy/tests/unit/test_tenancy_onboarding.py
Samir Boulahtit ef9ea29643 feat: module-driven onboarding system + simplified 3-step signup
Add OnboardingProviderProtocol so modules declare their own post-signup
onboarding steps. The core OnboardingAggregator discovers enabled
providers and exposes a dashboard API (GET /dashboard/onboarding).
A session-scoped banner on the store dashboard shows a checklist that
guides merchants through setup without blocking signup.

Signup is simplified from 4 steps to 3 (Plan → Account → Payment):
store creation is merged into account creation, store language is
captured from the user's browsing language, and platform-specific
template branching is removed.

Includes 47 unit and integration tests covering all new providers,
the aggregator, the API endpoint, and the signup service changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:39:42 +01:00

116 lines
3.8 KiB
Python

# app/modules/tenancy/tests/unit/test_tenancy_onboarding.py
"""Unit tests for TenancyOnboardingProvider."""
import uuid
import pytest
from app.modules.tenancy.models import Merchant, Store, User
from app.modules.tenancy.services.tenancy_onboarding import TenancyOnboardingProvider
@pytest.fixture
def onb_owner(db):
"""Create a store owner for onboarding tests."""
from middleware.auth import AuthManager
auth = AuthManager()
user = User(
email=f"onbowner_{uuid.uuid4().hex[:8]}@test.com",
username=f"onbowner_{uuid.uuid4().hex[:8]}",
hashed_password=auth.hash_password("pass123"),
role="merchant_owner",
is_active=True,
)
db.add(user)
db.commit()
db.refresh(user)
return user
@pytest.fixture
def onb_merchant(db, onb_owner):
"""Create a merchant for onboarding tests."""
merchant = Merchant(
name="Onboarding Test Merchant",
owner_user_id=onb_owner.id,
contact_email=onb_owner.email,
is_active=True,
is_verified=True,
)
db.add(merchant)
db.commit()
db.refresh(merchant)
return merchant
@pytest.fixture
def onb_store(db, onb_merchant):
"""Create a store with no description and no logo."""
uid = uuid.uuid4().hex[:8]
store = Store(
merchant_id=onb_merchant.id,
store_code=f"ONBSTORE_{uid.upper()}",
subdomain=f"onbstore{uid.lower()}",
name="Onboarding Test Store",
is_active=True,
is_verified=True,
)
db.add(store)
db.commit()
db.refresh(store)
return store
@pytest.mark.unit
@pytest.mark.tenancy
class TestTenancyOnboardingProvider:
"""Tests for TenancyOnboardingProvider."""
def setup_method(self):
self.provider = TenancyOnboardingProvider()
def test_category(self):
"""Returns 'tenancy' as the onboarding category."""
assert self.provider.onboarding_category == "tenancy"
def test_get_onboarding_steps_returns_one_step(self):
"""Returns exactly one step: customize_store."""
steps = self.provider.get_onboarding_steps()
assert len(steps) == 1
assert steps[0].key == "tenancy.customize_store"
assert steps[0].route_template == "/store/{store_code}/settings"
assert steps[0].order == 100
def test_incomplete_when_no_description_no_logo(self, db, onb_store):
"""Step is not completed when store has no description and no logo."""
assert onb_store.description is None or onb_store.description.strip() == ""
result = self.provider.is_step_completed(db, onb_store.id, "tenancy.customize_store")
assert result is False
def test_completed_when_store_has_description(self, db, onb_store):
"""Step is completed when store has a non-empty description."""
onb_store.description = "We sell great coffee!"
db.commit()
result = self.provider.is_step_completed(db, onb_store.id, "tenancy.customize_store")
assert result is True
def test_incomplete_when_description_is_whitespace(self, db, onb_store):
"""Step is not completed when description is whitespace only."""
onb_store.description = " "
db.commit()
result = self.provider.is_step_completed(db, onb_store.id, "tenancy.customize_store")
assert result is False
def test_incomplete_for_nonexistent_store(self, db):
"""Returns False for a store ID that doesn't exist."""
result = self.provider.is_step_completed(db, 999999, "tenancy.customize_store")
assert result is False
def test_incomplete_for_unknown_step_key(self, db, onb_store):
"""Returns False for an unrecognized step key."""
result = self.provider.is_step_completed(db, onb_store.id, "tenancy.unknown_step")
assert result is False