Files
Tirsvad e764269eda Implement the Selenium lecture steps with tests and screenshots (MIL-002)
Driver factory, click_link_by_text, search_for, fill_out_form, run_lecture
and CLI, layered as domain, application, infrastructure and presentation.
30 offline unit tests, a form fixture, a Docker image for headless runs and
four screenshots captured in Docker. Reviews RC-009 (code) and RC-010
(milestone wording of the screenshot criterion).

Task: MIL-002#1
2026-10-28 16:22:41 +08:00

112 lines
3.1 KiB
Python

from pathlib import Path
from typing import Any
import pytest
from fill_out_form import constants
from fill_out_form.application.ports import BrowserPort
from fill_out_form.domain.form_data import FormData, default_form_data
from fill_out_form.presentation import cli
from tests.unit.fakes import FakeBrowser
def test_parser_defaults() -> None:
args = cli.build_parser().parse_args([])
assert args.headless is False
assert args.screenshots is None
assert args.form_url == constants.FORM_URL
def test_parser_reads_all_options() -> None:
args = cli.build_parser().parse_args(
["--headless", "--screenshots", "out", "--form-url", "http://x/"]
)
assert args.headless is True
assert args.screenshots == Path("out")
assert args.form_url == "http://x/"
def test_main_runs_lecture_and_quits(monkeypatch: pytest.MonkeyPatch) -> None:
browser = FakeBrowser()
created: list[bool] = []
calls: list[dict[str, Any]] = []
def fake_create(headless: bool = False) -> FakeBrowser:
created.append(headless)
return browser
def fake_run(b: BrowserPort, **kwargs: Any) -> None:
calls.append({"browser": b, **kwargs})
monkeypatch.setattr(cli, "create_driver", fake_create)
monkeypatch.setattr(cli, "run_lecture", fake_run)
code = cli.main(["--headless", "--screenshots", "shots"])
assert code == 0
assert created == [True]
assert calls == [
{
"browser": browser,
"form_url": constants.FORM_URL,
"screenshot_dir": Path("shots"),
"form_data": default_form_data(),
}
]
assert ("quit",) in browser.events
def test_parser_form_data_defaults_come_from_constants() -> None:
args = cli.build_parser().parse_args([])
assert FormData(args.first_name, args.last_name, args.email) == (
default_form_data()
)
def test_parser_reads_form_data_options() -> None:
args = cli.build_parser().parse_args(
["--first-name", "Ada", "--last-name", "Lovelace", "--email", "a@example.test"]
)
assert (args.first_name, args.last_name, args.email) == (
"Ada",
"Lovelace",
"a@example.test",
)
def test_main_forwards_form_data_to_run_lecture(
monkeypatch: pytest.MonkeyPatch,
) -> None:
received: list[FormData | None] = []
def fake_run(b: BrowserPort, **kwargs: Any) -> None:
received.append(kwargs["form_data"])
monkeypatch.setattr(cli, "create_driver", lambda headless=False: FakeBrowser())
monkeypatch.setattr(cli, "run_lecture", fake_run)
cli.main(["--first-name", "Ada", "--last-name", "L", "--email", "a@example.test"])
assert received == [FormData("Ada", "L", "a@example.test")]
def test_main_quits_browser_when_lecture_fails(
monkeypatch: pytest.MonkeyPatch,
) -> None:
browser = FakeBrowser()
def failing_run(b: BrowserPort, **kwargs: Any) -> None:
raise RuntimeError("boom")
monkeypatch.setattr(cli, "create_driver", lambda headless=False: browser)
monkeypatch.setattr(cli, "run_lecture", failing_run)
with pytest.raises(RuntimeError, match="boom"):
cli.main([])
assert ("quit",) in browser.events