Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ jobs:
name: Plugins
uses: ./.github/workflows/plugins.yml

e2e:
name: E2E
uses: ./.github/workflows/e2e.yml

all-checks:
name: All Checks Passed
runs-on: ubuntu-22.04
needs: [skit, ui, plugins]
needs: [skit, ui, plugins, e2e]
steps:
- name: All checks passed
run: echo "All CI checks passed successfully!"
82 changes: 82 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# SPDX-FileCopyrightText: © 2025 StreamKit Contributors
#
# SPDX-License-Identifier: MPL-2.0

name: E2E Tests

on:
workflow_call:

env:
CARGO_TERM_COLOR: always

jobs:
e2e:
name: Playwright E2E
runs-on: ubuntu-22.04
steps:
- name: Free disk space
uses: jlumbroso/free-disk-space@main
with:
tool-cache: false
android: true
dotnet: true
haskell: true
large-packages: false
docker-images: true
swap-storage: false

- uses: actions/checkout@v5

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.5"

- name: Build UI
working-directory: ./ui
run: |
bun install --frozen-lockfile
bun run build

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: "1.92.0"

- uses: Swatinem/rust-cache@v2

- name: Build skit (debug)
run: cargo build -p streamkit-server --bin skit

- name: Install E2E dependencies
working-directory: ./e2e
run: bun install --frozen-lockfile

- name: Install Playwright browsers
working-directory: ./e2e
run: bunx playwright install chromium --with-deps

- name: Lint E2E (typecheck + prettier)
working-directory: ./e2e
run: bun run lint

- name: Run E2E tests
working-directory: ./e2e
run: bun run test

- name: Upload Playwright report
uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: e2e/playwright-report/
retention-days: 7

- name: Upload test artifacts
uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-results
path: e2e/test-results/
retention-days: 7
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,8 @@ models
/examples/plugins/*/build/

demo/

# E2E test artifacts
e2e/test-results
e2e/playwright-report
e2e/.playwright
10 changes: 10 additions & 0 deletions e2e/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# SPDX-FileCopyrightText: © 2025 StreamKit Contributors
#
# SPDX-License-Identifier: MPL-2.0

node_modules
bun.lock
.playwright
playwright-report
test-results

133 changes: 133 additions & 0 deletions e2e/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<!-- SPDX-FileCopyrightText: © 2025 StreamKit Contributors -->
<!-- SPDX-License-Identifier: MPL-2.0 -->

# StreamKit E2E Tests

End-to-end tests for StreamKit using Playwright.

## Prerequisites

- Bun 1.3.5+
- Rust 1.92.0+ (for building skit)
- Built UI (`cd ui && bun install && bun run build` or `just build-ui`)
- Built skit binary (`cargo build -p streamkit-server --bin skit`)

## Quick Start

```bash
# Install dependencies and Playwright browsers
just install-e2e
just install-playwright

# Run tests (automatically starts server)
just e2e

# Or run directly from e2e directory
cd e2e
bun install
bunx playwright install chromium
bun run test
```

## Running Against External Server

If you already have a StreamKit server running:

```bash
E2E_BASE_URL=http://localhost:4545 bun run test:only

# Or via justfile
just e2e-external http://localhost:4545
```

## Running Against Vite Dev Server

To test against the Vite development server (useful for debugging UI changes):

```bash
# Terminal 1: Start skit backend
cargo run -p streamkit-server --bin skit -- serve

# Terminal 2: Start Vite dev server
cd ui && bun run dev

# Terminal 3: Run E2E tests against Vite
just e2e-external http://localhost:3045
```

The Vite dev server proxies `/api/*` and `/healthz` requests to the skit backend
(default `127.0.0.1:4545`). This is primarily for Playwright’s direct API calls when
`E2E_BASE_URL` points at the Vite server; the UI itself still talks directly to the backend
in development (via `import.meta.env.VITE_API_BASE`).

Both servers must be running for tests to pass.

## Test Structure

- `tests/design.spec.ts` - Design view tests (canvas, samples, YAML editor)
- `tests/monitor.spec.ts` - Monitor view tests (session lifecycle)

## Server Harness

When `E2E_BASE_URL` is not set, the test harness (`src/harness/run.ts`):

1. Finds a free port
2. Starts `target/debug/skit serve` with `SK_SERVER__ADDRESS=127.0.0.1:<port>`
3. Polls `/healthz` until server is ready (30s timeout)
4. Runs all Playwright tests
5. Stops the server

Environment variables set by harness:

- `SK_SERVER__ADDRESS` - Bind address
- `SK_LOG__FILE_ENABLE=false` - Disable file logging
- `RUST_LOG=warn` - Reduce log noise

## Scripts

| Script | Description |
| --------------------- | -------------------------------------------- |
| `bun run test` | Run tests with auto server management |
| `bun run test:only` | Run tests directly (requires `E2E_BASE_URL`) |
| `bun run test:headed` | Run tests with visible browser |
| `bun run test:ui` | Run tests with Playwright UI |
| `bun run report` | Show HTML test report |

## Debugging

```bash
# Run with debug mode (shows server output)
DEBUG=1 bun run test

# Run single test file
bun run test -- tests/design.spec.ts

# Run with trace viewer on failure
bun run test -- --trace on

# Run specific test by name
bun run test -- -g "loads with all main panes"
```

## CI

Tests run automatically in CI via `.github/workflows/e2e.yml`.
On failure, `playwright-report/` and `test-results/` are uploaded as artifacts.

## Adding New Tests

1. Create a new spec file in `tests/` directory
2. Use `data-testid` attributes for stable element selection
3. Prefer role/name selectors for accessible elements
4. Avoid arbitrary waits; use Playwright's built-in assertions

Example:

```typescript
import { test, expect } from '@playwright/test';

test('my new test', async ({ page }) => {
await page.goto('/my-route');
await expect(page.getByTestId('my-element')).toBeVisible();
});
```
29 changes: 29 additions & 0 deletions e2e/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions e2e/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "streamkit-e2e",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit",
"format": "../ui/node_modules/.bin/prettier --write . --config ../ui/.prettierrc.json --ignore-path ./.prettierignore",
"format:check": "../ui/node_modules/.bin/prettier --check . --config ../ui/.prettierrc.json --ignore-path ./.prettierignore",
"lint": "bun run typecheck && bun run format:check",
"test": "bun run src/harness/run.ts",
"test:only": "playwright test",
"test:ui": "playwright test --ui",
"test:headed": "bun run src/harness/run.ts -- --headed",
"report": "playwright show-report"
},
"devDependencies": {
"@playwright/test": "^1.49.0",
"@types/node": "^22.0.0",
"typescript": "~5.9.3"
}
}
43 changes: 43 additions & 0 deletions e2e/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: © 2025 StreamKit Contributors
//
// SPDX-License-Identifier: MPL-2.0

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

// E2E_BASE_URL is set by the harness runner (run.ts) or passed externally
const baseURL = process.env.E2E_BASE_URL;

if (!baseURL) {
throw new Error(
'E2E_BASE_URL environment variable is required. ' +
'Run tests via "bun run test" to auto-start the server, ' +
'or set E2E_BASE_URL manually for an external server.'
);
}

export default defineConfig({
testDir: './tests',
fullyParallel: false, // Run tests serially for shared server
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: 1, // Single worker for shared server state
reporter: process.env.CI ? [['html'], ['github']] : [['html']],
timeout: 30000,
expect: {
timeout: 10000,
},

use: {
baseURL,
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},

projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});
32 changes: 32 additions & 0 deletions e2e/src/harness/health.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: © 2025 StreamKit Contributors
//
// SPDX-License-Identifier: MPL-2.0

/**
* Wait for the server to become healthy by polling the /healthz endpoint.
*/
export async function waitForHealth(
baseUrl: string,
timeoutMs: number = 30000,
intervalMs: number = 500
): Promise<void> {
const deadline = Date.now() + timeoutMs;
const healthUrl = `${baseUrl}/healthz`;

while (Date.now() < deadline) {
try {
const response = await fetch(healthUrl);
if (response.ok) {
const data = (await response.json()) as { status?: string };
if (data.status === 'ok') {
return;
}
}
} catch {
// Server not ready yet, continue polling
}
await new Promise((resolve) => setTimeout(resolve, intervalMs));
}

throw new Error(`Server health check timed out after ${timeoutMs}ms`);
}
Loading
Loading