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 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-13 05:15:46 +00:00
co-authored by Claude Opus 4.6
parent a7520be0e7
commit 5bc8932d25
4 changed files with 109 additions and 0 deletions
+31
View File
@@ -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)
})
})
+27
View File
@@ -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)
})
})
+34
View File
@@ -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 })
})
})
+17
View File
@@ -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 })
})
})