Skip to content

Commit 7cdfad4

Browse files
committed
Set up Playwright E2E testing framework with CI integration
- Add Playwright configuration with OAuth mocking for GitHub auth - Create reusable GitHub Actions workflow for E2E tests - Add basic smoke tests as a starting point - Configure test infrastructure with fixtures and helpers Add required environment variables to Playwright CI workflow The server requires several environment variables to start up. Added fake/test values for all required env vars so the server can start during E2E tests.
1 parent 5f9489f commit 7cdfad4

File tree

9 files changed

+395
-1
lines changed

9 files changed

+395
-1
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
name: Playwright Tests
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
environment:
7+
description: 'Environment to run tests against'
8+
required: false
9+
type: string
10+
default: 'test'
11+
push:
12+
branches:
13+
- main
14+
pull_request:
15+
types: [opened, synchronize]
16+
17+
env:
18+
DATABASE_URL: postgres://postgres:postgres@localhost:5432/coreyja_test
19+
APP_BASE_URL: http://localhost:3000
20+
SQLX_OFFLINE: true
21+
# Required environment variables for app startup (using test/fake values)
22+
OPEN_AI_API_KEY: test-openai-api-key
23+
ANTHROPIC_API_KEY: test-anthropic-api-key
24+
GITHUB_APP_ID: 123456
25+
GITHUB_APP_CLIENT_ID: test-github-client-id
26+
GITHUB_APP_CLIENT_SECRET: test-github-client-secret
27+
GITHUB_PERSONAL_ACCESS_TOKEN: test-github-pat
28+
GITHUB_APP_PRIVATE_KEY: |
29+
-----BEGIN RSA PRIVATE KEY-----
30+
MIIEowIBAAKCAQEA0Z3VS0JJcds3xg
31+
-----END RSA PRIVATE KEY-----
32+
TWITCH_CLIENT_ID: test-twitch-client-id
33+
TWITCH_CLIENT_SECRET: test-twitch-client-secret
34+
TWITCH_BOT_USER_ID: 123456789
35+
TWITCH_CHANNEL_USER_ID: 987654321
36+
ENCRYPTION_SECRET_KEY: test-encryption-secret-key-32-bytes-long!
37+
GOOGLE_CLIENT_ID: test-google-client-id
38+
GOOGLE_CLIENT_SECRET: test-google-client-secret
39+
DISCORD_TOKEN: test-discord-token
40+
COOKIE_KEY: test-cookie-key-32-bytes-long!!!!
41+
42+
jobs:
43+
playwright:
44+
name: E2E Tests
45+
runs-on: ubuntu-latest
46+
timeout-minutes: 30
47+
48+
services:
49+
postgres:
50+
image: postgres:15
51+
env:
52+
POSTGRES_DB: coreyja_test
53+
POSTGRES_PASSWORD: postgres
54+
options: >-
55+
--health-cmd pg_isready
56+
--health-interval 10s
57+
--health-timeout 5s
58+
--health-retries 5
59+
ports:
60+
- 5432:5432
61+
62+
steps:
63+
- name: Checkout
64+
uses: actions/checkout@v4
65+
66+
- name: Setup Node.js
67+
uses: actions/setup-node@v4
68+
with:
69+
node-version: "20"
70+
cache: "npm"
71+
cache-dependency-path: |
72+
thread-frontend/package-lock.json
73+
e2e/package-lock.json
74+
75+
- name: Setup Rust
76+
uses: actions-rust-lang/setup-rust-toolchain@v1
77+
with:
78+
toolchain: stable
79+
80+
- name: Cache Rust dependencies
81+
uses: Swatinem/rust-cache@v2
82+
83+
- name: Install system dependencies
84+
uses: awalsh128/cache-apt-pkgs-action@latest
85+
with:
86+
packages: protobuf-compiler libasound2-dev
87+
version: v0
88+
89+
- name: Install Tailwind CSS
90+
run: |
91+
curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 && \
92+
chmod +x tailwindcss-linux-x64 && \
93+
mv tailwindcss-linux-x64 tailwindcss && \
94+
./tailwindcss -i server/src/styles/tailwind.css -o target/tailwind.css
95+
96+
- name: Install frontend dependencies
97+
run: |
98+
cd thread-frontend
99+
npm ci
100+
101+
- name: Build frontend
102+
run: ./scripts/build-frontend.sh
103+
104+
- name: Run database migrations
105+
run: |
106+
cargo install sqlx-cli --no-default-features --features postgres || true
107+
sqlx migrate run --source db/migrations
108+
109+
- name: Build server (debug mode for speed)
110+
run: cargo build --bin server
111+
112+
- name: Install Playwright dependencies
113+
run: |
114+
cd e2e
115+
npm ci
116+
117+
- name: Install Playwright browsers
118+
run: |
119+
cd e2e
120+
npx playwright install --with-deps chromium
121+
122+
- name: Run Playwright tests
123+
run: |
124+
cd e2e
125+
npx playwright test
126+
env:
127+
CI: true
128+
129+
- name: Upload Playwright report
130+
uses: actions/upload-artifact@v4
131+
if: always()
132+
with:
133+
name: playwright-report
134+
path: e2e/playwright-report/
135+
retention-days: 30
136+
137+
- name: Upload test results
138+
uses: actions/upload-artifact@v4
139+
if: always()
140+
with:
141+
name: test-results
142+
path: e2e/test-results/
143+
retention-days: 30

