From 5bc8932d25c08147b52ca2a32aa30c7a626d24e6 Mon Sep 17 00:00:00 2001 From: Dorian Date: Fri, 13 Mar 2026 05:15:46 +0000 Subject: [PATCH] test: E2E specs for signup, fight replay, and leaderboard flows Bot registration (3 tests), human registration (1 test), fight replay (2 tests for JS error checking), and leaderboard (3 tests for rendering). All use Playwright with text-based selectors. Co-Authored-By: Claude Opus 4.6 --- e2e/fight-replay.spec.ts | 31 +++++++++++++++++++++++++++++++ e2e/leaderboard.spec.ts | 27 +++++++++++++++++++++++++++ e2e/signup-bot.spec.ts | 34 ++++++++++++++++++++++++++++++++++ e2e/signup-human.spec.ts | 17 +++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 e2e/fight-replay.spec.ts create mode 100644 e2e/leaderboard.spec.ts create mode 100644 e2e/signup-bot.spec.ts create mode 100644 e2e/signup-human.spec.ts diff --git a/e2e/fight-replay.spec.ts b/e2e/fight-replay.spec.ts new file mode 100644 index 0000000..89d1df4 --- /dev/null +++ b/e2e/fight-replay.spec.ts @@ -0,0 +1,31 @@ +import { test, expect } from '@playwright/test' + +test.describe('fight replay', () => { + test('arena page loads without JS errors', async ({ page }) => { + const jsErrors: string[] = [] + page.on('pageerror', err => jsErrors.push(err.message)) + + await page.goto('/arena') + await page.waitForTimeout(2000) + + // Filter out expected errors (e.g., missing API data in test env) + const criticalErrors = jsErrors.filter(e => + e.includes('TypeError') || e.includes('ReferenceError') || e.includes('SyntaxError') + ) + expect(criticalErrors).toHaveLength(0) + }) + + test('fight page with invalid ID shows error gracefully', async ({ page }) => { + const jsErrors: string[] = [] + page.on('pageerror', err => jsErrors.push(err.message)) + + await page.goto('/arena/nonexistent-fight-id') + await page.waitForTimeout(2000) + + // Should not crash — may show error state or redirect + const criticalErrors = jsErrors.filter(e => + e.includes('ReferenceError') || e.includes('SyntaxError') + ) + expect(criticalErrors).toHaveLength(0) + }) +}) diff --git a/e2e/leaderboard.spec.ts b/e2e/leaderboard.spec.ts new file mode 100644 index 0000000..2ed795c --- /dev/null +++ b/e2e/leaderboard.spec.ts @@ -0,0 +1,27 @@ +import { test, expect } from '@playwright/test' + +test.describe('leaderboard', () => { + test('leaderboard page loads and shows rankings header', async ({ page }) => { + await page.goto('/leaderboard') + + // Should show the rankings header + await expect(page.getByText(/rankings/i).first()).toBeVisible({ timeout: 10_000 }) + }) + + test('leaderboard has season toggle buttons', async ({ page }) => { + await page.goto('/leaderboard') + + // Should have season/alltime toggle + await expect(page.getByText(/this season/i).first()).toBeVisible({ timeout: 10_000 }) + await expect(page.getByText(/all time/i).first()).toBeVisible() + }) + + test('leaderboard shows tier column headers', async ({ page }) => { + await page.goto('/leaderboard') + await page.waitForTimeout(2000) + + // Should show table headers for rankings + const content = await page.textContent('body') + expect(content).toMatch(/elo|tier|fighter/i) + }) +}) diff --git a/e2e/signup-bot.spec.ts b/e2e/signup-bot.spec.ts new file mode 100644 index 0000000..238fa61 --- /dev/null +++ b/e2e/signup-bot.spec.ts @@ -0,0 +1,34 @@ +import { test, expect } from '@playwright/test' + +test.describe('bot registration flow', () => { + test('navigate to join page and see login step', async ({ page }) => { + await page.goto('/join') + // Should show login options + await expect(page.getByText(/sign in/i).first()).toBeVisible({ timeout: 10_000 }) + }) + + test('generate new identity shows choose-mode step', async ({ page }) => { + await page.goto('/join') + // Click "Generate New Identity" button + const genButton = page.getByText(/generate new identity/i) + await genButton.click() + + // Should advance to choose-mode step + await expect(page.getByText(/I BUILD BOTS/i)).toBeVisible({ timeout: 5_000 }) + await expect(page.getByText(/I FIGHT MYSELF/i)).toBeVisible() + }) + + test('select bot mode shows archetype picker', async ({ page }) => { + await page.goto('/join') + + // Generate identity + await page.getByText(/generate new identity/i).click() + await expect(page.getByText(/I BUILD BOTS/i)).toBeVisible({ timeout: 5_000 }) + + // Choose bot mode + await page.getByText(/I BUILD BOTS/i).click() + + // Should show character/archetype picker + await expect(page.getByText(/pick.*character/i).first()).toBeVisible({ timeout: 5_000 }) + }) +}) diff --git a/e2e/signup-human.spec.ts b/e2e/signup-human.spec.ts new file mode 100644 index 0000000..5e3868f --- /dev/null +++ b/e2e/signup-human.spec.ts @@ -0,0 +1,17 @@ +import { test, expect } from '@playwright/test' + +test.describe('human registration flow', () => { + test('select human mode shows avatar picker', async ({ page }) => { + await page.goto('/join') + + // Generate identity + await page.getByText(/generate new identity/i).click() + await expect(page.getByText(/I FIGHT MYSELF/i)).toBeVisible({ timeout: 5_000 }) + + // Choose human mode + await page.getByText(/I FIGHT MYSELF/i).click() + + // Should show human avatar picker + await expect(page.getByText(/pick.*avatar/i).first()).toBeVisible({ timeout: 5_000 }) + }) +})