251 lines
9.3 KiB
Python
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"]
|