# retoor 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() ticker_first = card.locator("[data-war-ticker] .war-event").first expect(ticker_first).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()