test(loyalty): add integration and unit tests for analytics, pages, and stats
Some checks failed
Some checks failed
- Add merchant stats API tests (GET /merchants/loyalty/stats) with 7 test cases - Add merchant page route tests (program, program-edit, analytics) with 6 test cases - Add store page route tests (terminal, cards, card-detail, program, program-edit, analytics, enroll) with 16 test cases - Add unit tests for get_merchant_stats() enhanced fields (new_this_month, estimated_liability_cents, location breakdown) with 6 test cases - Add unit tests for get_platform_stats() enhanced fields (total_points_issued/redeemed, total_points_balance, new_this_month, estimated_liability_cents) with 4 test cases - Total: 38 new tests (174 -> 212 passing) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -265,3 +265,110 @@ class TestMerchantDeleteProgram:
|
||||
f"{BASE}/program", headers=loyalty_merchant_headers
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# GET /stats
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.api
|
||||
@pytest.mark.loyalty
|
||||
class TestMerchantGetStats:
|
||||
"""Tests for GET /api/v1/merchants/loyalty/stats."""
|
||||
|
||||
def test_get_stats_success(
|
||||
self, client, loyalty_merchant_headers, loyalty_store_setup
|
||||
):
|
||||
"""Returns merchant-wide loyalty statistics."""
|
||||
response = client.get(
|
||||
f"{BASE}/stats", headers=loyalty_merchant_headers
|
||||
)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["merchant_id"] == loyalty_store_setup["merchant"].id
|
||||
assert data["program_id"] == loyalty_store_setup["program"].id
|
||||
|
||||
def test_get_stats_includes_card_counts(
|
||||
self, client, loyalty_merchant_headers, loyalty_store_setup
|
||||
):
|
||||
"""Stats include card counts from existing setup."""
|
||||
response = client.get(
|
||||
f"{BASE}/stats", headers=loyalty_merchant_headers
|
||||
)
|
||||
data = response.json()
|
||||
# loyalty_store_setup creates 1 card
|
||||
assert data["total_cards"] == 1
|
||||
assert data["active_cards"] == 1
|
||||
|
||||
def test_get_stats_includes_all_fields(
|
||||
self, client, loyalty_merchant_headers, loyalty_store_setup
|
||||
):
|
||||
"""Response includes all expected stat fields."""
|
||||
response = client.get(
|
||||
f"{BASE}/stats", headers=loyalty_merchant_headers
|
||||
)
|
||||
data = response.json()
|
||||
expected_fields = [
|
||||
"merchant_id",
|
||||
"program_id",
|
||||
"total_cards",
|
||||
"active_cards",
|
||||
"new_this_month",
|
||||
"total_points_issued",
|
||||
"total_points_redeemed",
|
||||
"points_issued_30d",
|
||||
"points_redeemed_30d",
|
||||
"transactions_30d",
|
||||
"estimated_liability_cents",
|
||||
"program",
|
||||
"locations",
|
||||
]
|
||||
for field in expected_fields:
|
||||
assert field in data, f"Missing field: {field}"
|
||||
|
||||
def test_get_stats_includes_program_info(
|
||||
self, client, loyalty_merchant_headers, loyalty_store_setup
|
||||
):
|
||||
"""Stats include program configuration details."""
|
||||
response = client.get(
|
||||
f"{BASE}/stats", headers=loyalty_merchant_headers
|
||||
)
|
||||
data = response.json()
|
||||
assert data["program"] is not None
|
||||
assert data["program"]["loyalty_type"] == "points"
|
||||
assert data["program"]["points_per_euro"] == 10
|
||||
|
||||
def test_get_stats_includes_locations(
|
||||
self, client, loyalty_merchant_headers, loyalty_store_setup
|
||||
):
|
||||
"""Stats include per-location breakdown."""
|
||||
response = client.get(
|
||||
f"{BASE}/stats", headers=loyalty_merchant_headers
|
||||
)
|
||||
data = response.json()
|
||||
assert isinstance(data["locations"], list)
|
||||
# loyalty_store_setup creates 1 store
|
||||
assert len(data["locations"]) >= 1
|
||||
loc = data["locations"][0]
|
||||
assert "store_id" in loc
|
||||
assert "store_name" in loc
|
||||
assert "enrolled_count" in loc
|
||||
assert "points_earned" in loc
|
||||
assert "points_redeemed" in loc
|
||||
assert "transactions_30d" in loc
|
||||
|
||||
def test_get_stats_no_program(
|
||||
self, client, loyalty_merchant_headers_no_program
|
||||
):
|
||||
"""Returns empty stats when merchant has no program."""
|
||||
response = client.get(
|
||||
f"{BASE}/stats", headers=loyalty_merchant_headers_no_program
|
||||
)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["program_id"] is None
|
||||
assert data["total_cards"] == 0
|
||||
assert data["program"] is None
|
||||
assert data["locations"] == []
|
||||
|
||||
Reference in New Issue
Block a user