browse

Playwright-powered browser automation and E2E testing for SolanaOS Hub. Covers test configuration, agent-driven test generation (planner/generator/healer), NanoHub route testing, Convex API validation

SKILL.md

GitHub

Browse — Playwright E2E Testing for SolanaOS Hub

Browser automation and end-to-end testing skill for the SolanaOS NanoHub, powered by Playwright.

Quick Start

# Install Playwright browsers
npx playwright install chromium

# Run E2E tests
bun run test:e2e

# Run with UI mode
npx playwright test --ui

# Generate tests interactively
npx playwright codegen https://seeker.solanaos.net

NanoHub Test Configuration

The NanoHub uses a dual config setup:

Playwright Config (playwright.config.ts)

Browser-based E2E tests against the built frontend.

import { defineConfig, devices } from '@playwright/test'

export default defineConfig({
  testDir: './e2e',
  testMatch: /.*\.pw\.test\.ts/,
  timeout: 60_000,
  expect: { timeout: 10_000 },
  fullyParallel: true,
  retries: process.env.CI ? 2 : 0,
  use: {
    baseURL: process.env.PLAYWRIGHT_BASE_URL || 'http://127.0.0.1:4173',
    trace: 'retain-on-failure',
  },
  webServer: {
    command: 'bun run preview -- --host 127.0.0.1 --port 4173',
    url: 'http://127.0.0.1:4173',
    reuseExistingServer: !process.env.CI,
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
  ],
})

Vitest E2E Config (vitest.e2e.config.ts)

Node-based E2E tests for CLI and API validation (no browser needed).

bun vitest run -c vitest.e2e.config.ts

NanoHub Routes to Test

Route Auth What to verify
/ No Landing page renders, navigation works
/launch No Boot sequence animation, CTA links
/mobile No Seeker mobile walkthrough renders
/skills No Skill cards load from Convex
/souls No Soul cards load from Convex
/ipfs No IPFS Hub page renders, wallet input works
/agents No Agent directory loads public agents
/dashboard Yes Wallet connect, agent factory, pairing
/upload Yes Skill publish flow with file upload
/settings Yes User preferences, agent config
/mining No BitAxe fleet dashboard renders
/strategy No Strategy builder loads
/create Yes Skill creator wizard
/auth/callback No GitHub OAuth redirect handling

Writing Hub Tests

Public Route Test

import { test, expect } from '@playwright/test'

test('IPFS Hub page loads', async ({ page }) => {
  await page.goto('/ipfs')
  await expect(page.locator('h1')).toContainText('Private IPFS')
  await expect(page.locator('.gallery-stat-card')).toHaveCount(4)
})

test('agent directory shows cards', async ({ page }) => {
  await page.goto('/agents')
  await expect(page.locator('h1')).toContainText('Registered')
  // Wait for Convex query
  await page.waitForSelector('.agent-card', { timeout: 10_000 })
})

test('skill search works', async ({ page }) => {
  await page.goto('/skills')
  await page.locator('input[type="search"]').fill('solanaos')
  await page.waitForSelector('.skill-card')
  await expect(page.locator('.skill-card')).toHaveCount.greaterThan(0)
})

Authenticated Route Test

import { test, expect } from '@playwright/test'

// Use storage state from auth setup
test.use({ storageState: 'e2e/.auth/user.json' })

test('dashboard loads for authenticated user', async ({ page }) => {
  await page.goto('/dashboard')
  await expect(page.locator('.dashboard-section')).toBeVisible()
})

Convex API Test (Vitest, no browser)

import { describe, expect, it } from 'vitest'

const CONVEX_URL = process.env.CONVEX_URL || 'https://artful-frog-940.convex.cloud'

describe('Convex IPFS API', () => {
  it('GET /api/v1/ipfs/files returns array', async () => {
    const res = await fetch(
      `${CONVEX_URL}/api/v1/ipfs/files?wallet=test`,
      { headers: { Accept: 'application/json' } }
    )
    expect(res.ok).toBe(true)
    const data = await res.json()
    expect(data).toHaveProperty('files')
    expect(Array.isArray(data.files)).toBe(true)
  })

  it('GET /api/v1/ipfs/stats returns stats object', async () => {
    const res = await fetch(
      `${CONVEX_URL}/api/v1/ipfs/stats?wallet=test`,
      { headers: { Accept: 'application/json' } }
    )
    expect(res.ok).toBe(true)
    const data = await res.json()
    expect(data.stats).toHaveProperty('totalFiles')
  })
})

