125 lines
4.0 KiB
Python
125 lines
4.0 KiB
Python
"""unit test: build_product_details thresholding, promo read, and combined_discount
|
|
|
|
run from the repo root:
|
|
uv run pytest tests/test_build_product_details.py
|
|
|
|
pure and offline — no Mongo. Builds a Product from a raw doc dict and checks the
|
|
discount threshold (with percentage codes compounding onto the sale price), the
|
|
promo fields read through via .get, and the combined_discount helper.
|
|
"""
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
from monitor_utils.runner import build_product_details, combined_discount
|
|
|
|
|
|
def _doc(**overrides) -> dict:
|
|
"""A well-formed product doc; override prices/promo per test."""
|
|
doc = {
|
|
"_id": "p1_tools",
|
|
"title": "Widget",
|
|
"url": "http://x/p1",
|
|
"currentPrice": 80.0,
|
|
"originalPrice": 100.0,
|
|
"imageUrl": "http://img/1",
|
|
"customizationIndex": None,
|
|
"memberNonMemberComparison": None,
|
|
"overstockText": None,
|
|
"discoveredDate": datetime(2026, 7, 26, tzinfo=timezone.utc),
|
|
"startDate": None,
|
|
"endDate": None,
|
|
"priceBeforeDrop": None,
|
|
"eduPrice": None,
|
|
"pastPrices": [
|
|
{"price": 80.0, "date": datetime(2026, 7, 26, tzinfo=timezone.utc)}
|
|
],
|
|
"available": True,
|
|
"condition": None,
|
|
"appExclusive": None,
|
|
"memberPick": None,
|
|
"memberDeal": None,
|
|
}
|
|
doc.update(overrides)
|
|
return doc
|
|
|
|
|
|
# ------------------------------------------------------------ combined_discount
|
|
|
|
|
|
def test_combined_discount_no_promo_is_base():
|
|
assert combined_discount(24, None) == 24
|
|
assert combined_discount(24, 0) == 24
|
|
|
|
|
|
def test_combined_discount_compounds_not_adds():
|
|
# 20% off then extra 30% code -> 44% off list (customer pays $56), not 50%
|
|
assert combined_discount(20, 30) == 44
|
|
|
|
|
|
def test_combined_discount_rounds_to_nearest():
|
|
# 24% sale + 22% code: 1 - .76*.78 = .4072 -> 41 (rounded, not truncated 40)
|
|
assert combined_discount(24, 22) == 41
|
|
|
|
|
|
# --------------------------------------------------------- build_product_details
|
|
|
|
|
|
def test_promo_fields_read_through():
|
|
doc = _doc(
|
|
promoCode="BIRTHDAY26",
|
|
promoPercentage=22,
|
|
promoDollarOff=None,
|
|
promoMinSpend=None,
|
|
)
|
|
product = build_product_details(doc, min_percentage=0)
|
|
assert product.metadata.promo_code == "BIRTHDAY26"
|
|
assert product.metadata.promo_percentage == 22
|
|
# base percentage is the raw price delta, unchanged by the code
|
|
assert product.metadata.percentage == 20
|
|
|
|
|
|
def test_missing_promo_keys_default_to_none():
|
|
"""a doc from a lagging monitor lacks promo keys -> None, not KeyError"""
|
|
product = build_product_details(_doc(), min_percentage=0)
|
|
assert product.metadata.promo_code is None
|
|
assert product.metadata.promo_percentage is None
|
|
|
|
|
|
def test_percentage_code_lifts_item_over_threshold():
|
|
# 30% base fails min 40, but +22% code -> 45% combined clears it
|
|
doc = _doc(currentPrice=70.0, originalPrice=100.0, promoPercentage=22)
|
|
assert build_product_details(doc, min_percentage=40) is not None
|
|
|
|
|
|
def test_below_threshold_without_code_is_skipped():
|
|
doc = _doc(currentPrice=70.0, originalPrice=100.0) # 30%, no code
|
|
assert build_product_details(doc, min_percentage=40) is None
|
|
|
|
|
|
def test_dollar_code_does_not_affect_threshold():
|
|
# a dollar code has no promoPercentage, so 30% base stays below min 40
|
|
doc = _doc(
|
|
currentPrice=70.0,
|
|
originalPrice=100.0,
|
|
promoCode="STORE22",
|
|
promoDollarOff=22,
|
|
promoMinSpend=100,
|
|
)
|
|
assert build_product_details(doc, min_percentage=40) is None
|
|
|
|
|
|
# ----------------------------------------------------------------- pastPrices
|
|
|
|
|
|
def test_past_prices_read_through():
|
|
"""Price history passes through unchanged."""
|
|
|
|
history = [
|
|
{"price": 95.0, "date": datetime(2026, 7, 20, tzinfo=timezone.utc)},
|
|
{"price": 90.0, "date": datetime(2026, 7, 24, tzinfo=timezone.utc)},
|
|
]
|
|
|
|
product = build_product_details(_doc(pastPrices=history), min_percentage=0)
|
|
|
|
assert product.pricing.past_prices == history
|