Files
surugaya/tests/test_other_shop_parser.py
T
2026-07-08 21:53:20 +08:00

140 lines
6.1 KiB
Python

"""SurugayaClient._parse_other_shop_list 的解析单元测试。
固定 HTML 节选自真实的 /product/other/{goods_id} 页面结构(tbl_all 标签页),
覆盖官方自营行(无 tenpo_cd/无评分)与加盟店/市场店铺行(含 tenpo_cd/评分)。
"""
from __future__ import annotations
from selectolax.parser import HTMLParser
from app.services.surugaya_client import SurugayaClient
OTHER_SHOP_HTML = """
<div class="tab-item" id="tabs-all">
<table id="tbl_all">
<tr class="thead"><th>头</th></tr>
<tr class="item">
<td><p><strong class="text-red text-bold mgnL10">1,370円</strong></p></td>
<td>
<a href="/product/detail/220035970?tenpo_cd=400451&branch_number=0003">
<h2 class="title_product">中古箱・ジャケット・ケース不備(中)</h2>
</a>
</td>
<td>
<div class="space_text_1 mgnB5"><strong><a href="/shop/400451">駿河屋 山口大学前店</a></strong></div>
<div class="star_group mgnB5"></div>
<div>5.0(1334件)</div>
</td>
<td>
<ul class="shipping_campaing_info">
<li class="padT5">1日〜3日以内に発送します</li>
<li class="all ajax-campaign-placeholder"
data-zaiko_data="{&quot;shinaban&quot;:&quot;220035970&quot;,&quot;branch_number&quot;:&quot;0003&quot;,&quot;tenpo_cd&quot;:&quot;400451&quot;,&quot;baika&quot;:&quot;1370&quot;}">
</li>
</ul>
</td>
</tr>
<tr class="item">
<td><p><strong class="text-red text-bold mgnL10">2,000円</strong></p></td>
<td>
<a href="/product/detail/220035970?branch_number=0001">
<h2 class="title_product">中古</h2>
</a>
</td>
<td>
<div><a href="/"><img src="/database/images/top-logo.png" class="w100"></a></div>
</td>
<td>
<ul class="shipping_campaing_info">
<li class="padT5">1日〜7日以内に発送します</li>
<li class="all ajax-campaign-placeholder"
data-zaiko_data="{&quot;shinaban&quot;:&quot;220035970&quot;,&quot;branch_number&quot;:&quot;0001&quot;,&quot;tenpo_cd&quot;:&quot;&quot;,&quot;baika&quot;:&quot;2000&quot;}">
</li>
</ul>
</td>
</tr>
<tr class="item">
<td><p><strong class="text-red text-bold mgnL10">2,744円</strong></p></td>
<td>
<a href="/product/detail/220035970?tenpo_cd=410118&branch_number=9001">
<h2 class="title_product">新品新古品(店頭在庫品) ※ショップ情報をご確認下さい</h2>
</a>
</td>
<td>
<div class="space_text_1 mgnB5"><strong><a href="/shop/410118">玉光堂 駿河屋マーケットプレイス店</a></strong></div>
<div class="star_group mgnB5"></div>
<div>5.0(46件)</div>
</td>
<td>
<ul class="shipping_campaing_info">
<li class="padT5">2日〜7日以内に発送します</li>
<li class="all ajax-campaign-placeholder"
data-zaiko_data="{&quot;shinaban&quot;:&quot;220035970&quot;,&quot;branch_number&quot;:&quot;9001&quot;,&quot;tenpo_cd&quot;:&quot;410118&quot;,&quot;baika&quot;:&quot;2744&quot;}">
</li>
</ul>
</td>
</tr>
</table>
</div>
"""
def test_parse_other_shop_list_extracts_all_rows() -> None:
"""三行分别为:加盟店、官方自营、市场店铺,均应被正确解析。"""
tree = HTMLParser(OTHER_SHOP_HTML)
items = SurugayaClient._parse_other_shop_list(tree)
assert len(items) == 3
def test_parse_other_shop_list_franchise_row() -> None:
"""加盟店行:tenpo_cd/店名/评分/价格/发货时效均应正确填充。"""
tree = HTMLParser(OTHER_SHOP_HTML)
item = SurugayaClient._parse_other_shop_list(tree)[0]
assert item.tenpo_cd == "400451"
assert item.is_official is False
assert item.shop_name == "駿河屋 山口大学前店"
assert item.shop_url == "https://www.suruga-ya.jp/shop/400451"
assert item.price == 1370
assert item.condition == "中古箱・ジャケット・ケース不備(中)"
assert item.branch_number == "0003"
assert item.rating_score == "5.0"
assert item.rating_count == 1334
assert item.shipping_note == "1日〜3日以内に発送します"
assert item.detail_url == (
"https://www.suruga-ya.jp/product/detail/220035970?tenpo_cd=400451&branch_number=0003"
)
def test_parse_other_shop_list_official_row_has_no_tenpo_cd() -> None:
"""官方自营行:无 /shop/ 链接、tenpo_cd 为空、is_official 应为 True,且无评分。"""
tree = HTMLParser(OTHER_SHOP_HTML)
item = SurugayaClient._parse_other_shop_list(tree)[1]
assert item.tenpo_cd == ""
assert item.is_official is True
assert item.shop_name == "駿河屋"
assert item.price == 2000
assert item.rating_score == ""
assert item.rating_count == 0
def test_parse_other_shop_list_marketplace_row() -> None:
"""市场店铺行:与加盟店行结构一致,同样应正确解析。"""
tree = HTMLParser(OTHER_SHOP_HTML)
item = SurugayaClient._parse_other_shop_list(tree)[2]
assert item.tenpo_cd == "410118"
assert item.is_official is False
assert item.shop_name == "玉光堂 駿河屋マーケットプレイス店"
assert item.price == 2744
assert item.rating_score == "5.0"
assert item.rating_count == 46
def test_parse_other_shop_list_empty_html_returns_empty_list() -> None:
"""页面结构不包含 tbl_all 时(如解析失败/改版),应返回空列表而非抛异常。"""
tree = HTMLParser("<html><body>no table here</body></html>")
assert SurugayaClient._parse_other_shop_list(tree) == []