- Run tests for all 10 services via per-service pytest subprocesses - Group results by service with section headers - Clickable summary cards filter by outcome (passed/failed/errors/skipped) - Service filter nav using ~nav-link buttons in menu bar - Full menu integration: ~header-row + ~header-child + ~menu-row - Show logo image via cart-mini rendering - Mount full service directories in docker-compose for test access - Add 24 unit test files across 9 services Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
140 lines
5.0 KiB
Python
140 lines
5.0 KiB
Python
"""Unit tests for cart checkout helpers."""
|
|
from __future__ import annotations
|
|
|
|
from types import SimpleNamespace
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from cart.bp.cart.services.checkout import (
|
|
build_sumup_description,
|
|
build_sumup_reference,
|
|
build_webhook_url,
|
|
validate_webhook_secret,
|
|
)
|
|
|
|
|
|
def _ci(title=None, qty=1):
|
|
return SimpleNamespace(product_title=title, quantity=qty)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# build_sumup_description
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestBuildSumupDescription:
|
|
def test_empty_cart_no_tickets(self):
|
|
result = build_sumup_description([], 1)
|
|
assert "Order 1" in result
|
|
assert "0 items" in result
|
|
assert "order items" in result
|
|
|
|
def test_single_item(self):
|
|
result = build_sumup_description([_ci("Widget", 1)], 42)
|
|
assert "Order 42" in result
|
|
assert "1 item)" in result
|
|
assert "Widget" in result
|
|
|
|
def test_quantity_counted(self):
|
|
result = build_sumup_description([_ci("Widget", 3)], 1)
|
|
assert "3 items" in result
|
|
|
|
def test_three_titles(self):
|
|
items = [_ci("A"), _ci("B"), _ci("C")]
|
|
result = build_sumup_description(items, 1)
|
|
assert "A, B, C" in result
|
|
assert "more" not in result
|
|
|
|
def test_four_titles_truncated(self):
|
|
items = [_ci("A"), _ci("B"), _ci("C"), _ci("D")]
|
|
result = build_sumup_description(items, 1)
|
|
assert "A, B, C" in result
|
|
assert "+ 1 more" in result
|
|
|
|
def test_none_titles_excluded(self):
|
|
items = [_ci(None), _ci("Visible")]
|
|
result = build_sumup_description(items, 1)
|
|
assert "Visible" in result
|
|
|
|
def test_tickets_singular(self):
|
|
result = build_sumup_description([], 1, ticket_count=1)
|
|
assert "1 ticket" in result
|
|
assert "tickets" not in result
|
|
|
|
def test_tickets_plural(self):
|
|
result = build_sumup_description([], 1, ticket_count=3)
|
|
assert "3 tickets" in result
|
|
|
|
def test_mixed_items_and_tickets(self):
|
|
result = build_sumup_description([_ci("A", 2)], 1, ticket_count=1)
|
|
assert "3 items" in result # 2 + 1
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# build_sumup_reference
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestBuildSumupReference:
|
|
def test_with_page_config(self):
|
|
pc = SimpleNamespace(sumup_checkout_prefix="SHOP-")
|
|
assert build_sumup_reference(42, pc) == "SHOP-42"
|
|
|
|
def test_without_page_config(self):
|
|
with patch("cart.bp.cart.services.checkout.config",
|
|
return_value={"sumup": {"checkout_reference_prefix": "RA-"}}):
|
|
assert build_sumup_reference(99) == "RA-99"
|
|
|
|
def test_no_prefix(self):
|
|
with patch("cart.bp.cart.services.checkout.config",
|
|
return_value={"sumup": {}}):
|
|
assert build_sumup_reference(1) == "1"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# build_webhook_url
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestBuildWebhookUrl:
|
|
def test_no_secret(self):
|
|
with patch("cart.bp.cart.services.checkout.config",
|
|
return_value={"sumup": {}}):
|
|
assert build_webhook_url("https://x.com/hook") == "https://x.com/hook"
|
|
|
|
def test_with_secret_no_query(self):
|
|
with patch("cart.bp.cart.services.checkout.config",
|
|
return_value={"sumup": {"webhook_secret": "s3cret"}}):
|
|
result = build_webhook_url("https://x.com/hook")
|
|
assert "?token=s3cret" in result
|
|
|
|
def test_with_secret_existing_query(self):
|
|
with patch("cart.bp.cart.services.checkout.config",
|
|
return_value={"sumup": {"webhook_secret": "s3cret"}}):
|
|
result = build_webhook_url("https://x.com/hook?a=1")
|
|
assert "&token=s3cret" in result
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# validate_webhook_secret
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestValidateWebhookSecret:
|
|
def test_no_secret_configured(self):
|
|
with patch("cart.bp.cart.services.checkout.config",
|
|
return_value={"sumup": {}}):
|
|
assert validate_webhook_secret(None) is True
|
|
|
|
def test_correct_token(self):
|
|
with patch("cart.bp.cart.services.checkout.config",
|
|
return_value={"sumup": {"webhook_secret": "abc"}}):
|
|
assert validate_webhook_secret("abc") is True
|
|
|
|
def test_wrong_token(self):
|
|
with patch("cart.bp.cart.services.checkout.config",
|
|
return_value={"sumup": {"webhook_secret": "abc"}}):
|
|
assert validate_webhook_secret("wrong") is False
|
|
|
|
def test_none_token_with_secret(self):
|
|
with patch("cart.bp.cart.services.checkout.config",
|
|
return_value={"sumup": {"webhook_secret": "abc"}}):
|
|
assert validate_webhook_secret(None) is False
|