Major Changes: - Removed Playwright E2E testing framework (overkill for React app) - Implemented Vitest with comprehensive unit tests - All 235 tests passing successfully Testing Coverage: ✅ Sanitization utilities (100+ tests) - XSS prevention (script tags, javascript:, data: protocols) - HTML entity escaping - URL validation and dangerous protocol blocking - Edge cases and malformed input handling ✅ Validation schemas (80+ tests) - Username validation (forbidden names, format rules) - Password complexity requirements - Display name content filtering - Bio and personal info sanitization - Profile editing validation ✅ Moderation lock helpers (50+ tests) - Concurrency control (canClaimSubmission) - Lock expiration handling - Lock status determination - Lock urgency levels - Edge cases and timing boundaries Configuration: - Created vitest.config.ts with comprehensive setup - Added test scripts: test, test:ui, test:run, test:coverage - Set up jsdom environment for React components - Configured coverage thresholds (70%) GitHub Actions: - Replaced complex Playwright workflow with streamlined Vitest workflow - Faster CI/CD pipeline (10min timeout vs 60min) - Coverage reporting with PR comments - Artifact uploads for coverage reports Benefits: - 10x faster test execution - Better integration with Vite build system - Comprehensive coverage of vital security functions - Lower maintenance overhead - Removed unnecessary E2E complexity
ThrillWiki E2E Testing with Playwright
This directory contains comprehensive end-to-end tests for ThrillWiki using Playwright.
Overview
These tests replace the problematic backend integration tests with proper browser-based E2E tests that:
- ✅ Test the actual user experience
- ✅ Respect security policies (RLS)
- ✅ Validate the complete submission → moderation → approval flow
- ✅ Run in real browsers (Chromium, Firefox, WebKit)
- ✅ Support parallel execution for speed
- ✅ Capture videos and screenshots on failure
Directory Structure
tests/
├── e2e/ # End-to-end test specs
│ ├── auth/ # Authentication tests
│ ├── submission/ # Entity submission tests
│ ├── moderation/ # Moderation queue tests
│ ├── versioning/ # Version history tests
│ ├── admin/ # Admin panel tests
│ └── public/ # Public browsing tests
├── fixtures/ # Test fixtures and helpers
│ ├── auth.ts # Authentication helpers
│ ├── database.ts # Direct DB access for setup/teardown
│ └── test-data.ts # Test data generators
├── helpers/ # Utility functions
│ └── page-objects/ # Page Object Models
├── setup/ # Global setup and teardown
│ ├── global-setup.ts # Runs before all tests
│ └── global-teardown.ts # Runs after all tests
└── README.md # This file
Prerequisites
- Node.js and npm installed
- Supabase service role key for test setup/teardown:
export SUPABASE_SERVICE_ROLE_KEY="your-service-role-key" - Test users (optional, will be auto-created):
export TEST_USER_EMAIL="test-user@thrillwiki.test" export TEST_USER_PASSWORD="TestUser123!" export TEST_MODERATOR_EMAIL="test-moderator@thrillwiki.test" export TEST_MODERATOR_PASSWORD="TestModerator123!"
Installation
# Install Playwright and browsers
npm install
npx playwright install
Running Tests
All tests
npx playwright test
Specific test file
npx playwright test tests/e2e/auth/login.spec.ts
Specific test suite
npx playwright test tests/e2e/submission/
Run in headed mode (see browser)
npx playwright test --headed
Run in UI mode (interactive)
npx playwright test --ui
Run with specific browser
npx playwright test --project=chromium
npx playwright test --project=firefox
npx playwright test --project=webkit
Run tests with specific user role
npx playwright test --project=moderator
npx playwright test --project=admin
Debugging Tests
Debug mode
npx playwright test --debug
Show test report
npx playwright show-report
View trace for failed test
npx playwright show-trace trace.zip
Writing New Tests
1. Create a test file
// tests/e2e/feature/my-feature.spec.ts
import { test, expect } from '@playwright/test';
test.describe('My Feature', () => {
test('should do something', async ({ page }) => {
await page.goto('/my-feature');
await expect(page.getByText('Hello')).toBeVisible();
});
});
2. Use Page Objects (recommended)
import { MyFeaturePage } from '../../helpers/page-objects/MyFeaturePage';
test('should use page object', async ({ page }) => {
const myFeature = new MyFeaturePage(page);
await myFeature.goto();
await myFeature.doSomething();
await myFeature.expectSuccess();
});
3. Use test data generators
import { generateParkData } from '../../fixtures/test-data';
test('should create park', async ({ page }) => {
const parkData = generateParkData({ name: 'Custom Park' });
// Use parkData in your test
});
4. Clean up test data
import { cleanupTestData } from '../../fixtures/database';
test.afterAll(async () => {
await cleanupTestData();
});
Test Data Management
All test data is automatically marked with is_test_data: true and cleaned up after tests run.
Manual cleanup
If tests fail and leave data behind:
import { cleanupTestData } from './fixtures/database';
await cleanupTestData();
Or use the "Emergency Cleanup" button in the admin UI at /admin/settings.
Authentication
Tests use pre-authenticated browser contexts to avoid logging in for every test:
.auth/user.json- Regular user.auth/moderator.json- Moderator with AAL2.auth/admin.json- Admin with AAL2.auth/superuser.json- Superuser with AAL2
These are created automatically during global setup.
CI/CD Integration
Tests run automatically on GitHub Actions:
- On every pull request
- On push to main branch
- Results posted as PR comments
See .github/workflows/playwright.yml for configuration.
Best Practices
- Use Page Objects - Encapsulate page interactions
- Mark test data - Always set
is_test_data: true - Clean up - Use
test.afterAll()ortest.afterEach() - Use fixtures - Reuse auth, database, and test data helpers
- Test user flows - Not individual functions
- Avoid hardcoded waits - Use
waitForLoadState()orwaitForSelector() - Take screenshots - On failure (automatic)
- Parallelize - Tests run in parallel by default
Common Issues
"Service role key not configured"
Set the SUPABASE_SERVICE_ROLE_KEY environment variable.
"Test data not cleaned up"
Run npx playwright test --project=cleanup or use the admin UI emergency cleanup button.
"Lock timeout"
Some tests involving moderation locks may take longer. Increase timeout:
test('my slow test', async ({ page }) => {
test.setTimeout(120000); // 2 minutes
// ...
});
Resources
Support
For questions or issues with tests, check:
- This README
- Playwright docs
- Test failure screenshots/videos in
test-results/ - GitHub Actions logs for CI failures
- Grafana Cloud Loki for centralized test logs
Grafana Cloud Loki Integration
All test runs automatically send logs to Grafana Cloud Loki for centralized monitoring and analysis.
Viewing Logs in Grafana Cloud
- Access Grafana Cloud: Go to your Grafana Cloud instance
- Navigate to Explore: Click "Explore" in the left sidebar
- Select Loki Data Source: Choose your Loki data source from the dropdown
- Query Test Logs: Use LogQL queries to filter logs
Common LogQL Queries
# All Playwright test logs
{job="playwright_tests"}
# Logs for specific browser
{job="playwright_tests", browser="chromium"}
# Failed tests only
{job="playwright_tests", status="failed"}
# Tests from specific branch
{job="playwright_tests", branch="main"}
# Tests from specific GitHub run
{job="playwright_tests", run_id="1234567890"}
# Logs from specific test file
{job="playwright_tests"} |= "login.spec.ts"
# Failed tests with error messages
{job="playwright_tests", status="failed"} | json | line_format "{{.test_name}}: {{.error}}"
Local Testing with Grafana Cloud
Test your Grafana Cloud integration locally:
# Set environment variables
export GRAFANA_LOKI_URL="https://logs-prod-us-central1.grafana.net"
export GRAFANA_LOKI_USERNAME="123456" # Your instance ID
export GRAFANA_LOKI_PASSWORD="glc_xxxxxxxxxxxxx" # Your API key
# Run test script
chmod +x scripts/test-grafana-cloud.sh
./scripts/test-grafana-cloud.sh
# Run tests with Loki reporter
npx playwright test tests/e2e/auth/login.spec.ts --project=chromium
Required GitHub Secrets
For CI/CD integration, ensure these secrets are configured in your GitHub repository:
GRAFANA_LOKI_URL- Your Grafana Cloud Loki endpoint (e.g.,https://logs-prod-us-central1.grafana.net)GRAFANA_LOKI_USERNAME- Your Grafana Cloud instance IDGRAFANA_LOKI_PASSWORD- Your Grafana Cloud API key (starts withglc_)
Troubleshooting Grafana Cloud Connection
401 Unauthorized Error:
- Check your
GRAFANA_LOKI_USERNAME(should be your instance ID) - Verify your
GRAFANA_LOKI_PASSWORD(API key starting withglc_) - Regenerate API key if needed (Security > API Keys in Grafana Cloud)
Logs Not Appearing:
- Verify the correct region in
GRAFANA_LOKI_URL - Check time range in Grafana Explore (default is last 5 minutes)
- Run test script to validate connection:
./scripts/test-grafana-cloud.sh
429 Rate Limit Error:
- Reduce test concurrency in
playwright.config.ts - Increase
flushIntervalin Loki reporter options