Files
Tirsvad 34e70b31dc MIL-005 live Amazon page (Step 4)
Delivers MIL-005 (lecture Step 4): the product URL comes from `PRODUCT_URL` (default: the lecture's Amazon page), price and title selectors and robot-check markers live in `constants.py`, and a robot-check page raises `RobotCheckError` with a clear message. The code does not try to solve or bypass the check.

Outcome on the live page (2026-10-28): Amazon returned HTTP 200 with a robot-check page and no price; the page is kept (tokens redacted) as a test fixture and shown in the README. Two live requests were made in total, one to inspect the response and one for the screenshot; there are no retries or loops.

Review: code against QC-PY-001 as RC-014 (Go, autonomous, not independent). 56 pytest tests (no network), ruff and mypy --strict pass.

Task: MIL-005#1
Task: MIL-005#2
Task: MIL-005#3
Task: MIL-005#4
Task: MIL-005#5
2026-10-28 14:48:21 +08:00

85 lines
2.6 KiB
Python

import pytest
from amazon_price_tracker.constants import (
AMAZON_URL,
ENV_EMAIL_ADDRESS,
ENV_EMAIL_PASSWORD,
ENV_PRODUCT_URL,
ENV_SMTP_ADDRESS,
PRACTICE_URL,
)
from amazon_price_tracker.domain.errors import InvalidSettingError, MissingSettingError
from amazon_price_tracker.infrastructure.settings import (
load_mail_settings,
load_product_url,
)
FULL = {
ENV_SMTP_ADDRESS: "smtp.example.test",
ENV_EMAIL_ADDRESS: "me@example.test",
ENV_EMAIL_PASSWORD: "s3cret-pw",
}
def test_load_mail_settings_reads_all_values() -> None:
settings = load_mail_settings(FULL)
assert settings.smtp_address == "smtp.example.test"
assert settings.email_address == "me@example.test"
assert settings.email_password == "s3cret-pw"
@pytest.mark.parametrize(
"name", [ENV_SMTP_ADDRESS, ENV_EMAIL_ADDRESS, ENV_EMAIL_PASSWORD]
)
def test_load_mail_settings_raises_naming_missing_variable(name: str) -> None:
environ = {key: value for key, value in FULL.items() if key != name}
with pytest.raises(MissingSettingError, match=name):
load_mail_settings(environ)
def test_load_mail_settings_raises_on_empty_value() -> None:
with pytest.raises(MissingSettingError, match=ENV_EMAIL_ADDRESS):
load_mail_settings({**FULL, ENV_EMAIL_ADDRESS: ""})
def test_load_mail_settings_names_first_missing_variable() -> None:
with pytest.raises(MissingSettingError, match=ENV_SMTP_ADDRESS):
load_mail_settings({})
def test_load_product_url_defaults_to_amazon() -> None:
assert load_product_url({}) == AMAZON_URL
def test_load_product_url_defaults_when_blank() -> None:
assert load_product_url({ENV_PRODUCT_URL: " "}) == AMAZON_URL
def test_load_product_url_uses_override() -> None:
assert load_product_url({ENV_PRODUCT_URL: PRACTICE_URL}) == PRACTICE_URL
def test_load_product_url_strips_whitespace() -> None:
assert load_product_url({ENV_PRODUCT_URL: f" {PRACTICE_URL}\n"}) == PRACTICE_URL
@pytest.mark.parametrize("value", ["http://example.test/", "ftp://x", "example.test"])
def test_load_product_url_rejects_non_https(value: str) -> None:
with pytest.raises(InvalidSettingError, match=ENV_PRODUCT_URL) as info:
load_product_url({ENV_PRODUCT_URL: value})
assert value not in str(info.value)
def test_mail_settings_repr_hides_password() -> None:
assert "s3cret-pw" not in repr(load_mail_settings(FULL))
def test_missing_setting_error_does_not_contain_password() -> None:
with pytest.raises(MissingSettingError) as info:
load_mail_settings({**FULL, ENV_SMTP_ADDRESS: ""})
assert "s3cret-pw" not in str(info.value)