Files
surugaya/tests/test_surugaya_client_shops.py
T
q792602257 118667d01f 下单接口支持其他店铺
/api/order/get_shipping_fee 与购物车加入逻辑此前只认官方自营详情页,加盟店运费分桶
仅靠自由文本 supplier 判断,未与其他店铺列表的 tenpo_cd 打通。补充 OrderItem/
CargoItemRequest 的 tenpo_cd/branch_number 字段,运费计算优先按 tenpo_cd 分桶
(无则回退 supplier 保持兼容),cargo_service 加购 URL 同步带上店铺参数。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-08 22:31:03 +08:00

112 lines
4.1 KiB
Python

"""SurugayaClient 中「指定店铺」相关能力的单元测试:
- _build_product_url 携带 tenpo_cd/branch_number 构造跳转到指定店铺报价的详情页 URL
- fetch_other_shops 独立于 fetch_detail,仅返回 other_shop_list(解耦双倍抓取成本)
"""
from __future__ import annotations
import pytest
from app.core.config import Settings
from app.models.scrape import DetailRequest, OtherShopItem
from app.services.surugaya_client import SurugayaClient
def _make_client() -> SurugayaClient:
return SurugayaClient(
settings=Settings(_env_file=None),
browser_pool=None,
session_manager=None,
session_store=None,
)
class TestBuildProductUrl:
def test_without_shop_params(self) -> None:
client = _make_client()
assert client._build_product_url("220035970") == "https://www.suruga-ya.jp/product/detail/220035970"
def test_with_tenpo_cd_and_branch_number(self) -> None:
client = _make_client()
url = client._build_product_url("220035970", tenpo_cd="400451", branch_number="0003")
assert url == "https://www.suruga-ya.jp/product/detail/220035970?tenpo_cd=400451&branch_number=0003"
def test_missing_product_id_raises(self) -> None:
client = _make_client()
with pytest.raises(Exception):
client._build_product_url(None)
class TestFetchOtherShops:
@pytest.mark.asyncio
async def test_returns_goods_id_and_shop_list(self, monkeypatch: pytest.MonkeyPatch) -> None:
client = _make_client()
fake_items = [OtherShopItem(tenpo_cd="400451", shop_name="駿河屋 山口大学前店", price=1370)]
async def fake_fetch_other_shop_list(goods_id: str) -> list[OtherShopItem]:
assert goods_id == "220035970"
return fake_items
monkeypatch.setattr(client, "_fetch_other_shop_list", fake_fetch_other_shop_list)
result = await client.fetch_other_shops(DetailRequest(id="220035970"))
assert result.goods_id == "220035970"
assert result.other_shop_list == fake_items
@pytest.mark.asyncio
async def test_empty_id_raises(self) -> None:
client = _make_client()
with pytest.raises(Exception):
await client.fetch_other_shops(DetailRequest(id=None))
class TestFetchDetailIncludeOtherShops:
"""DetailRequest.include_other_shops 控制 fetch_detail 是否顺带抓取 other_shop_list。"""
MINIMAL_DETAIL_HTML = '<html><body><h1 id="item_title">测试商品</h1></body></html>'
@pytest.mark.asyncio
async def test_flag_false_skips_other_shop_fetch(self, monkeypatch: pytest.MonkeyPatch) -> None:
client = _make_client()
monkeypatch.setattr(client, "_session_manager", _FakeSessionManager(self.MINIMAL_DETAIL_HTML))
called = False
async def fake_fetch_other_shop_list(goods_id: str) -> list[OtherShopItem]:
nonlocal called
called = True
return []
monkeypatch.setattr(client, "_fetch_other_shop_list", fake_fetch_other_shop_list)
detail = await client.fetch_detail(DetailRequest(id="220035970"))
assert called is False
assert detail.other_shop_list == []
@pytest.mark.asyncio
async def test_flag_true_includes_other_shop_list(self, monkeypatch: pytest.MonkeyPatch) -> None:
client = _make_client()
monkeypatch.setattr(client, "_session_manager", _FakeSessionManager(self.MINIMAL_DETAIL_HTML))
fake_items = [OtherShopItem(tenpo_cd="400451", shop_name="駿河屋 山口大学前店", price=1370)]
async def fake_fetch_other_shop_list(goods_id: str) -> list[OtherShopItem]:
assert goods_id == "220035970"
return fake_items
monkeypatch.setattr(client, "_fetch_other_shop_list", fake_fetch_other_shop_list)
detail = await client.fetch_detail(DetailRequest(id="220035970", include_other_shops=True))
assert detail.other_shop_list == fake_items
class _FakeSessionManager:
def __init__(self, html: str) -> None:
self._html = html
async def fetch_html(self, url: str):
return self._html, None