# retoor from datetime import datetime, timedelta, timezone from playwright.sync_api import expect from tests.conftest import BASE_URL from tests.e2e.game.index import reset_farm, warp_ready def _plant_growing(username, crop="python", slot=0): from devplacepy.database import get_table from devplacepy.services.game import store user = get_table("users").find_one(username=username) store.plant({"uid": user["uid"], "username": username}, slot, crop) def _warp_stealable(username): from devplacepy.database import get_table from devplacepy.services.game import economy, store user = get_table("users").find_one(username=username) farm = store.get_farm(user["uid"]) past = ( datetime.now(timezone.utc) - timedelta(seconds=economy.STEAL_GRACE_SECONDS + 10) ).isoformat() for plot in store.get_plots(farm["uid"]): if plot.get("crop_key"): get_table("game_plots").update( {"uid": plot["uid"], "ready_at": past}, ["uid"] ) def _farm_coins(username): from devplacepy.database import get_table from devplacepy.services.game import store user = get_table("users").find_one(username=username) farm = store.get_farm(user["uid"]) return int(farm.get("coins", 0)) def _has_badge(username, badge_name): from devplacepy.database import get_table user = get_table("users").find_one(username=username) return ( get_table("badges").find_one(user_uid=user["uid"], badge_name=badge_name) is not None ) def test_view_other_farm(bob): page, _ = bob reset_farm("alice_test") page.goto(f"{BASE_URL}/game/farm/alice_test", wait_until="domcontentloaded") page.locator(".game-header h1").wait_for(state="visible") assert "alice_test" in page.locator(".game-header h1").inner_text() assert page.locator("[data-game-grid]").first.is_visible() def test_water_neighbour_build(bob): page, _ = bob reset_farm("alice_test") _plant_growing("alice_test") page.goto(f"{BASE_URL}/game/farm/alice_test", wait_until="domcontentloaded") page.locator("[data-game-grid]").first.wait_for(state="visible") page.wait_for_timeout(800) water = page.locator("form[data-game-action='water'] button").first water.wait_for(state="visible") water.click() expect(page.locator(".plot-water-count").first).to_contain_text("1/3") def test_guest_can_view_farm(page): reset_farm("alice_test") page.goto(f"{BASE_URL}/game/farm/alice_test", wait_until="domcontentloaded") page.wait_for_timeout(500) assert "/auth/login" not in page.url assert "alice_test" in page.locator(".game-header h1").inner_text() def test_unknown_farm_is_404(bob): page, _ = bob response = page.goto( f"{BASE_URL}/game/farm/nope_nobody", wait_until="domcontentloaded" ) assert response is not None and response.status == 404 def test_ready_build_is_protected_during_grace(bob): page, _ = bob reset_farm("alice_test") _plant_growing("alice_test", crop="python") warp_ready("alice_test") page.goto(f"{BASE_URL}/game/farm/alice_test", wait_until="domcontentloaded") page.locator("[data-game-grid]").first.wait_for(state="visible") page.wait_for_timeout(800) expect(page.locator(".plot-ready-label").first).to_be_visible() assert page.locator("form[data-game-action='steal']").count() == 0 def test_steal_button_appears_after_grace(bob): page, _ = bob reset_farm("alice_test") _plant_growing("alice_test", crop="python") _warp_stealable("alice_test") page.goto(f"{BASE_URL}/game/farm/alice_test", wait_until="domcontentloaded") page.locator("[data-game-grid]").first.wait_for(state="visible") steal = page.locator("form[data-game-action='steal'] button").first steal.wait_for(state="visible") assert "Steal" in steal.inner_text() def test_steal_takes_build_and_pays_thief(bob): page, _ = bob reset_farm("alice_test") reset_farm("bob_test", coins=0) _plant_growing("alice_test", crop="python") _warp_stealable("alice_test") alice_coins_before = _farm_coins("alice_test") page.goto(f"{BASE_URL}/game/farm/alice_test", wait_until="domcontentloaded") page.locator("[data-game-grid]").first.wait_for(state="visible") steal = page.locator("form[data-game-action='steal'] button").first steal.wait_for(state="visible") steal.click() confirm_btn = page.locator(".dialog-confirm") confirm_btn.wait_for(state="visible") confirm_btn.click() expect(page.locator("form[data-game-action='steal']")).to_have_count(0) page.wait_for_timeout(400) assert _farm_coins("bob_test") == 18 assert _farm_coins("alice_test") == alice_coins_before assert _has_badge("bob_test", "Cat Burglar") assert _has_badge("alice_test", "Robbed") def test_owner_sees_harvest_not_steal(alice): page, _ = alice reset_farm("alice_test") _plant_growing("alice_test", crop="python") _warp_stealable("alice_test") page.goto(f"{BASE_URL}/game", wait_until="domcontentloaded") page.locator("[data-game-grid]").first.wait_for(state="visible") expect(page.locator("form[data-game-action='harvest'] button").first).to_be_visible() assert page.locator("form[data-game-action='steal']").count() == 0 def test_victim_gets_anonymous_notification(bob): page, _ = bob from devplacepy.database import get_table reset_farm("alice_test") reset_farm("bob_test", coins=0) alice = get_table("users").find_one(username="alice_test") get_table("notifications").delete(user_uid=alice["uid"], type="harvest_stolen") _plant_growing("alice_test", crop="python") _warp_stealable("alice_test") page.goto(f"{BASE_URL}/game/farm/alice_test", wait_until="domcontentloaded") page.locator("[data-game-grid]").first.wait_for(state="visible") steal = page.locator("form[data-game-action='steal'] button").first steal.wait_for(state="visible") steal.click() confirm_btn = page.locator(".dialog-confirm") confirm_btn.wait_for(state="visible") confirm_btn.click() expect(page.locator("form[data-game-action='steal']")).to_have_count(0) page.wait_for_timeout(400) note = get_table("notifications").find_one( user_uid=alice["uid"], type="harvest_stolen" ) assert note is not None assert "bob_test" not in note["message"]