mirror of
https://github.com/HKUDS/CLI-Anything.git
synced 2026-07-03 13:02:27 +08:00
fix: address Web Yu-pri review feedback
This commit is contained in:
@@ -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"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.")
|
||||
|
||||
Reference in New Issue
Block a user