chore: [workflow] 提交工作区改动

This commit is contained in:
2026-09-07 15:14:54 +08:00
parent 485e77ee74
commit 2ff588a65d
27 changed files with 373 additions and 138 deletions
@@ -32,6 +32,45 @@ def test_buyin_source_uses_doudian_market_and_cookie_scope():
assert xingtu.BUSINESS_COOKIE_DOMAINS == ("jinritemai.com",)
def test_buyin_search_stays_on_market_route_instead_of_clicking_global_nav():
xingtu.configure_source("buyin")
events = []
class Locator:
def __init__(self, count):
self._count = count
self.first = self
def count(self):
return self._count
def wait_for(self, **kwargs):
events.append(("wait", kwargs))
class Page:
url = "https://www.douyinec.com/"
def locator(self, selector):
events.append(("locator", selector))
return Locator(0)
def goto(self, url, **kwargs):
events.append(("goto", url, kwargs))
def get_by_text(self, *_args, **_kwargs):
raise AssertionError("Buyin must not click the global 找达人 navigation")
xingtu.select_nickname_search(Page())
assert events[0] == (
"locator",
f"{xingtu.BUYIN_SEARCH_INPUT_SELECTOR}:visible",
)
assert events[1][0] == "goto"
assert events[1][1] == xingtu.MARKET_URL
assert events[2][0] == "wait"
def test_save_state_creates_cookie_parent_directory(tmp_path, monkeypatch):
cookie_file = tmp_path / "nested" / "cookies.json"
monkeypatch.setattr(xingtu, "DATA_DIR", tmp_path / "raw")
@@ -36,13 +36,29 @@ def test_style_plan_rejects_one_erp_code_owned_by_two_styles() -> None:
backfill.build_style_plans(
{
"styles": {
"款式甲": {"erp_codes": ["10416"]},
"款式乙": {"erp_codes": ["10416"]},
"款式甲": {"erp_codes": ["10416"], "tm": {"item_ids": ["tm-1"]}},
"款式乙": {"erp_codes": ["10416"], "tm": {"item_ids": ["tm-2"]}},
}
}
)
def test_style_plan_skips_erp_only_style_until_product_id_is_added() -> None:
plans = backfill.build_style_plans(
{
"styles": {
"研发款": {"erp_codes": ["ERP-ONLY"]},
"已上架款": {
"erp_codes": ["ERP-READY"],
"jd": {"spus": ["JD-1"]},
},
}
}
)
assert plans == (backfill.StylePlan("已上架款", ("ERP-READY",)),)
def test_all_shop_filter_selects_every_shop_and_batches_all_codes() -> None:
class Frame:
def __init__(self) -> None:
@@ -210,8 +210,11 @@ def test_erp_style_plan_uses_style_base_codes_and_aliases() -> None:
ProductTarget("云栖相机双肩包", 200),
]
styles = {
"盖世m1": {"erp_codes": ["10416", "10455", "10416"]},
"星迹2": {"erp_codes": ["10504", "10394"]},
"盖世m1": {
"erp_codes": ["10416", "10455", "10416"],
"tm": {"item_ids": ["tm-1"]},
},
"星迹2": {"erp_codes": ["10504", "10394"], "tm": {"item_ids": ["tm-2"]}},
"云栖": {"erp_codes": []},
}
@@ -321,6 +321,83 @@ def test_upload_template_supports_tmall_dialog_import_button(
assert chooser.files == str(template)
class _AnnouncementDialog:
def __init__(self) -> None:
self.dismiss = _LoginLocator()
def is_visible(self) -> bool:
return True
def inner_text(self, **_kwargs) -> str:
return "公告 26年天猫活动通知"
def count(self) -> int:
return 1
def nth(self, _index: int):
return self
def get_by_role(self, role: str, *, name: str, exact: bool):
if role == "button" and name == "我已阅读完成" and exact:
return self.dismiss
return _LoginLocator(visible=False)
def get_by_text(self, _label: str, *, exact: bool):
return _LoginLocator(visible=False)
def locator(self, _selector: str):
return _LoginLocator(visible=False)
class _AnnouncementPage:
frames: list[object] = []
def __init__(self) -> None:
self.dialog = _AnnouncementDialog()
def get_by_role(self, role: str, **_kwargs):
if role == "dialog":
return self.dialog
return _LoginLocator(visible=False)
def test_dismiss_blocking_announcements_closes_only_announcement_dialog() -> None:
page = _AnnouncementPage()
assert baibu._dismiss_blocking_announcements(page) is True
assert page.dialog.dismiss.click_count == 1
def test_open_batch_import_dismisses_announcement_before_click(monkeypatch) -> None:
events: list[str] = []
page = SimpleNamespace()
monkeypatch.setattr(
baibu,
"_page_text",
lambda _page: (
"您于2026-09-03 15:00:51执行了商品批量导入操作,"
"总数量2件,已成功2件,失败0件,待查看0件。"
),
)
monkeypatch.setattr(baibu.time, "sleep", lambda _seconds: None)
monkeypatch.setattr(
baibu,
"_dismiss_blocking_announcements",
lambda _page: events.append("dismiss") or True,
)
monkeypatch.setattr(
baibu,
"_click_text",
lambda _page, _labels: events.append("click") or True,
)
baibu._open_batch_import(page, _entry())
assert events[:2] == ["dismiss", "dismiss"]
assert events[2:] == ["click"]
def test_open_batch_import_refuses_an_active_previous_operation(monkeypatch) -> None:
page = SimpleNamespace()
monkeypatch.setattr(
@@ -538,6 +615,33 @@ def test_return_to_draft_list_falls_back_to_browser_history(monkeypatch) -> None
assert events == ["draft", "back"]
def test_return_to_draft_list_closes_editor_before_clicking_draft_tab(
monkeypatch,
) -> None:
events: list[str] = []
monkeypatch.setattr(
baibu,
"_close_editor",
lambda _page: events.append("close") or True,
)
monkeypatch.setattr(
baibu,
"_draft_list_is_ready",
lambda _page: events.append("ready") or True,
)
monkeypatch.setattr(
baibu,
"_click_draft_tab",
lambda _page: pytest.fail("关闭编辑器后列表已就绪时不得重复点草稿"),
)
monkeypatch.setattr(baibu.time, "sleep", lambda _seconds: None)
baibu._return_to_draft_list(SimpleNamespace(), _entry())
assert events == ["close", "ready"]
def test_tmall_config_enables_draft_completion_for_only_old_all_3c() -> None:
old_all_3c = baibu._load_entry("old_all_3c")
old_all_bag = baibu._load_entry("old_all_bag")