Playwright Agents (AI-Driven Testing)

Playwright includes three built-in AI test agents.

Setup

npx playwright init-agents --loop=vscode

Planner

Explores the app and produces a Markdown test plan.

Input: "Generate a test plan for the IPFS Hub upload and recall flow"
Output: specs/ipfs-hub.md

The planner needs a seed test that sets up the environment:

// tests/seed.spec.ts
import { test } from '@playwright/test'

test('seed', async ({ page }) => {
  await page.goto('/')
})

Generator

Transforms Markdown plans into executable Playwright test files.

Input: specs/ipfs-hub.md
Output: tests/ipfs-hub/upload-file.spec.ts

Healer

Automatically repairs failing tests by:

  1. Replaying failing steps
  2. Inspecting current UI for equivalent elements
  3. Patching locators, waits, or data
  4. Re-running until pass or skip
Input: "Heal tests/ipfs-hub/upload-file.spec.ts"
Output: Passing test (or skipped with reason)

Configuration Reference

Top-Level Options

Option Description
testDir Directory with test files
testMatch Glob/regex for test file matching
testIgnore Glob/regex for files to skip
timeout Per-test timeout (default: 30s)
retries Retry count for flaky tests
workers Parallel worker count
fullyParallel Run all tests in parallel
forbidOnly Fail if test.only found (CI)
reporter Output format: list, html, json, dot
outputDir Artifacts directory (screenshots, videos, traces)
globalSetup Path to setup script (runs before all tests)
globalTeardown Path to teardown script (runs after all tests)
webServer Auto-start dev server before tests

use Options

Option Description
baseURL Base URL for page.goto('/')
storageState Pre-populated auth state
trace Trace capture: off, on, retain-on-failure, on-first-retry
screenshot Screenshot capture: off, on, only-on-failure
video Video recording: off, on, retain-on-failure
headless Run without browser UI (default: true)
viewport Browser viewport size
locale User locale emulation
colorScheme light or dark mode
geolocation GPS coordinate emulation
permissions Browser permission grants
offline Simulate offline mode
proxy HTTP proxy settings
extraHTTPHeaders Headers sent with every request
actionTimeout Timeout per action (click, fill, etc.)
testIdAttribute Custom test ID attribute

Annotations

// Skip a test
test.skip('not ready', async ({ page }) => {})

// Mark as expected failure
test.fail('known bug', async ({ page }) => {})

// Mark as slow (3x timeout)
test.slow()

// Tag for filtering
test('login @smoke', async ({ page }) => {})
test('checkout', { tag: ['@e2e', '@slow'] }, async ({ page }) => {})

// Run tagged tests
// npx playwright test --grep @smoke
// npx playwright test --grep-invert @slow

CLI Commands

# Run all tests
npx playwright test

# Run specific file
npx playwright test e2e/ipfs-hub.pw.test.ts

# Run by title match
npx playwright test -g "IPFS Hub"

# Run with browser visible
npx playwright test --headed

# Debug mode (inspector + slow)
npx playwright test --debug

# Interactive UI mode
npx playwright test --ui

# Generate test code interactively
npx playwright codegen https://seeker.solanaos.net

# View last test report
npx playwright show-report

# View trace file
npx playwright show-trace test-results/trace.zip

# Only re-run failures
npx playwright test --last-failed

# Shard across CI workers
npx playwright test --shard=1/3

CI Integration

# .github/workflows/e2e.yml
name: E2E Tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - run: bun install
      - run: npx playwright install --with-deps chromium
      - run: bun run build
      - run: npx playwright test
      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: playwright-report
          path: playwright-report/

NanoHub E2E Environment Variables

Variable Description
PLAYWRIGHT_BASE_URL Override base URL (skip local server)
PLAYWRIGHT_PORT Override preview server port (default: 4173)
CLAWHUB_E2E_TOKEN API token for authenticated CLI tests
CLAWDHUB_E2E_TOKEN Alias for above
CLAWHUB_REGISTRY Registry URL override
CLAWHUB_SITE Site URL override
CI Enables retries, single worker, forbidOnly