e2e/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules/
2+
playwright-report/
3+
test-results/
4+
.DS_Store
5+
*.log

e2e/auth/github-oauth-mock.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Page } from '@playwright/test';
2+
3+
export interface MockUser {
4+
login: string;
5+
node_id: string;
6+
id: number;
7+
email: string;
8+
name: string;
9+
}
10+
11+
export async function setupGitHubOAuthMock(page: Page, user: MockUser) {
12+
// Intercept GitHub OAuth authorization
13+
await page.route('https://github.com/login/oauth/authorize**', async route => {
14+
const url = new URL(route.request().url());
15+
const redirectUri = url.searchParams.get('redirect_uri');
16+
const state = url.searchParams.get('state');
17+
18+
// Immediately redirect back with mock code
19+
await route.fulfill({
20+
status: 302,
21+
headers: {
22+
'Location': `${redirectUri}?code=mock_code_${Date.now()}&state=${state}`
23+
}
24+
});
25+
});
26+
27+
// Mock token exchange
28+
await page.route('https://github.com/login/oauth/access_token', async route => {
29+
await route.fulfill({
30+
status: 200,
31+
contentType: 'application/json',
32+
body: JSON.stringify({
33+
access_token: `mock_token_${Date.now()}`,
34+
expires_in: 28800,
35+
refresh_token: `mock_refresh_${Date.now()}`,
36+
refresh_token_expires_in: 15897600,
37+
scope: 'read:user user:email',
38+
token_type: 'bearer'
39+
})
40+
});
41+
});
42+
43+
// Mock user API
44+
await page.route('https://api.github.com/user', async route => {
45+
await route.fulfill({
46+
status: 200,
47+
contentType: 'application/json',
48+
body: JSON.stringify(user)
49+
});
50+
});
51+
}

e2e/fixtures/test-users.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export const testUsers = {
2+
admin: {
3+
login: 'test_admin',
4+
node_id: 'MDQ6VXNlcjE=',
5+
id: 1,
6+
7+
name: 'Test Admin'
8+
},
9+
regular: {
10+
login: 'test_user',
11+
node_id: 'MDQ6VXNlcjI=',
12+
id: 2,
13+
14+
name: 'Test User'
15+
}
16+
};

e2e/package-lock.json

Lines changed: 97 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

e2e/package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "e2e",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"directories": {
6+
"test": "tests"
7+
},
8+
"scripts": {
9+
"test": "playwright test",
10+
"test:ui": "playwright test --ui",
11+
"test:debug": "playwright test --debug",
12+
"test:headed": "playwright test --headed",
13+
"test:report": "playwright show-report"
14+
},
15+
"keywords": [],
16+
"author": "",
17+
"license": "ISC",
18+
"description": "",
19+
"devDependencies": {
20+
"@playwright/test": "^1.54.2",
21+
"@types/node": "^24.2.1"
22+
}
23+
}

e2e/playwright.config.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { defineConfig, devices } from '@playwright/test';
2+
3+
export default defineConfig({
4+
testDir: './tests',
5+
timeout: 30000,
6+
fullyParallel: true,
7+
forbidOnly: !!process.env.CI,
8+
retries: process.env.CI ? 2 : 0,
9+
workers: process.env.CI ? 1 : undefined,
10+
reporter: 'html',
11+
12+
use: {
13+
baseURL: 'http://localhost:3000',
14+
trace: 'on-first-retry',
15+
screenshot: 'only-on-failure',
16+
},
17+
18+
projects: [
19+
{
20+
name: 'chromium',
21+
use: { ...devices['Desktop Chrome'] },
22+
},
23+
],
24+
25+
webServer: {
26+
command: process.env.CI
27+
? 'cd .. && ./target/debug/server'
28+
: 'cd .. && ./scripts/dev-build.sh && ./target/debug/server',
29+
port: 3000,
30+
reuseExistingServer: !process.env.CI,
31+
timeout: 120000,
32+
stdout: 'pipe',
33+
stderr: 'pipe',
34+
},
35+
});

0 commit comments

Comments
 (0)