test: add Playwright E2E infrastructure with smoke test

Set up Playwright with Chromium, dev server auto-start, test helpers
for seeding bots and programmatic auth. Added smoke spec that verifies
homepage and leaderboard load without crashes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-13 05:14:15 +00:00
co-authored by Claude Opus 4.6
parent 5e40221a2f
commit a7520be0e7
6 changed files with 174 additions and 1 deletions
+37
View File
@@ -0,0 +1,37 @@
/**
* E2E authentication helpers.
* Provides programmatic login for tests without browser extension interaction.
*/
import { randomPubkey } from './setup.js'
/**
* Create a test identity (pubkey + nsec equivalent).
* For E2E tests, we use direct pubkey-based login (legacy endpoint)
* since we can't interact with NIP-07 browser extensions.
*/
export function createTestIdentity() {
return {
pubkey: randomPubkey(),
// In a real NIP-98 flow, this would be a signed event
// For testing, we use the legacy login endpoint
}
}
/**
* Login via legacy endpoint and get bot data.
* Returns bot info if the pubkey has a registered bot.
*/
export async function loginWithPubkey(baseURL: string, pubkey: string): Promise<{ bot?: { id: string; name: string } }> {
const res = await fetch(`${baseURL}/api/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pubkey }),
})
if (!res.ok) {
return {}
}
return res.json()
}
+46
View File
@@ -0,0 +1,46 @@
/**
* E2E test setup helpers.
* Provides utilities for seeding test data and managing test state.
*/
/** Wait for the dev server to be ready */
export async function waitForServer(baseURL: string, timeoutMs = 10_000): Promise<void> {
const start = Date.now()
while (Date.now() - start < timeoutMs) {
try {
const res = await fetch(baseURL)
if (res.ok) return
} catch {
// Server not ready yet
}
await new Promise(r => setTimeout(r, 500))
}
throw new Error(`Server at ${baseURL} did not start within ${timeoutMs}ms`)
}
/** Seed a mock bot via the API for testing */
export async function seedBot(baseURL: string, name: string, pubkey: string): Promise<{ id: string; secret: string }> {
const res = await fetch(`${baseURL}/api/auth/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
pubkey,
name,
webhookUrl: 'http://mock.local',
}),
})
if (!res.ok) {
const body = await res.text()
throw new Error(`Failed to seed bot ${name}: ${res.status} ${body}`)
}
return res.json()
}
/** Generate a random hex pubkey for testing */
export function randomPubkey(): string {
const bytes = new Uint8Array(32)
crypto.getRandomValues(bytes)
return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('')
}