forked from retoor/devplacepy
The auth matrix probes documented endpoints with their documented form params; the faction param was declared with location body instead of form, so the anonymous probe sent an empty body and hit 422 validation before the auth guard. And the first fight always triggers a lead-change event that outranks the fight event at the top of the ticker, so the e2e flow now asserts on the ticker as a whole. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
157 lines
5.9 KiB
Python
157 lines
5.9 KiB
Python
# retoor <retoor@molodetz.nl>
|
|
|
|
import time
|
|
|
|
import requests
|
|
from playwright.sync_api import expect
|
|
|
|
from tests.conftest import BASE_URL
|
|
|
|
_counter_wars = [0]
|
|
|
|
|
|
def _seed_war(faction_a="Tabs", faction_b="Spaces"):
|
|
_counter_wars[0] += 1
|
|
name = f"ewar{int(time.time() * 1000)}{_counter_wars[0]}"
|
|
s = requests.Session()
|
|
s.post(
|
|
f"{BASE_URL}/auth/signup",
|
|
data={
|
|
"username": name,
|
|
"email": f"{name}@t.dev",
|
|
"password": "secret123",
|
|
"confirm_password": "secret123",
|
|
"birth_date": "1990-01-01",
|
|
"accept_terms": "1",
|
|
},
|
|
allow_redirects=True,
|
|
)
|
|
r = s.post(
|
|
f"{BASE_URL}/posts/create",
|
|
data={
|
|
"content": "Seeded battle post for browser tests.",
|
|
"title": f"battle-{name}",
|
|
"topic": "question",
|
|
"war_faction_a": faction_a,
|
|
"war_faction_b": faction_b,
|
|
},
|
|
allow_redirects=False,
|
|
)
|
|
return r.headers["location"].split("/posts/")[-1]
|
|
|
|
|
|
def _open_composer(page):
|
|
page.goto(f"{BASE_URL}/feed", wait_until="domcontentloaded")
|
|
page.locator(".feed-fab").first.wait_for(state="visible")
|
|
page.locator(".feed-fab").first.click()
|
|
page.locator("#create-post-modal.visible").wait_for(state="visible")
|
|
|
|
|
|
def test_battles_page_lists_cards(alice):
|
|
page, _ = alice
|
|
_seed_war("Vikings", "Knights")
|
|
page.goto(f"{BASE_URL}/battles", wait_until="domcontentloaded")
|
|
page.locator("dp-opinion-war").first.wait_for(state="visible")
|
|
expect(page.locator(".topnav-link.active:has-text('Battles')")).to_be_visible()
|
|
expect(page.locator("dp-opinion-war .war-vs").first).to_have_text("VS")
|
|
|
|
|
|
def test_battle_card_on_post_page(alice):
|
|
page, _ = alice
|
|
slug = _seed_war("Ninjas", "Pirates")
|
|
page.goto(f"{BASE_URL}/posts/{slug}", wait_until="domcontentloaded")
|
|
card = page.locator("dp-opinion-war")
|
|
card.wait_for(state="visible")
|
|
expect(card.locator(".war-side-a .war-side-name")).to_have_text("Ninjas")
|
|
expect(card.locator(".war-field")).to_be_visible()
|
|
expect(card.locator(".war-all-link")).to_have_attribute("href", "/battles")
|
|
|
|
|
|
def test_composer_war_toggle_and_poll_exclusivity(alice):
|
|
page, _ = alice
|
|
_open_composer(page)
|
|
modal = page.locator("#create-post-modal")
|
|
expect(modal.locator("[data-war-builder]")).to_be_hidden()
|
|
modal.locator("[data-war-toggle]").click()
|
|
expect(modal.locator("[data-war-builder]")).to_be_visible()
|
|
expect(modal.locator("input[name='war_faction_a']")).to_be_enabled()
|
|
modal.locator("[data-poll-toggle]").click()
|
|
expect(modal.locator("[data-poll-builder]")).to_be_visible()
|
|
expect(modal.locator("[data-war-builder]")).to_be_hidden()
|
|
modal.locator("[data-war-toggle]").click()
|
|
expect(modal.locator("[data-war-builder]")).to_be_visible()
|
|
expect(modal.locator("[data-poll-builder]")).to_be_hidden()
|
|
|
|
|
|
def test_composer_war_validation_blocks_submit(alice):
|
|
page, _ = alice
|
|
_open_composer(page)
|
|
modal = page.locator("#create-post-modal")
|
|
page.fill("#post-content", "A war with only one named faction must not submit.")
|
|
modal.locator("[data-war-toggle]").click()
|
|
modal.locator("input[name='war_faction_a']").fill("Solo")
|
|
modal.locator("button.btn-primary:has-text('Post')").click()
|
|
expect(modal.locator("[data-war-error]")).to_be_visible()
|
|
assert "/feed" in page.url
|
|
|
|
|
|
def test_create_join_and_fight_flow(alice):
|
|
page, _ = alice
|
|
from devplacepy.database import get_table, refresh_snapshot
|
|
from devplacepy.services.game.store import ensure_farm
|
|
|
|
refresh_snapshot()
|
|
row = get_table("users").find_one(username="alice_test")
|
|
farm = ensure_farm(row["uid"])
|
|
get_table("game_farms").update({"uid": farm["uid"], "coins": 1000}, ["uid"])
|
|
|
|
_open_composer(page)
|
|
modal = page.locator("#create-post-modal")
|
|
page.fill("#post-content", "Full battle flow: create, join and fight in browser.")
|
|
modal.locator("[data-war-toggle]").click()
|
|
modal.locator("input[name='war_faction_a']").fill("Coffee")
|
|
modal.locator("input[name='war_faction_b']").fill("Tea")
|
|
modal.locator("button.btn-primary:has-text('Post')").click()
|
|
page.wait_for_url(f"{BASE_URL}/posts/*", wait_until="domcontentloaded")
|
|
|
|
card = page.locator("dp-opinion-war")
|
|
card.wait_for(state="visible")
|
|
card.locator(".war-join-a").click()
|
|
card.locator("[data-war-mine]").wait_for(state="visible")
|
|
|
|
hp_before = card.locator("[data-war-hp-a]").text_content()
|
|
card.locator("[data-war-fight]").click()
|
|
page.wait_for_function(
|
|
"before => document.querySelector('[data-war-hp-a]').textContent !== before",
|
|
arg=hp_before,
|
|
)
|
|
expect(card.locator("[data-war-fight]")).to_be_disabled()
|
|
expect(card.locator("[data-war-ticker]")).to_contain_text("dealt")
|
|
|
|
|
|
def test_switch_faction_shows_confirm(alice):
|
|
page, _ = alice
|
|
slug = _seed_war("Left", "Right")
|
|
page.goto(f"{BASE_URL}/posts/{slug}", wait_until="domcontentloaded")
|
|
card = page.locator("dp-opinion-war")
|
|
card.wait_for(state="visible")
|
|
card.locator(".war-join-b").click()
|
|
page.wait_for_url(f"{BASE_URL}/posts/*", wait_until="domcontentloaded")
|
|
card = page.locator("dp-opinion-war")
|
|
card.locator(".war-switch-btn").wait_for(state="visible")
|
|
card.locator(".war-switch-btn").click()
|
|
page.locator(".dialog-overlay.visible .dialog-confirm").wait_for(state="visible")
|
|
page.locator(".dialog-overlay.visible .dialog-confirm").click()
|
|
page.wait_for_url(f"{BASE_URL}/posts/*", wait_until="domcontentloaded")
|
|
card = page.locator("dp-opinion-war")
|
|
expect(card.locator(".war-mine-faction")).to_have_text("Left")
|
|
|
|
|
|
def test_guest_sees_disabled_actions(page, app_server):
|
|
slug = _seed_war("Sun", "Moon")
|
|
page.goto(f"{BASE_URL}/posts/{slug}", wait_until="domcontentloaded")
|
|
card = page.locator("dp-opinion-war")
|
|
card.wait_for(state="visible")
|
|
expect(card.locator(".war-join-a")).to_be_disabled()
|
|
expect(card.locator(".war-join-b")).to_be_disabled()
|