mirror of
https://github.com/Sea-Haven-Industries/meal-order-manager.git
synced 2026-10-03 20:03:16 +00:00
fix(cart): account for a closed window and an empty menu
A closed page during add marks the remaining meals as not attempted, and an empty menu catalog raises the same error as the menu parser.
This commit is contained in:
parent
9462ce0966
commit
ddf150f428
4 changed files with 63 additions and 21 deletions
|
|
@ -145,7 +145,8 @@ def _fill_page(page, plan: FillPlan, menu_url: str) -> int:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
posted = []
|
posted = []
|
||||||
for item in plan.adds:
|
page_closed = False
|
||||||
|
for index, item in enumerate(plan.adds):
|
||||||
try:
|
try:
|
||||||
_cart_request(
|
_cart_request(
|
||||||
page,
|
page,
|
||||||
|
|
@ -161,27 +162,37 @@ def _fill_page(page, plan: FillPlan, menu_url: str) -> int:
|
||||||
failed.append(f"{item.name}: {exc}")
|
failed.append(f"{item.name}: {exc}")
|
||||||
print(f"Failed: {item.name}: {exc}")
|
print(f"Failed: {item.name}: {exc}")
|
||||||
continue
|
continue
|
||||||
posted.append(item)
|
except PlaywrightError as exc:
|
||||||
|
failed.append(f"{item.name}: {exc}")
|
||||||
try:
|
print(f"Failed: {item.name}: {exc}")
|
||||||
current = cart_lines(_cart_request(page, "GET", "/api/cart"))
|
for rest in plan.adds[index + 1 :]:
|
||||||
except RuntimeError as exc:
|
message = f"{rest.name}: not attempted"
|
||||||
failed.append(f"Could not read the cart: {exc}")
|
|
||||||
print(f"Failed: Could not read the cart: {exc}")
|
|
||||||
else:
|
|
||||||
for item in posted:
|
|
||||||
found = quantity_for(current, item.uuid)
|
|
||||||
if found != item.quantity:
|
|
||||||
message = (
|
|
||||||
f"{item.name}: requested {item.quantity}, cart has {found}"
|
|
||||||
)
|
|
||||||
failed.append(message)
|
failed.append(message)
|
||||||
print(f"Failed: {message}")
|
print(f"Failed: {message}")
|
||||||
else:
|
page_closed = True
|
||||||
added += 1
|
break
|
||||||
origin = _origin(page.url or menu_url)
|
posted.append(item)
|
||||||
page.goto(f"{origin}/cart", wait_until="domcontentloaded", timeout=60000)
|
|
||||||
ready = True
|
if not page_closed:
|
||||||
|
try:
|
||||||
|
current = cart_lines(_cart_request(page, "GET", "/api/cart"))
|
||||||
|
except RuntimeError as exc:
|
||||||
|
failed.append(f"Could not read the cart: {exc}")
|
||||||
|
print(f"Failed: Could not read the cart: {exc}")
|
||||||
|
else:
|
||||||
|
for item in posted:
|
||||||
|
found = quantity_for(current, item.uuid)
|
||||||
|
if found != item.quantity:
|
||||||
|
message = (
|
||||||
|
f"{item.name}: requested {item.quantity}, cart has {found}"
|
||||||
|
)
|
||||||
|
failed.append(message)
|
||||||
|
print(f"Failed: {message}")
|
||||||
|
else:
|
||||||
|
added += 1
|
||||||
|
origin = _origin(page.url or menu_url)
|
||||||
|
page.goto(f"{origin}/cart", wait_until="domcontentloaded", timeout=60000)
|
||||||
|
ready = True
|
||||||
except (RuntimeError, PlaywrightError) as exc:
|
except (RuntimeError, PlaywrightError) as exc:
|
||||||
failed.append(str(exc))
|
failed.append(str(exc))
|
||||||
print(f"Failed: {exc}")
|
print(f"Failed: {exc}")
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@ def extract_catalog_products(page: str) -> list:
|
||||||
products = _extract_json_attr(page, PRODUCTS_MARKER)
|
products = _extract_json_attr(page, PRODUCTS_MARKER)
|
||||||
if not isinstance(products, list):
|
if not isinstance(products, list):
|
||||||
raise MenuParseError(":products must be a JSON array")
|
raise MenuParseError(":products must be a JSON array")
|
||||||
|
if not products:
|
||||||
|
raise MenuParseError("Menu catalog is empty")
|
||||||
return products
|
return products
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,29 @@ def test_fill_page_prints_a_summary_when_the_window_closes_mid_add(capsys):
|
||||||
assert "Cart is ready" not in output
|
assert "Cart is ready" not in output
|
||||||
|
|
||||||
|
|
||||||
|
def test_fill_page_counts_items_left_when_the_window_closes(capsys):
|
||||||
|
plan = build_plan(
|
||||||
|
"Item,Quantity\nKorean Steak Bowl,1\nSale Bowl,2\n",
|
||||||
|
PRODUCTS,
|
||||||
|
)
|
||||||
|
page = _CartPage(
|
||||||
|
[
|
||||||
|
{"ok": True, "status": 200, "data": {"items": []}},
|
||||||
|
PlaywrightError("Target page, context or browser has been closed"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
code = fill_redefine_cart._fill_page(
|
||||||
|
page, plan, "https://www.redefinemeals.com/menu"
|
||||||
|
)
|
||||||
|
output = capsys.readouterr().out
|
||||||
|
|
||||||
|
assert code == 1
|
||||||
|
assert "Korean Steak Bowl:" in output
|
||||||
|
assert "Sale Bowl: not attempted" in output
|
||||||
|
assert "Added 0. Failed 2. Skipped 0." in output
|
||||||
|
|
||||||
|
|
||||||
def test_fill_page_prints_a_summary_when_the_first_cart_read_fails(capsys):
|
def test_fill_page_prints_a_summary_when_the_first_cart_read_fails(capsys):
|
||||||
plan = build_plan("Item,Quantity\nKorean Steak Bowl,1\n", PRODUCTS)
|
plan = build_plan("Item,Quantity\nKorean Steak Bowl,1\n", PRODUCTS)
|
||||||
page = _CartPage(
|
page = _CartPage(
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from scraper.parse_menu import MenuParseError, parse_menu_html
|
from scraper.parse_menu import MenuParseError, extract_catalog_products, parse_menu_html
|
||||||
|
|
||||||
FIXTURE = Path(__file__).resolve().parent / "fixtures" / "menu_page.html"
|
FIXTURE = Path(__file__).resolve().parent / "fixtures" / "menu_page.html"
|
||||||
|
|
||||||
|
|
@ -43,6 +43,12 @@ def test_parse_menu_html_rejects_a_missing_catalog():
|
||||||
parse_menu_html("<html></html>", menu_url="https://example.com/menu")
|
parse_menu_html("<html></html>", menu_url="https://example.com/menu")
|
||||||
|
|
||||||
|
|
||||||
|
def test_extract_catalog_products_rejects_an_empty_catalog():
|
||||||
|
page = "<orders-page :products='[]' :newest-ids='[]'></orders-page>"
|
||||||
|
with pytest.raises(MenuParseError, match="empty"):
|
||||||
|
extract_catalog_products(page)
|
||||||
|
|
||||||
|
|
||||||
def test_parse_menu_html_rejects_an_empty_catalog():
|
def test_parse_menu_html_rejects_an_empty_catalog():
|
||||||
page = "<orders-page :products='[]' :newest-ids='[]'></orders-page>"
|
page = "<orders-page :products='[]' :newest-ids='[]'></orders-page>"
|
||||||
with pytest.raises(MenuParseError, match="empty"):
|
with pytest.raises(MenuParseError, match="empty"):
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue