Files
ewoooc/tests/test_price_comparison_routes.py
ogt 2888bac597
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
fix: align pchome growth comparison and promo watch
2026-06-26 11:53:14 +08:00

251 lines
9.3 KiB
Python

from flask import Flask
def test_compare_prices_auto_fetches_targeted_momo_candidates_when_pchome_products_exist(monkeypatch):
from routes import price_comparison_routes as routes
captured = {}
def fake_targeted_search(pchome_products, **kwargs):
captured["targeted_momo_search"] = (pchome_products, kwargs)
return True, "ok", [
{
"name": "理膚寶水 B5 修復霜",
"price": 890,
"product_id": "12345678",
"product_url": "https://www.momoshop.com.tw/goods/GoodsDetail.jsp?i_code=12345678",
"can_auto_compare": True,
}
]
def fake_search_momo(keyword, limit=10):
captured["fallback_momo_search"] = (keyword, limit)
return True, "fallback", []
def fake_compare(brand, pchome_products, momo_products):
captured["compare"] = (brand, pchome_products, momo_products)
return {
"pchome_count": len(pchome_products),
"momo_count": len(momo_products),
"matched_count": 0,
"matches": [],
"stats": {},
}
monkeypatch.setattr(routes, "search_momo_products_for_pchome_products", fake_targeted_search)
monkeypatch.setattr(routes, "search_momo_products", fake_search_momo)
monkeypatch.setattr(routes, "compare_brand_prices", fake_compare)
app = Flask(__name__)
with app.test_request_context(
"/api/price_comparison/compare",
method="POST",
json={
"brand": "理膚寶水",
"pchome_products": [
{"name": "理膚寶水 B5 修復霜", "price": 900, "product_id": "PCHOME-1"},
],
},
):
response = routes.compare_prices.__wrapped__()
payload = response.get_json()
assert payload["success"] is True
assert payload["data"]["momo_count"] == 1
assert payload["data"]["momo_targeted_search"] == {
"message": "ok",
"candidate_count": 1,
"auto_compare_count": 1,
"exact_compare_count": 1,
"unit_compare_count": 0,
"review_count": 0,
}
assert captured["targeted_momo_search"][0][0]["name"] == "理膚寶水 B5 修復霜"
assert captured["targeted_momo_search"][1]["max_products"] == 30
assert "fallback_momo_search" not in captured
assert captured["compare"][0] == "理膚寶水"
assert captured["compare"][2][0]["product_id"] == "12345678"
def test_compare_prices_falls_back_to_brand_momo_search_without_pchome_products(monkeypatch):
from routes import price_comparison_routes as routes
captured = {}
def fake_search_momo(keyword, limit=10):
captured["momo_search"] = (keyword, limit)
return True, "ok", [
{"name": "理膚寶水 B5 修復霜", "price": 890, "product_id": "12345678"}
]
def fake_search_pchome(keyword, limit=100):
captured["pchome_search"] = (keyword, limit)
return True, "ok", []
def fake_compare(brand, pchome_products, momo_products):
captured["compare"] = (brand, pchome_products, momo_products)
return {
"pchome_count": len(pchome_products),
"momo_count": len(momo_products),
"matched_count": 0,
"matches": [],
"stats": {},
}
monkeypatch.setattr(routes, "search_pchome_products", fake_search_pchome)
monkeypatch.setattr(routes, "search_momo_products", fake_search_momo)
monkeypatch.setattr(routes, "compare_brand_prices", fake_compare)
app = Flask(__name__)
with app.test_request_context(
"/api/price_comparison/compare",
method="POST",
json={"brand": "理膚寶水"},
):
response = routes.compare_prices.__wrapped__()
payload = response.get_json()
assert payload["success"] is True
assert payload["data"]["momo_count"] == 1
assert captured["pchome_search"] == ("理膚寶水", 100)
assert captured["momo_search"] == ("理膚寶水", 100)
def test_fetch_momo_for_pchome_endpoint_splits_auto_and_review_candidates(monkeypatch):
from routes import price_comparison_routes as routes
def fake_targeted_search(pchome_products, **kwargs):
return True, "找到候選", [
{
"name": "可直接比價商品",
"price": 890,
"product_id": "AUTO-1",
"can_auto_compare": True,
},
{
"name": "組合需確認商品",
"price": 468,
"product_id": "UNIT-1",
"auto_compare_type": "unit_price",
"can_auto_compare": True,
"target_review_status": "自動單位價比較",
"target_unit_price_comparison": {
"comparable": True,
"unit_label": "ml",
"momo_unit_price": 11.7,
"competitor_unit_price": 23.0,
"unit_gap_pct": -49.13,
},
},
{
"name": "組合需確認商品",
"price": 468,
"product_id": "REVIEW-1",
"product_url": "https://www.momoshop.com.tw/goods/GoodsDetail.jsp?i_code=REVIEW-1",
"can_auto_compare": False,
"target_review_status": "需人工確認",
"target_pchome_product_id": "PCH-1",
"target_pchome_name": "PChome B5 修復霜",
"target_pchome_price": 920,
"target_match_score": 0.97,
"target_match_reasons": ["variant_selection_review"],
},
]
monkeypatch.setattr(routes, "search_momo_products_for_pchome_products", fake_targeted_search)
app = Flask(__name__)
with app.test_request_context(
"/api/price_comparison/fetch_momo_for_pchome",
method="POST",
json={
"pchome_products": [
{"name": "理膚寶水 B5 修復霜", "price": 920, "product_id": "PCH-1"},
],
},
):
response = routes.fetch_momo_for_pchome_products.__wrapped__()
payload = response.get_json()
assert payload["success"] is True
assert payload["message"] == "找到候選"
assert payload["data"]["count"] == 1
assert payload["data"]["exact_compare_count"] == 1
assert payload["data"]["unit_compare_count"] == 1
assert payload["data"]["auto_compare_count"] == 2
assert payload["data"]["review_count"] == 1
assert payload["data"]["candidate_count"] == 3
assert payload["data"]["products"][0]["product_id"] == "AUTO-1"
assert payload["data"]["unit_compare_candidates"][0]["product_id"] == "UNIT-1"
review_candidate = payload["data"]["review_candidates"][0]
assert review_candidate["product_id"] == "REVIEW-1"
assert review_candidate["target_pchome_product_id"] == "PCH-1"
assert review_candidate["target_pchome_name"] == "PChome B5 修復霜"
assert review_candidate["target_pchome_price"] == 920
assert review_candidate["target_pchome_url"] == "https://24h.pchome.com.tw/prod/PCH-1"
assert review_candidate["target_match_reason_labels"] == ["可信度 97%", "需確認色號"]
assert "target_match_reasons" not in review_candidate
assert payload["data"]["external_offer_sync"]["status"] == "not_requested"
def test_fetch_momo_for_pchome_endpoint_syncs_auto_candidates_when_requested(monkeypatch):
from routes import price_comparison_routes as routes
captured = {}
def fake_targeted_search(pchome_products, **kwargs):
return True, "找到候選", [
{
"name": "可直接比價商品",
"price": 890,
"product_id": "AUTO-1",
"auto_compare_type": "total_price",
"can_auto_compare": True,
},
{
"name": "自動單位價商品",
"price": 468,
"product_id": "UNIT-1",
"auto_compare_type": "unit_price",
"can_auto_compare": True,
},
{
"name": "需確認商品",
"price": 468,
"product_id": "REVIEW-1",
"can_auto_compare": False,
},
]
def fake_sync(candidates):
captured["sync_candidates"] = candidates
return {
"success": True,
"status": "synced",
"written_count": len(candidates),
"unit_price_count": 1,
"total_price_count": 1,
}
monkeypatch.setattr(routes, "search_momo_products_for_pchome_products", fake_targeted_search)
monkeypatch.setattr(routes, "_sync_targeted_candidates_to_external_offers", fake_sync)
app = Flask(__name__)
with app.test_request_context(
"/api/price_comparison/fetch_momo_for_pchome",
method="POST",
json={
"sync_external_offers": True,
"pchome_products": [
{"name": "理膚寶水 B5 修復霜", "price": 920, "product_id": "PCH-1"},
],
},
):
response = routes.fetch_momo_for_pchome_products.__wrapped__()
payload = response.get_json()
assert payload["success"] is True
assert payload["data"]["external_offer_sync"]["status"] == "synced"
assert payload["data"]["external_offer_sync"]["written_count"] == 2
assert [item["product_id"] for item in captured["sync_candidates"]] == ["AUTO-1", "UNIT-1"]