69cc29b5e5
Six Playwright tests covering server-side state persistence across hard reloads, stale-phase propagation after back-navigation, stale banner dismiss, exported group immutability, and notes surviving phase navigation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
88 lines
3.4 KiB
Python
88 lines
3.4 KiB
Python
import json
|
|
|
|
|
|
def test_hard_refresh_preserves_triage_state(base_url, page, seed_state, flask_app):
|
|
"""State is server-side — hard refresh must not reset it."""
|
|
album_id = seed_state("phase2_state")
|
|
page.goto(f"{base_url}/triage?album_id={album_id}")
|
|
page.locator(".photo-card").first.click()
|
|
page.keyboard.press("j")
|
|
page.wait_for_timeout(400)
|
|
page.reload()
|
|
first_card = page.locator(".photo-card").first
|
|
assert "border-success" in first_card.get_attribute("class")
|
|
|
|
|
|
def test_back_nav_from_group_to_triage_marks_curate_group_stale(base_url, page, seed_state):
|
|
album_id = seed_state("phase4_state") # completed=[triage, curate], phase=group
|
|
page.request.post(
|
|
f"{base_url}/nav/phase",
|
|
data=json.dumps({"album_id": album_id, "target_phase": "triage"}),
|
|
headers={"Content-Type": "application/json"},
|
|
)
|
|
resp = page.request.get(f"{base_url}/state/{album_id}")
|
|
state = resp.json()
|
|
assert "curate" in state["phase_stale"]
|
|
assert "group" in state["phase_stale"]
|
|
|
|
|
|
def test_stale_banner_visible_on_stale_phase(base_url, page, seed_state):
|
|
album_id = seed_state("phase4_state")
|
|
page.request.post(
|
|
f"{base_url}/nav/phase",
|
|
data=json.dumps({"album_id": album_id, "target_phase": "triage"}),
|
|
headers={"Content-Type": "application/json"},
|
|
)
|
|
# Now visit curate (which is stale)
|
|
page.goto(f"{base_url}/curate?album_id={album_id}")
|
|
assert page.locator("#stale-banner").is_visible()
|
|
|
|
|
|
def test_dismiss_stale_clears_flag(base_url, page, seed_state, flask_app):
|
|
album_id = seed_state("phase4_state")
|
|
page.request.post(
|
|
f"{base_url}/nav/phase",
|
|
data=json.dumps({"album_id": album_id, "target_phase": "triage"}),
|
|
headers={"Content-Type": "application/json"},
|
|
)
|
|
page.goto(f"{base_url}/curate?album_id={album_id}")
|
|
page.locator("#stale-banner button").click()
|
|
page.wait_for_url("**/curate**")
|
|
with flask_app.app_context():
|
|
from app.state import load_state
|
|
state = load_state(album_id, flask_app)
|
|
assert "curate" not in state.phase_stale
|
|
|
|
|
|
def test_exported_group_not_affected_by_back_nav(base_url, page, seed_state, flask_app):
|
|
"""Exporting then going back to triage must not touch the exported group."""
|
|
album_id = seed_state("phase6_state")
|
|
# Manually set one group to exported
|
|
with flask_app.app_context():
|
|
from app.state import load_state, save_state
|
|
state = load_state(album_id, flask_app)
|
|
state.groups[0].status = "exported"
|
|
save_state(state, flask_app)
|
|
# Navigate back
|
|
page.request.post(
|
|
f"{base_url}/nav/phase",
|
|
data=json.dumps({"album_id": album_id, "target_phase": "triage"}),
|
|
headers={"Content-Type": "application/json"},
|
|
)
|
|
with flask_app.app_context():
|
|
from app.state import load_state
|
|
state = load_state(album_id, flask_app)
|
|
assert state.groups[0].status == "exported"
|
|
|
|
|
|
def test_notes_autosave_survives_phase_navigation(base_url, page, seed_state, flask_app):
|
|
album_id = seed_state("phase2_state")
|
|
page.request.post(
|
|
f"{base_url}/notes/save",
|
|
data=json.dumps({"album_id": album_id, "notes": "survives navigation"}),
|
|
headers={"Content-Type": "application/json"},
|
|
)
|
|
page.goto(f"{base_url}/curate?album_id={album_id}")
|
|
resp = page.request.get(f"{base_url}/notes/{album_id}")
|
|
assert resp.json()["notes"] == "survives navigation"
|