from services import webcrumbs_host_data_service as svc def test_webcrumbs_host_data_maps_price_alert_exact_rows(monkeypatch): engine = object() monkeypatch.setattr( svc, "fetch_top_competitor_risks", lambda passed_engine, limit: [ { "sku": "SKU-REVIEW", "name": "需人工覆核的非直接告警候選", "momo_price": 999, "pchome_price": 500, "gap_pct": 99.8, "match_score": 0.95, "alert_tier": "identity_review", "match_type": "exact", "price_basis": "total_price", }, { "sku": "SKU-1", "name": "Derma Angel 護妍天使 集中抗痘精華", "momo_price": 420, "pchome_price": 250, "gap_pct": 68.0, "match_score": 0.91, "alert_tier": "price_alert_exact", "match_type": "exact", "price_basis": "total_price", "pchome_id": "DABC123", "pchome_name": "Derma Angel 集中抗痘精華", "crawled_at": "05/31 20:50", } ], ) monkeypatch.setattr( svc, "fetch_competitor_coverage", lambda passed_engine: {"valid_matches": 88, "match_rate": 12.3}, ) payload = svc.build_webcrumbs_marketplace_host_data(engine=engine, limit=5) assert payload["marketSnapshot"][0]["name"].startswith("SKU-1") assert payload["marketSnapshot"][0]["price"] == 250 assert payload["marketSnapshot"][0]["change_pct"] == 68.0 assert payload["aiCandidate"]["ticker"] == "SKU-1" assert payload["aiCandidate"]["confidence_score"] == 0.91 assert "MOMO NT$420 vs PChome NT$250" in payload["aiCandidate"]["thesis"] assert payload["aiCandidate"]["release_status"] == "review_required" assert payload["metadata"]["writes_database"] is False assert payload["metadata"]["calls_llm"] is False assert payload["metadata"]["fetches_external"] is False assert all(row["freshness_status"] == "price_alert_exact" for row in payload["marketSnapshot"]) def test_webcrumbs_host_data_uses_empty_state_without_risks(monkeypatch): monkeypatch.setattr(svc, "fetch_top_competitor_risks", lambda engine, limit: []) monkeypatch.setattr(svc, "fetch_competitor_coverage", lambda engine: {"valid_matches": 0}) payload = svc.build_webcrumbs_marketplace_host_data(engine=object(), limit=5) assert payload["marketSnapshot"][0]["freshness_status"] == "no_current_exact_risk" assert payload["aiCandidate"]["release_status"] == "blocked" assert "非同款、單位價或變體候選" in payload["aiCandidate"]["thesis"] def test_webcrumbs_seed_data_fallback_does_not_expose_demo_values(monkeypatch): from services import external_tool_payload_service as payload_service def boom(limit): raise RuntimeError("db unavailable") monkeypatch.setattr(payload_service, "build_webcrumbs_marketplace_host_data", boom) payload = payload_service.build_webcrumbs_seed_data(limit=5) assert payload["marketSnapshot"][0]["freshness_status"] == "diagnostic_unavailable" assert payload["aiCandidate"]["release_status"] == "blocked" assert "fallback demo" in payload["aiCandidate"]["thesis"] assert "TAIEX" not in str(payload) def test_webcrumbs_auth_required_seed_data_is_non_sensitive(): from services.external_tool_payload_service import build_webcrumbs_auth_required_seed_data payload = build_webcrumbs_auth_required_seed_data() assert payload["marketSnapshot"][0]["freshness_status"] == "auth_required" assert payload["aiCandidate"]["release_status"] == "blocked" assert payload["metadata"]["source"] == "auth_required" assert "MOMO NT$" not in str(payload) assert "PChome NT$" not in str(payload)