fix: address Web Yu-pri review feedback

This commit is contained in:
Codex
2026-06-09 10:15:13 +09:00
parent 0ac0342369
commit 76ddd41735
4 changed files with 53 additions and 13 deletions

View File

@@ -152,8 +152,8 @@
"category": "web",
"contributors": [
{
"name": "CLI-Anything-Team",
"url": "https://github.com/HKUDS/CLI-Anything"
"name": "shinpei710",
"url": "https://github.com/shinpei710"
}
]
},

View File

@@ -2,7 +2,7 @@
## Test Inventory Plan
- `test_core.py`: 12 unit/CLI smoke tests planned.
- `test_core.py`: 15 unit/CLI smoke tests planned.
- `test_full_e2e.py`: 2 E2E tests planned.
## Unit Test Plan
@@ -57,7 +57,7 @@ python -m pytest cli_anything/web_yu_pri/tests -v
Result:
```text
collected 14 items
collected 17 items
cli_anything/web_yu_pri/tests/test_core.py::test_parse_item_mapping_aliases PASSED
cli_anything/web_yu_pri/tests/test_core.py::test_parse_item_rejects_bad_country PASSED
@@ -70,11 +70,14 @@ cli_anything/web_yu_pri/tests/test_core.py::test_selector_report_contains_conten
cli_anything/web_yu_pri/tests/test_core.py::test_build_dry_run_has_safety_metadata PASSED
cli_anything/web_yu_pri/tests/test_core.py::test_cli_help PASSED
cli_anything/web_yu_pri/tests/test_core.py::test_cli_plan_json PASSED
cli_anything/web_yu_pri/tests/test_core.py::test_cli_plan_missing_file_json PASSED
cli_anything/web_yu_pri/tests/test_core.py::test_cli_contents_fill_dry_run_json PASSED
cli_anything/web_yu_pri/tests/test_core.py::test_cli_contents_fill_missing_file_json PASSED
cli_anything/web_yu_pri/tests/test_core.py::test_cli_open_login_json_defaults_to_no_wait PASSED
cli_anything/web_yu_pri/tests/test_full_e2e.py::test_dry_run_cli_workflow PASSED
cli_anything/web_yu_pri/tests/test_full_e2e.py::test_live_status_against_contents_page SKIPPED
13 passed, 1 skipped
16 passed, 1 skipped
```
Additional checks:

View File

@@ -1,6 +1,7 @@
"""Core tests for cli-anything-web-yu-pri."""
import json
from unittest.mock import patch
from click.testing import CliRunner
import pytest
@@ -115,6 +116,16 @@ def test_cli_plan_json(tmp_path):
assert data["computed_total"] == 100
def test_cli_plan_missing_file_json(tmp_path):
missing = tmp_path / "missing.json"
result = CliRunner().invoke(cli, ["--json", "plan", str(missing)])
assert result.exit_code == 1
assert "Usage:" not in result.output
data = json.loads(result.output)
assert data["type"] == "FileNotFoundError"
assert "items file not found" in data["error"]
def test_cli_contents_fill_dry_run_json(tmp_path):
path = tmp_path / "items.json"
path.write_text(json.dumps([{"description": "A", "value": 100}]), encoding="utf-8")
@@ -123,3 +134,25 @@ def test_cli_contents_fill_dry_run_json(tmp_path):
data = json.loads(result.output)
assert data["dry_run"] is True
assert data["plan"]["declared_total"] == 100
def test_cli_contents_fill_missing_file_json(tmp_path):
missing = tmp_path / "missing.json"
result = CliRunner().invoke(cli, ["--json", "contents", "fill", str(missing), "--dry-run"])
assert result.exit_code == 1
assert "Usage:" not in result.output
data = json.loads(result.output)
assert data["type"] == "FileNotFoundError"
assert "items file not found" in data["error"]
def test_cli_open_login_json_defaults_to_no_wait():
fake_info = {"url": "https://mgr.post.japanpost.jp/C30P01Action.do", "title": "Web Yu-pri"}
with patch("cli_anything.web_yu_pri.web_yu_pri_cli.open_login", return_value=fake_info) as open_mock, \
patch("cli_anything.web_yu_pri.web_yu_pri_cli._interactive_session") as interactive_mock:
result = CliRunner().invoke(cli, ["--json", "open-login"])
assert result.exit_code == 0
assert json.loads(result.output) == fake_info
open_mock.assert_called_once()
interactive_mock.assert_not_called()

View File

@@ -6,6 +6,7 @@ from __future__ import annotations
import json
import shlex
from contextlib import contextmanager
from pathlib import Path
from typing import Any
import click
@@ -79,7 +80,10 @@ def _load_plan(
total_value: int | None,
value_mode: str,
) -> tuple[list[Any], dict[str, Any]]:
items = load_items(items_file, default_country=default_country)
path = Path(items_file).expanduser()
if not path.is_file():
raise FileNotFoundError(f"items file not found: {items_file}")
items = load_items(path, default_country=default_country)
plan = build_contents_plan(items, total_value=total_value, value_mode=value_mode)
return items, plan
@@ -126,7 +130,7 @@ def selectors_cmd() -> None:
@cli.command("plan")
@click.argument("items_file", type=click.Path(exists=True, dir_okay=False, path_type=str))
@click.argument("items_file", type=str)
@click.option("--country-default", default=None, help="Default ISO country code for rows without one.")
@click.option("--total-value", type=int, default=None, help="Override the declared total value in yen.")
@click.option(
@@ -152,15 +156,15 @@ def plan_cmd(items_file: str, country_default: str | None, total_value: int | No
@click.option("--browser-channel", default=None, help="Playwright channel, for example msedge or chrome.")
@click.option(
"--wait/--no-wait",
default=True,
show_default=True,
help="Keep the browser open until Enter is pressed.",
default=None,
help="Keep the browser open until Enter is pressed. Defaults to on for human output and off for --json.",
)
def open_login_cmd(url: str, headless: bool, browser_channel: str | None, wait: bool) -> None:
def open_login_cmd(url: str, headless: bool, browser_channel: str | None, wait: bool | None) -> None:
"""Open the Web Yu-pri login/start page in the persistent profile."""
try:
if wait:
should_wait = (not _json_output) if wait is None else wait
if should_wait:
with _interactive_session(url, headless=headless, browser_channel=browser_channel) as info:
emit(info, "Opened Web Yu-pri login page.")
if not _json_output:
@@ -234,7 +238,7 @@ def contents() -> None:
@contents.command("fill")
@click.argument("items_file", type=click.Path(exists=True, dir_okay=False, path_type=str))
@click.argument("items_file", type=str)
@click.option("--url", default=CONTENTS_URL, show_default=True, help="Contents form URL.")
@click.option("--country-default", default=None, help="Default ISO country code for rows without one.")
@click.option("--total-value", type=int, default=None, help="Override the declared total value in yen.")