Add Handbook.md benchmark tasks
This commit is contained in:
@@ -0,0 +1,538 @@
|
||||
"""Tests for loyalty program tools and create_order integration."""
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from shopify import state as shopify_state
|
||||
from shopify.models import (
|
||||
AwardPointsArgs,
|
||||
ConfigureLoyaltyProgramArgs,
|
||||
CreateDiscountCodeArgs,
|
||||
CreateOrderArgs,
|
||||
GetLoyaltyBalanceArgs,
|
||||
GetLoyaltyProgramArgs,
|
||||
GetLoyaltyTierArgs,
|
||||
ListLoyaltyTiersArgs,
|
||||
LoyaltyTier,
|
||||
RedeemPointsArgs,
|
||||
UpdateDiscountCodeArgs,
|
||||
)
|
||||
from shopify.tools.discounts import handle_create_discount_code, handle_update_discount_code
|
||||
from shopify.tools.loyalty import (
|
||||
compute_tier,
|
||||
handle_award_points,
|
||||
handle_configure_loyalty_program,
|
||||
handle_get_loyalty_balance,
|
||||
handle_get_loyalty_program,
|
||||
handle_get_loyalty_tier,
|
||||
handle_list_loyalty_tiers,
|
||||
handle_redeem_points,
|
||||
)
|
||||
from shopify.tools.orders import handle_create_order
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def shopify_data(tmp_path):
|
||||
data_file = tmp_path / "shopify_data.json"
|
||||
data_file.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"products": {
|
||||
"gid://shopify/Product/1": {
|
||||
"id": "gid://shopify/Product/1",
|
||||
"title": "Widget",
|
||||
"variants": [
|
||||
{
|
||||
"id": "gid://shopify/ProductVariant/1",
|
||||
"title": "Default",
|
||||
"price": {"amount": "100.00", "currencyCode": "USD"},
|
||||
"availableForSale": True,
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
"carts": {
|
||||
"gid://shopify/Cart/c1001": {
|
||||
"id": "gid://shopify/Cart/c1001",
|
||||
"lines": [
|
||||
{
|
||||
"id": "gid://shopify/CartLine/1001",
|
||||
"quantity": 1,
|
||||
"merchandise": {
|
||||
"id": "gid://shopify/ProductVariant/1",
|
||||
"title": "Default",
|
||||
"price": {"amount": "100.00", "currencyCode": "USD"},
|
||||
"product": {"id": "gid://shopify/Product/1", "title": "Widget"},
|
||||
},
|
||||
"cost": {
|
||||
"amountPerQuantity": {"amount": "100.00", "currencyCode": "USD"},
|
||||
"subtotalAmount": {"amount": "100.00", "currencyCode": "USD"},
|
||||
"totalAmount": {"amount": "100.00", "currencyCode": "USD"},
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
"orders": {},
|
||||
"customers": {
|
||||
"gid://shopify/Customer/5001": {
|
||||
"id": "gid://shopify/Customer/5001",
|
||||
"firstName": "Jane",
|
||||
"lastName": "Doe",
|
||||
"email": "jane@example.com",
|
||||
"phone": None,
|
||||
"createdAt": "2026-01-01T00:00:00Z",
|
||||
"updatedAt": "2026-01-01T00:00:00Z",
|
||||
"defaultAddress": None,
|
||||
"addresses": [],
|
||||
"ordersCount": 0,
|
||||
"totalSpent": None,
|
||||
"tags": [],
|
||||
"note": None,
|
||||
"acceptsMarketing": False,
|
||||
"state": "ENABLED",
|
||||
}
|
||||
},
|
||||
"collections": {},
|
||||
"reviews": {},
|
||||
"returns": {},
|
||||
"discount_codes": {},
|
||||
"shipping_methods": {
|
||||
"standard": {
|
||||
"id": "standard",
|
||||
"title": "Standard Shipping",
|
||||
"price": {"amount": "5.00", "currencyCode": "USD"},
|
||||
"estimatedDays": "5-7",
|
||||
"active": True,
|
||||
}
|
||||
},
|
||||
"loyalty_program": {
|
||||
"enabled": True,
|
||||
"earn_rate": 1,
|
||||
"redemption_rate": 100,
|
||||
"max_redemption_percent": 50,
|
||||
"tiers": [
|
||||
{"name": "Bronze", "min_lifetime_points": 0, "discount_percent": 5},
|
||||
{"name": "Silver", "min_lifetime_points": 1000, "discount_percent": 10},
|
||||
{"name": "Gold", "min_lifetime_points": 5000, "discount_percent": 15},
|
||||
],
|
||||
},
|
||||
"policies": [],
|
||||
"counters": {
|
||||
"cart_id": 1001,
|
||||
"line_id": 1001,
|
||||
"order_id": 2001,
|
||||
"line_item_id": 3001,
|
||||
"customer_id": 5001,
|
||||
"collection_id": 6001,
|
||||
"review_id": 7001,
|
||||
"return_id": 8001,
|
||||
"product_id": 9001,
|
||||
"variant_id": 10001,
|
||||
"discount_id": 11001,
|
||||
"policy_id": 12001,
|
||||
},
|
||||
}
|
||||
)
|
||||
)
|
||||
return data_file
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _patch_state(shopify_data, monkeypatch):
|
||||
monkeypatch.setattr(shopify_state, "_STATE_FILE", shopify_data)
|
||||
shopify_state._current_state = None
|
||||
shopify_state._stores.clear()
|
||||
shopify_state._active_store_id = "default"
|
||||
shopify_state.load_state()
|
||||
|
||||
|
||||
# ============================================
|
||||
# compute_tier UNIT TESTS
|
||||
# ============================================
|
||||
|
||||
|
||||
class TestComputeTier:
|
||||
def test_no_tiers_returns_none(self):
|
||||
assert compute_tier(1000, []) is None
|
||||
|
||||
def test_below_lowest_threshold_returns_none(self):
|
||||
tiers = [LoyaltyTier(name="Silver", min_lifetime_points=1000, discount_percent=10)]
|
||||
assert compute_tier(500, tiers) is None
|
||||
|
||||
def test_highest_matching_tier(self):
|
||||
tiers = [
|
||||
LoyaltyTier(name="Bronze", min_lifetime_points=0, discount_percent=5),
|
||||
LoyaltyTier(name="Silver", min_lifetime_points=1000, discount_percent=10),
|
||||
LoyaltyTier(name="Gold", min_lifetime_points=5000, discount_percent=15),
|
||||
]
|
||||
result = compute_tier(6000, tiers)
|
||||
assert result is not None
|
||||
assert result.name == "Gold"
|
||||
|
||||
def test_exact_threshold_qualifies(self):
|
||||
tiers = [LoyaltyTier(name="Silver", min_lifetime_points=1000, discount_percent=10)]
|
||||
result = compute_tier(1000, tiers)
|
||||
assert result is not None
|
||||
assert result.name == "Silver"
|
||||
|
||||
|
||||
# ============================================
|
||||
# PROGRAM CONFIG TESTS
|
||||
# ============================================
|
||||
|
||||
|
||||
class TestConfigureProgram:
|
||||
def test_toggle_enabled(self):
|
||||
result = handle_configure_loyalty_program(ConfigureLoyaltyProgramArgs(enabled=False))
|
||||
assert result["userErrors"] == []
|
||||
assert result["program"]["enabled"] is False
|
||||
|
||||
def test_update_earn_rate(self):
|
||||
result = handle_configure_loyalty_program(ConfigureLoyaltyProgramArgs(earn_rate=2))
|
||||
assert result["program"]["earn_rate"] == 2
|
||||
|
||||
def test_replace_tiers(self):
|
||||
new_tiers = [LoyaltyTier(name="VIP", min_lifetime_points=100, discount_percent=25)]
|
||||
result = handle_configure_loyalty_program(ConfigureLoyaltyProgramArgs(tiers=new_tiers))
|
||||
assert len(result["program"]["tiers"]) == 1
|
||||
assert result["program"]["tiers"][0]["name"] == "VIP"
|
||||
|
||||
def test_rejects_invalid_earn_rate(self):
|
||||
result = handle_configure_loyalty_program(ConfigureLoyaltyProgramArgs(earn_rate=-1))
|
||||
assert result["program"] is None
|
||||
assert len(result["userErrors"]) == 1
|
||||
|
||||
def test_rejects_invalid_config_before_any_mutation(self):
|
||||
state = shopify_state.get_state()
|
||||
result = handle_configure_loyalty_program(ConfigureLoyaltyProgramArgs(enabled=False, earn_rate=-1))
|
||||
assert result["program"] is None
|
||||
assert state.loyalty_program.enabled is True
|
||||
assert state.loyalty_program.earn_rate == 1
|
||||
|
||||
def test_rejects_invalid_redemption_rate(self):
|
||||
result = handle_configure_loyalty_program(ConfigureLoyaltyProgramArgs(redemption_rate=0))
|
||||
assert result["program"] is None
|
||||
|
||||
def test_rejects_invalid_percent(self):
|
||||
result = handle_configure_loyalty_program(ConfigureLoyaltyProgramArgs(max_redemption_percent=150))
|
||||
assert result["program"] is None
|
||||
|
||||
|
||||
class TestGetProgram:
|
||||
def test_read_program(self):
|
||||
result = handle_get_loyalty_program(GetLoyaltyProgramArgs())
|
||||
assert result["program"]["enabled"] is True
|
||||
assert result["program"]["earn_rate"] == 1
|
||||
|
||||
|
||||
class TestListTiers:
|
||||
def test_sorted_ascending(self):
|
||||
result = handle_list_loyalty_tiers(ListLoyaltyTiersArgs())
|
||||
assert result["totalCount"] == 3
|
||||
names = [t["name"] for t in result["tiers"]]
|
||||
assert names == ["Bronze", "Silver", "Gold"]
|
||||
|
||||
|
||||
# ============================================
|
||||
# BALANCE / TIER LOOKUP
|
||||
# ============================================
|
||||
|
||||
|
||||
class TestGetBalance:
|
||||
def test_new_customer_zero_balance(self):
|
||||
result = handle_get_loyalty_balance(GetLoyaltyBalanceArgs(customer_id="gid://shopify/Customer/5001"))
|
||||
assert result["userErrors"] == []
|
||||
assert result["balance"]["pointsBalance"] == 0
|
||||
assert result["balance"]["tier"] is None
|
||||
|
||||
def test_nonexistent_customer(self):
|
||||
result = handle_get_loyalty_balance(GetLoyaltyBalanceArgs(customer_id="nope"))
|
||||
assert result["balance"] is None
|
||||
assert len(result["userErrors"]) == 1
|
||||
|
||||
|
||||
class TestGetTier:
|
||||
def test_customer_with_lifetime_points(self):
|
||||
handle_award_points(AwardPointsArgs(customer_id="gid://shopify/Customer/5001", points=1200))
|
||||
result = handle_get_loyalty_tier(GetLoyaltyTierArgs(customer_id="gid://shopify/Customer/5001"))
|
||||
assert result["tier"]["name"] == "Silver"
|
||||
|
||||
def test_customer_no_tier(self):
|
||||
result = handle_get_loyalty_tier(GetLoyaltyTierArgs(customer_id="gid://shopify/Customer/5001"))
|
||||
# 0 lifetime points still qualifies for Bronze (min_lifetime_points=0)
|
||||
assert result["tier"]["name"] == "Bronze"
|
||||
|
||||
|
||||
# ============================================
|
||||
# AWARD / REDEEM
|
||||
# ============================================
|
||||
|
||||
|
||||
class TestAwardPoints:
|
||||
def test_award_grows_both_balances(self):
|
||||
result = handle_award_points(
|
||||
AwardPointsArgs(customer_id="gid://shopify/Customer/5001", points=500, reason="welcome bonus")
|
||||
)
|
||||
assert result["userErrors"] == []
|
||||
assert result["balance"]["pointsBalance"] == 500
|
||||
assert result["balance"]["lifetimePoints"] == 500
|
||||
|
||||
def test_award_updates_tier(self):
|
||||
handle_award_points(AwardPointsArgs(customer_id="gid://shopify/Customer/5001", points=1500))
|
||||
customer = shopify_state.get_customer_by_id("gid://shopify/Customer/5001")
|
||||
assert customer is not None
|
||||
assert customer["tier"] == "Silver"
|
||||
|
||||
def test_reject_negative_points(self):
|
||||
result = handle_award_points(AwardPointsArgs(customer_id="gid://shopify/Customer/5001", points=-10))
|
||||
assert result["balance"] is None
|
||||
|
||||
|
||||
class TestRedeemPoints:
|
||||
def test_redeem_reduces_balance(self):
|
||||
handle_award_points(AwardPointsArgs(customer_id="gid://shopify/Customer/5001", points=1000))
|
||||
result = handle_redeem_points(RedeemPointsArgs(customer_id="gid://shopify/Customer/5001", points=500))
|
||||
assert result["userErrors"] == []
|
||||
assert result["redemption"]["pointsBalance"] == 500
|
||||
assert result["redemption"]["dollarValue"]["amount"] == "5.00"
|
||||
|
||||
def test_redeem_preserves_lifetime_points(self):
|
||||
handle_award_points(AwardPointsArgs(customer_id="gid://shopify/Customer/5001", points=2000))
|
||||
handle_redeem_points(RedeemPointsArgs(customer_id="gid://shopify/Customer/5001", points=500))
|
||||
customer = shopify_state.get_customer_by_id("gid://shopify/Customer/5001")
|
||||
assert customer is not None
|
||||
assert customer["lifetimePoints"] == 2000
|
||||
assert customer["pointsBalance"] == 1500
|
||||
|
||||
def test_insufficient_balance(self):
|
||||
result = handle_redeem_points(RedeemPointsArgs(customer_id="gid://shopify/Customer/5001", points=100))
|
||||
assert result["redemption"] is None
|
||||
|
||||
|
||||
# ============================================
|
||||
# CREATE_ORDER INTEGRATION
|
||||
# ============================================
|
||||
|
||||
|
||||
def _default_order_args(**overrides):
|
||||
base: dict[str, Any] = {
|
||||
"cart_id": "gid://shopify/Cart/c1001",
|
||||
"payment_method": {
|
||||
"type": "credit_card",
|
||||
"card_number": "4111111111111111",
|
||||
"cvv": "123",
|
||||
"expiry": "12/26",
|
||||
},
|
||||
"shipping_address": {"address1": "1 Main", "city": "Portland", "countryCode": "US"},
|
||||
"billing_address": {"address1": "1 Main", "city": "Portland", "countryCode": "US"},
|
||||
"shipping_method_id": "standard",
|
||||
"email": "jane@example.com",
|
||||
}
|
||||
base.update(overrides)
|
||||
return CreateOrderArgs.model_validate(base)
|
||||
|
||||
|
||||
class TestOrderLoyaltyIntegration:
|
||||
def test_order_awards_points(self):
|
||||
result = handle_create_order(_default_order_args())
|
||||
assert result["userErrors"] == []
|
||||
order = result["order"]
|
||||
# Bronze tier = 5% off $100 subtotal = $5 tier discount, post-tier-discount = $95 → 95 points
|
||||
assert order["loyaltyPointsEarned"] == 95
|
||||
|
||||
def test_order_applies_tier_discount(self):
|
||||
result = handle_create_order(_default_order_args())
|
||||
order = result["order"]
|
||||
assert order["tierDiscount"]["name"] == "Bronze"
|
||||
assert order["tierDiscountAmount"]["amount"] == "5.00"
|
||||
# total = 100 - 5 tier + 5 shipping = 100
|
||||
assert order["totalPrice"]["amount"] == "100.00"
|
||||
|
||||
def test_tier_discount_can_be_disabled(self):
|
||||
result = handle_create_order(_default_order_args(apply_tier_discount=False))
|
||||
order = result["order"]
|
||||
assert order["tierDiscount"] is None
|
||||
assert order["tierDiscountAmount"]["amount"] == "0.00"
|
||||
|
||||
def test_order_redeems_points(self):
|
||||
handle_award_points(AwardPointsArgs(customer_id="gid://shopify/Customer/5001", points=1000))
|
||||
result = handle_create_order(_default_order_args(redeem_points=1000))
|
||||
order = result["order"]
|
||||
assert order["loyaltyPointsRedeemed"] == 1000
|
||||
# Bronze tier still qualifies (1000 lifetime points = Silver actually)
|
||||
# Silver = 10% off, so subtotal after tier = 90, redemption_cap = 45 (50% of 90)
|
||||
# $10 redemption requested (1000/100), capped at $45 → $10 applied
|
||||
assert order["loyaltyRedemptionAmount"]["amount"] == "10.00"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_public_create_order_exposes_redeem_points(self):
|
||||
from shopify.server import create_order
|
||||
|
||||
handle_award_points(AwardPointsArgs(customer_id="gid://shopify/Customer/5001", points=1000))
|
||||
|
||||
result = await create_order(
|
||||
cart_id="gid://shopify/Cart/c1001",
|
||||
payment_method={
|
||||
"type": "credit_card",
|
||||
"card_number": "4111111111111111",
|
||||
"cvv": "123",
|
||||
"expiry": "12/26",
|
||||
},
|
||||
shipping_address={"address1": "1 Main", "city": "Portland", "countryCode": "US"},
|
||||
billing_address={"address1": "1 Main", "city": "Portland", "countryCode": "US"},
|
||||
shipping_method_id="standard",
|
||||
email="jane@example.com",
|
||||
redeem_points=1000,
|
||||
)
|
||||
|
||||
order = result["order"]
|
||||
assert result["userErrors"] == []
|
||||
assert order["loyaltyPointsRedeemed"] == 1000
|
||||
assert order["loyaltyRedemptionAmount"]["amount"] == "10.00"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_public_create_order_falls_back_to_current_customer_email(self):
|
||||
from shopify.server import create_order
|
||||
|
||||
shopify_state.get_state().current_customer_email = "jane@example.com"
|
||||
|
||||
result = await create_order(
|
||||
cart_id="gid://shopify/Cart/c1001",
|
||||
payment_method={
|
||||
"type": "credit_card",
|
||||
"card_number": "4111111111111111",
|
||||
"cvv": "123",
|
||||
"expiry": "12/26",
|
||||
},
|
||||
shipping_address={"address1": "1 Main", "city": "Portland", "countryCode": "US"},
|
||||
billing_address={"address1": "1 Main", "city": "Portland", "countryCode": "US"},
|
||||
shipping_method_id="standard",
|
||||
)
|
||||
|
||||
assert result["userErrors"] == []
|
||||
assert result["order"]["email"] == "jane@example.com"
|
||||
assert shopify_state.get_state().customers["gid://shopify/Customer/5001"].ordersCount == 1
|
||||
|
||||
def test_redeem_respects_max_percent_cap(self):
|
||||
# Award 50000 points ($500 of value), subtotal only $100
|
||||
handle_award_points(AwardPointsArgs(customer_id="gid://shopify/Customer/5001", points=50000))
|
||||
result = handle_create_order(_default_order_args(redeem_points=10000))
|
||||
order = result["order"]
|
||||
# 50000 lifetime = Gold tier (15% off), subtotal after tier = $85
|
||||
# Max redemption = 50% of 85 = $42.50
|
||||
# Requested $100 (10000/100), capped at $42.50
|
||||
assert order["loyaltyRedemptionAmount"]["amount"] == "42.50"
|
||||
# Only the points that became discount should be deducted: $42.50 * 100 = 4250.
|
||||
# Burning the full 10000 would cost the customer 5750 points of value for
|
||||
# nothing.
|
||||
assert order["loyaltyPointsRedeemed"] == 4250
|
||||
|
||||
def test_redeem_requires_enabled_program(self):
|
||||
handle_award_points(AwardPointsArgs(customer_id="gid://shopify/Customer/5001", points=1000))
|
||||
handle_configure_loyalty_program(ConfigureLoyaltyProgramArgs(enabled=False))
|
||||
result = handle_create_order(_default_order_args(redeem_points=500))
|
||||
assert result["order"] is None
|
||||
assert any(e["field"] == "redeem_points" for e in result["userErrors"])
|
||||
|
||||
def test_redeem_requires_customer_lookup(self):
|
||||
# Email with no matching customer
|
||||
result = handle_create_order(_default_order_args(redeem_points=500, email="unknown@example.com"))
|
||||
assert result["order"] is None
|
||||
|
||||
def test_order_updates_customer_totals(self):
|
||||
handle_create_order(_default_order_args())
|
||||
customer = shopify_state.get_customer_by_id("gid://shopify/Customer/5001")
|
||||
assert customer is not None
|
||||
assert customer["ordersCount"] == 1
|
||||
assert float(customer["totalSpent"]["amount"]) == 100.0
|
||||
assert customer["pointsBalance"] == 95
|
||||
|
||||
def test_unknown_email_no_loyalty_effects(self):
|
||||
result = handle_create_order(_default_order_args(email="ghost@example.com"))
|
||||
order = result["order"]
|
||||
assert order["loyaltyPointsEarned"] == 0
|
||||
assert order["tierDiscount"] is None
|
||||
|
||||
def test_disabled_program_no_loyalty_effects(self):
|
||||
handle_configure_loyalty_program(ConfigureLoyaltyProgramArgs(enabled=False))
|
||||
result = handle_create_order(_default_order_args())
|
||||
order = result["order"]
|
||||
assert order["loyaltyPointsEarned"] == 0
|
||||
assert order["tierDiscount"] is None
|
||||
|
||||
|
||||
# ============================================
|
||||
# TIER-GATED DISCOUNT CODES
|
||||
# ============================================
|
||||
|
||||
|
||||
class TestTierGatedDiscountCodes:
|
||||
def test_create_code_with_minimum_tier(self):
|
||||
result = handle_create_discount_code(
|
||||
CreateDiscountCodeArgs(
|
||||
code="GOLD25",
|
||||
value="25",
|
||||
discount_type="PERCENTAGE",
|
||||
minimum_tier="Gold",
|
||||
)
|
||||
)
|
||||
assert result["userErrors"] == []
|
||||
assert result["discountCode"]["minimumTier"] == "Gold"
|
||||
|
||||
def test_update_clears_tier_restriction(self):
|
||||
handle_create_discount_code(
|
||||
CreateDiscountCodeArgs(code="TIERED", value="10", discount_type="PERCENTAGE", minimum_tier="Silver")
|
||||
)
|
||||
result = handle_update_discount_code(UpdateDiscountCodeArgs(code="TIERED", minimum_tier=""))
|
||||
assert result["discountCode"]["minimumTier"] is None
|
||||
|
||||
def test_order_with_qualified_customer_succeeds(self):
|
||||
handle_create_discount_code(
|
||||
CreateDiscountCodeArgs(code="SILVERONLY", value="15", discount_type="PERCENTAGE", minimum_tier="Silver")
|
||||
)
|
||||
# Award enough points to reach Silver (1000 lifetime)
|
||||
handle_award_points(AwardPointsArgs(customer_id="gid://shopify/Customer/5001", points=1200))
|
||||
|
||||
result = handle_create_order(_default_order_args(discount_code="SILVERONLY"))
|
||||
assert result["userErrors"] == []
|
||||
order = result["order"]
|
||||
assert order["discount"]["code"] == "SILVERONLY"
|
||||
assert order["discount"]["minimumTier"] == "Silver"
|
||||
|
||||
def test_order_with_underqualified_customer_rejected(self):
|
||||
handle_create_discount_code(
|
||||
CreateDiscountCodeArgs(code="GOLDONLY", value="20", discount_type="PERCENTAGE", minimum_tier="Gold")
|
||||
)
|
||||
# Customer is only Bronze (0 lifetime points)
|
||||
result = handle_create_order(_default_order_args(discount_code="GOLDONLY"))
|
||||
assert result["order"] is None
|
||||
assert any("Gold" in e["message"] for e in result["userErrors"])
|
||||
|
||||
def test_higher_tier_qualifies_for_lower_code(self):
|
||||
handle_create_discount_code(
|
||||
CreateDiscountCodeArgs(code="BRONZEANDUP", value="5", discount_type="PERCENTAGE", minimum_tier="Bronze")
|
||||
)
|
||||
# Customer reaches Gold (5000+ lifetime)
|
||||
handle_award_points(AwardPointsArgs(customer_id="gid://shopify/Customer/5001", points=6000))
|
||||
|
||||
result = handle_create_order(_default_order_args(discount_code="BRONZEANDUP"))
|
||||
assert result["userErrors"] == []
|
||||
|
||||
def test_anonymous_customer_rejected_by_tier_code(self):
|
||||
handle_create_discount_code(
|
||||
CreateDiscountCodeArgs(code="BRONZEUP", value="5", discount_type="PERCENTAGE", minimum_tier="Bronze")
|
||||
)
|
||||
# Use email that doesn't match any customer
|
||||
result = handle_create_order(_default_order_args(discount_code="BRONZEUP", email="ghost@example.com"))
|
||||
assert result["order"] is None
|
||||
assert any("Bronze" in e["message"] for e in result["userErrors"])
|
||||
|
||||
def test_unknown_tier_rejected(self):
|
||||
result = handle_create_discount_code(
|
||||
CreateDiscountCodeArgs(code="PLATONLY", value="30", discount_type="PERCENTAGE", minimum_tier="Platinum")
|
||||
)
|
||||
assert result["discountCode"] is None
|
||||
assert any("Platinum" in e["message"] for e in result["userErrors"])
|
||||
Reference in New Issue
Block a user