Skip to content

Add comprehensive E2E test for full 4-player Lockout game#22

Merged
adamweeks merged 6 commits intomainfrom
claude/game-testing-suite-UmmNW
Mar 11, 2026
Merged

Add comprehensive E2E test for full 4-player Lockout game#22
adamweeks merged 6 commits intomainfrom
claude/game-testing-suite-UmmNW

Conversation

@adamweeks
Copy link
Copy Markdown
Contributor

Summary

This PR adds a complete end-to-end test suite for the Lockout game using Playwright, enabling automated validation of the full game flow from lobby creation through game completion with a winner.

Key Changes

  • Added e2e/full-game.spec.js: Comprehensive E2E test that simulates a complete 4-player game with:

    • Four independent browser contexts representing Alice (host, Team 1 hacker), Bob (Team 2 hacker), Charlie (Team 1 AI agent), and Diana (Team 2 AI agent)
    • Full game lifecycle: lobby creation → player joins → team assignment → role selection → ready state → game launch → turn-based gameplay loop → winner determination
    • Automated keyword submission by hackers and card guessing by AI agents
    • Backend API polling to verify game state transitions and validate team composition
    • Safety guards (MAX_TURNS limit, generous timeouts) to prevent infinite loops
    • Comprehensive assertions on final game state and winner validation
  • Added playwright.config.js: Playwright configuration with:

    • Sequential test execution (workers: 1) to prevent interference between coordinated multi-context tests
    • Failure artifacts (traces, screenshots, videos) for debugging
    • CI-aware retry logic
    • HTML and list reporters
  • Updated package.json: Added Playwright test dependency and three new npm scripts:

    • test:e2e: Run tests in headless mode
    • test:e2e:ui: Run tests with interactive UI
    • test:e2e:debug: Run tests in debug mode
  • Updated .gitignore: Added Playwright output directories (playwright-report/, test-results/)

Notable Implementation Details

  • The test uses helper functions (waitForGameState, waitForLobbyState) to poll the backend API with configurable conditions and timeouts, avoiding brittle hard-coded waits
  • Team assignment is validated against the backend's auto-balancing logic (host → team1, then alternating)
  • The game loop dynamically identifies correct cards to guess by filtering unrevealed cards of the active team's type, ensuring guesses always succeed
  • Turn timing accounts for the backend's 3-second post-guess sleep plus socket propagation overhead (8-second total wait)
  • All browser contexts are properly closed in a finally block to prevent resource leaks

https://claude.ai/code/session_01TAh7bmhCF5NV4Tn8CHuY34

claude added 2 commits March 8, 2026 06:07
Creates a complete browser-based testing suite that simulates 4 players
playing through an entire Lockout game from lobby creation to winner:

- playwright.config.js: Playwright configuration (chromium, sequential
  workers, report on failure)
- e2e/full-game.spec.js: Full game spec that:
  - Spawns 4 isolated browser contexts (Alice, Bob, Charlie, Diana)
  - Alice creates lobby; Bob/Charlie/Diana join
  - Alice & Bob become Hackers for their respective teams
  - All 4 players mark ready; Alice force-starts the game
  - Game loop: hacker submits keyword → AI agent picks correct card
    via backend API state inspection → submit guess → await turn end
  - Asserts game_over=true, valid winner, zero remaining cards
- package.json: Adds test:e2e / test:e2e:ui / test:e2e:debug scripts
  and @playwright/test devDependency

https://claude.ai/code/session_01TAh7bmhCF5NV4Tn8CHuY34
These directories are generated by Playwright and should not be tracked.

https://claude.ai/code/session_01TAh7bmhCF5NV4Tn8CHuY34
@aws-amplify-us-east-1
Copy link
Copy Markdown

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-22.d16sx389cvyqhv.amplifyapp.com

claude added 4 commits March 8, 2026 20:38
playwright.config.js:
- Add webServer array that starts the Flask backend (python -m backend.app)
  and Vite frontend (npm run dev) automatically before the test suite runs
- Backend: polls /health, sets FLASK_ENV/SECRET_KEY/ALLOWED_ORIGINS
- Frontend: sets VITE_API_URL and VITE_SOCKET_URL, inherits host PATH
- reuseExistingServer=true locally so dev servers aren't restarted on each run
- Remove FRONTEND_URL from use.baseURL (hardcoded to match webServer port)

e2e/full-game.spec.js:
- Fix prettier formatting (single quotes, trailing commas, line wrapping)

.github/workflows/e2e.yml:
- New workflow triggered on pull_request to main
- Sets up Python 3.12 and installs backend requirements
- Sets up Node 22 and installs root + frontend npm dependencies
- Installs Playwright chromium browser with system deps
- Runs npm run test:e2e with CI=true (no server reuse, 1 retry)
- Uploads playwright-report/ and test-results/ as artifacts on every run

https://claude.ai/code/session_01TAh7bmhCF5NV4Tn8CHuY34
Four bugs caused the CI run to fail within ~80s:

Bug 1 (critical): playwright.config.js set VITE_API_URL to
'http://localhost:5000' but all backend blueprints are registered under
the '/api' prefix (app.register_blueprint(..., url_prefix='/api')).
Every frontend REST call (create lobby, get lobby) returned 404 so the
game could never be created.
Fix: VITE_API_URL → 'http://localhost:5000/api'

Bug 2 (critical): waitForGameState and waitForLobbyState helpers called
${BACKEND_URL}/game/... and ${BACKEND_URL}/lobby/... — same missing /api
prefix — causing every polling loop to time out (10–15 s each).
Fix: introduce BACKEND_API_URL = `${BACKEND_URL}/api` and use it in all
request.get() calls including the final assertion.

Bug 3 (moderate): locator.isVisible() is synchronous in Playwright and
ignores any timeout argument; if the lobby socket update hadn't reached
Alice's page yet the check could return false too early, falling back to
the force-start path unnecessarily.
Fix: waitForSelector on either button text before calling isVisible().

Bug 4 (moderate): The keyword input selector did not require the element
to be enabled. HackerPrompt keeps the input in the DOM but disabled when
it is not the hacker's turn; Playwright's fill() throws on disabled
inputs.
Fix: add :not([disabled]) to the waitForSelector query.

https://claude.ai/code/session_01TAh7bmhCF5NV4Tn8CHuY34
MUI Tooltip overrides a button's accessible name with the tooltip's title
text, breaking getByRole('button', { name: 'Become Hacker' }) selectors.
Replace with locator('button:has-text(...)') which matches on visible text.

Also carries forward prior fixes:
- VITE_API_URL includes /api prefix so frontend REST calls hit real routes
- BACKEND_API_URL constant in test ensures polling helpers use /api prefix
- waitForSelector for start-game button before isVisible() check
- :not([disabled]) guard on keyword input selector
- Poll-based turn-end wait (TURN_END_POLL_TIMEOUT_MS) instead of fixed sleep
- 5-minute test timeout

https://claude.ai/code/session_01TAh7bmhCF5NV4Tn8CHuY34
The game blueprint (url_prefix='/game') is registered via
register_blueprint(game_bp, url_prefix='/api'), which replaces the
blueprint's own prefix, making the route /api/<lobby_id> rather than
/api/game/<lobby_id>.  Fix waitForGameState and the final state check
to use the correct path.

https://claude.ai/code/session_01TAh7bmhCF5NV4Tn8CHuY34
@adamweeks adamweeks merged commit b49981a into main Mar 11, 2026
5 checks passed
@adamweeks adamweeks deleted the claude/game-testing-suite-UmmNW branch March 11, 2026 00:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants