Add Playwright e2e tests for all 8 spec acceptance scenarios
All checks were successful
Deploy / deploy (push) Successful in 1m49s
All checks were successful
Deploy / deploy (push) Successful in 1m49s
Implement browser-based e2e tests covering: - Tests 1-5: Stats progression (cohort, feed, eggs, moves, backdating) - Test 6: Event viewing and deletion UI - Test 7: Harvest outcomes with yield items - Test 8: Optimistic lock selection validation Includes page objects for reusable form interactions and fresh_db fixtures for tests requiring isolated database state. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
137
tests/e2e/pages/eggs.py
Normal file
137
tests/e2e/pages/eggs.py
Normal file
@@ -0,0 +1,137 @@
|
||||
# ABOUTME: Page object for egg collection and sales pages.
|
||||
# ABOUTME: Encapsulates navigation and form interactions for product operations.
|
||||
|
||||
from playwright.sync_api import Page, expect
|
||||
|
||||
|
||||
class EggsPage:
|
||||
"""Page object for egg collection and sales pages."""
|
||||
|
||||
def __init__(self, page: Page, base_url: str):
|
||||
self.page = page
|
||||
self.base_url = base_url
|
||||
|
||||
def goto_eggs_page(self):
|
||||
"""Navigate to the eggs (home) page."""
|
||||
self.page.goto(self.base_url)
|
||||
expect(self.page.locator("body")).to_be_visible()
|
||||
|
||||
def collect_eggs(
|
||||
self,
|
||||
*,
|
||||
location_name: str,
|
||||
quantity: int,
|
||||
notes: str = "",
|
||||
):
|
||||
"""Fill and submit the egg harvest (collect) form.
|
||||
|
||||
Args:
|
||||
location_name: Human-readable location name (e.g., "Strip 1")
|
||||
quantity: Number of eggs collected
|
||||
notes: Optional notes
|
||||
"""
|
||||
self.goto_eggs_page()
|
||||
|
||||
# Fill harvest form
|
||||
self.page.select_option("#location_id", label=location_name)
|
||||
self.page.fill("#quantity", str(quantity))
|
||||
|
||||
if notes:
|
||||
self.page.fill("#notes", notes)
|
||||
|
||||
# Submit the harvest form
|
||||
self.page.click('form[hx-post*="product-collected"] button[type="submit"]')
|
||||
|
||||
# Wait for HTMX response
|
||||
self.page.wait_for_load_state("networkidle")
|
||||
|
||||
def collect_eggs_backdated(
|
||||
self,
|
||||
*,
|
||||
location_name: str,
|
||||
quantity: int,
|
||||
datetime_local: str,
|
||||
notes: str = "",
|
||||
):
|
||||
"""Collect eggs with a backdated timestamp.
|
||||
|
||||
Args:
|
||||
location_name: Human-readable location name
|
||||
quantity: Number of eggs
|
||||
datetime_local: Datetime string in format "YYYY-MM-DDTHH:MM"
|
||||
notes: Optional notes
|
||||
"""
|
||||
self.goto_eggs_page()
|
||||
|
||||
# Fill harvest form
|
||||
self.page.select_option("#location_id", label=location_name)
|
||||
self.page.fill("#quantity", str(quantity))
|
||||
|
||||
if notes:
|
||||
self.page.fill("#notes", notes)
|
||||
|
||||
# Expand datetime picker and set backdated time
|
||||
# Click the datetime toggle to expand
|
||||
datetime_toggle = self.page.locator("[data-datetime-picker]")
|
||||
if datetime_toggle.count() > 0:
|
||||
datetime_toggle.first.click()
|
||||
# Fill the datetime-local input
|
||||
self.page.fill('input[type="datetime-local"]', datetime_local)
|
||||
|
||||
# Submit the harvest form
|
||||
self.page.click('form[hx-post*="product-collected"] button[type="submit"]')
|
||||
|
||||
# Wait for HTMX response
|
||||
self.page.wait_for_load_state("networkidle")
|
||||
|
||||
def sell_eggs(
|
||||
self,
|
||||
*,
|
||||
product_code: str = "egg.duck",
|
||||
quantity: int,
|
||||
total_price_cents: int,
|
||||
buyer: str = "",
|
||||
notes: str = "",
|
||||
):
|
||||
"""Fill and submit the egg sale form.
|
||||
|
||||
Args:
|
||||
product_code: Product code (e.g., "egg.duck")
|
||||
quantity: Number of eggs sold
|
||||
total_price_cents: Total price in cents
|
||||
buyer: Optional buyer name
|
||||
notes: Optional notes
|
||||
"""
|
||||
self.goto_eggs_page()
|
||||
|
||||
# Switch to sell tab if needed
|
||||
sell_tab = self.page.locator('text="Sell"')
|
||||
if sell_tab.count() > 0:
|
||||
sell_tab.click()
|
||||
self.page.wait_for_load_state("networkidle")
|
||||
|
||||
# Fill sell form
|
||||
self.page.select_option("#product_code", product_code)
|
||||
self.page.fill("#sell_quantity", str(quantity))
|
||||
self.page.fill("#total_price_cents", str(total_price_cents))
|
||||
|
||||
if buyer:
|
||||
self.page.fill("#buyer", buyer)
|
||||
|
||||
if notes:
|
||||
self.page.fill("#sell_notes", notes)
|
||||
|
||||
# Submit the sell form
|
||||
self.page.click('form[hx-post*="product-sold"] button[type="submit"]')
|
||||
|
||||
# Wait for HTMX response
|
||||
self.page.wait_for_load_state("networkidle")
|
||||
|
||||
def get_egg_stats(self) -> dict:
|
||||
"""Get egg statistics from the page.
|
||||
|
||||
Returns dict with stats like eggs_per_day, cost_per_egg, etc.
|
||||
"""
|
||||
# This depends on how stats are displayed on the page
|
||||
# May need to parse text content from stats section
|
||||
return {}
|
||||
Reference in New Issue
Block a user