-
Notifications
You must be signed in to change notification settings - Fork 0
Fix E2E chat test timeout: move E2E tests to local Docker pre-push workflow, add WebGPU/Vulkan support #68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1f213a4
ec23ac7
96b2b31
ba01c92
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| #!/usr/bin/env sh | ||
| . "$(dirname -- "$0")/_/husky.sh" | ||
|
|
||
| # Run Playwright E2E tests before pushing. | ||
| # Requires Docker (see e2e/run-local.sh). | ||
| # | ||
| # Skip when Docker is unavailable or for a quick push: | ||
| # git push --no-verify | ||
|
|
||
| if ! command -v docker > /dev/null 2>&1; then | ||
| echo "⚠ Docker not found — skipping E2E tests. Install Docker to enable local E2E." | ||
| exit 0 | ||
| fi | ||
|
|
||
| echo "▶ Running E2E tests before push (skip with: git push --no-verify)..." | ||
| bun run test:e2e:local |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # syntax=docker/dockerfile:1 | ||
| # | ||
| # E2E local test image for Q². | ||
| # | ||
| # Built on the official Playwright Ubuntu Jammy image — Chromium and all of | ||
| # its system-level dependencies are pre-installed and version-matched. | ||
| # Mesa Vulkan drivers are layered on top so that Chromium can use WebGPU via: | ||
| # • Intel ANV (Intel integrated / discrete GPU) | ||
| # • AMD RADV (AMD GPU via /dev/dri passthrough) | ||
| # • lavapipe (Mesa software Vulkan — unconditional fallback, no GPU needed) | ||
| # | ||
| # Build: docker build -t q2-e2e -f e2e/Dockerfile . | ||
| # Run: bun run test:e2e:local (or directly: ./e2e/run-local.sh) | ||
| # | ||
| # Update this tag when you bump @playwright/test in package.json. | ||
| # Available tags: https://mcr.microsoft.com/v2/playwright/tags/list | ||
| FROM mcr.microsoft.com/playwright:v1.50.1-jammy | ||
|
|
||
| # ── Vulkan support ──────────────────────────────────────────────────────── | ||
| # mesa-vulkan-drivers installs Intel ANV, AMD RADV, and lavapipe in one shot. | ||
| # libvulkan1 is the Vulkan loader (required by both drivers and Chromium). | ||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
| libvulkan1 \ | ||
| mesa-vulkan-drivers \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # ── Bun ─────────────────────────────────────────────────────────────────── | ||
| # Bun is the project's build tool and package manager. | ||
| RUN curl -fsSL https://bun.sh/install | bash | ||
| ENV PATH="/root/.bun/bin:$PATH" | ||
|
|
||
| WORKDIR /app | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -13,6 +13,7 @@ import { test, expect } from '@playwright/test'; | |||||||||
| test.setTimeout(480_000); | ||||||||||
|
|
||||||||||
| const MODEL_ID = process.env.E2E_MODEL ?? 'onnx-community/Qwen3.5-0.8B-ONNX'; | ||||||||||
| const MODEL_DTYPE = process.env.E2E_DTYPE ?? 'q4'; | ||||||||||
|
Comment on lines
15
to
+16
|
||||||||||
| const MODEL_ID = process.env.E2E_MODEL ?? 'onnx-community/Qwen3.5-0.8B-ONNX'; | |
| const MODEL_DTYPE = process.env.E2E_DTYPE ?? 'q4'; | |
| const MODEL_ID = process.env.E2E_MODEL || 'onnx-community/Qwen3.5-0.8B-ONNX'; | |
| const MODEL_DTYPE = process.env.E2E_DTYPE || 'q4'; |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,14 +7,15 @@ | |||||||||
| * ONNX Runtime WASM session, and the UI transitions to "ready". | ||||||||||
| * | ||||||||||
| * The default model is onnx-community/Qwen3.5-0.8B-ONNX (q4). Override with | ||||||||||
| * the E2E_MODEL environment variable for faster CI runs. | ||||||||||
| * the E2E_MODEL and E2E_DTYPE environment variables for faster CI runs. | ||||||||||
|
||||||||||
| * the E2E_MODEL and E2E_DTYPE environment variables for faster CI runs. | |
| * the E2E_MODEL and E2E_DTYPE environment variables for faster local runs. |
Copilot
AI
Mar 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue as in chat.spec.ts: using ?? here will not fall back when E2E_MODEL/E2E_DTYPE are present but empty (which the new Docker runner currently does). Use || (or normalize env vars) so empty values don’t break model selection.
| const MODEL_ID = process.env.E2E_MODEL ?? 'onnx-community/Qwen3.5-0.8B-ONNX'; | |
| const MODEL_DTYPE = process.env.E2E_DTYPE ?? 'q4'; | |
| const MODEL_ID = process.env.E2E_MODEL || 'onnx-community/Qwen3.5-0.8B-ONNX'; | |
| const MODEL_DTYPE = process.env.E2E_DTYPE || 'q4'; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,63 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Run Playwright E2E tests locally inside a Docker container. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # • Builds the q2-e2e Docker image on first run (one-time ~3 min). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # • Caches node_modules in a named Docker volume so subsequent bun installs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # are near-instant. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # • Passes /dev/dri to the container for Intel/AMD GPU acceleration when | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # available; falls back to Mesa lavapipe (software Vulkan) otherwise. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # • The pre-installed Playwright browsers in the image are reused — no | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # 200 MB chromium download on each run. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Usage: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ./e2e/run-local.sh | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # E2E_MODEL=onnx-community/SmolLM2-135M-Instruct E2E_DTYPE=q4 ./e2e/run-local.sh | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Rebuild the image after updating the Playwright version in package.json: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # docker build -t q2-e2e -f e2e/Dockerfile . | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IMAGE="q2-e2e:local" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NM_VOLUME="q2-e2e-node-modules" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ── Require Docker ──────────────────────────────────────────────────────── | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ! command -v docker > /dev/null 2>&1; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "✖ Docker is not installed or not in PATH." >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo " Install Docker Desktop: https://docs.docker.com/get-docker/" >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ── Build image if it does not exist yet ───────────────────────────────── | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ! docker image inspect "$IMAGE" > /dev/null 2>&1; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "▶ Building E2E Docker image (first-run setup — ~3 min)..." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docker build -t "$IMAGE" -f "$SCRIPT_DIR/Dockerfile" "$REPO_ROOT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ── GPU passthrough ─────────────────────────────────────────────────────── | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GPU_FLAGS=() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GPU_AVAILABLE="" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -d /dev/dri ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GPU_FLAGS+=(--device /dev/dri) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GPU_AVAILABLE="1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "▶ /dev/dri found — Intel/AMD GPU passthrough enabled (WebGPU)." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "▶ /dev/dri not found — using Mesa lavapipe (software Vulkan fallback)." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ── Run tests ───────────────────────────────────────────────────────────── | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "▶ Running E2E tests..." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exec docker run --rm \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --ipc=host \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ${GPU_FLAGS[@]+"${GPU_FLAGS[@]}"} \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -v "$REPO_ROOT:/app" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -v "$NM_VOLUME:/app/node_modules" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -w /app \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -e CI=true \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -e E2E_GPU_AVAILABLE="${E2E_GPU_AVAILABLE:-$GPU_AVAILABLE}" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -e E2E_MODEL="${E2E_MODEL:-}" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -e E2E_DTYPE="${E2E_DTYPE:-}" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+50
to
+61
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ── Run tests ───────────────────────────────────────────────────────────── | |
| echo "▶ Running E2E tests..." | |
| exec docker run --rm \ | |
| --ipc=host \ | |
| ${GPU_FLAGS[@]+"${GPU_FLAGS[@]}"} \ | |
| -v "$REPO_ROOT:/app" \ | |
| -v "$NM_VOLUME:/app/node_modules" \ | |
| -w /app \ | |
| -e CI=true \ | |
| -e E2E_GPU_AVAILABLE="${E2E_GPU_AVAILABLE:-$GPU_AVAILABLE}" \ | |
| -e E2E_MODEL="${E2E_MODEL:-}" \ | |
| -e E2E_DTYPE="${E2E_DTYPE:-}" \ | |
| # ── Optional E2E env flags ──────────────────────────────────────────────── | |
| E2E_FLAGS=() | |
| if [ -n "${E2E_MODEL:-}" ]; then | |
| E2E_FLAGS+=(-e "E2E_MODEL=$E2E_MODEL") | |
| fi | |
| if [ -n "${E2E_DTYPE:-}" ]; then | |
| E2E_FLAGS+=(-e "E2E_DTYPE=$E2E_DTYPE") | |
| fi | |
| # ── Run tests ───────────────────────────────────────────────────────────── | |
| echo "▶ Running E2E tests..." | |
| exec docker run --rm \ | |
| --ipc=host \ | |
| ${GPU_FLAGS[@]+"${GPU_FLAGS[@]}"} \ | |
| ${E2E_FLAGS[@]+"${E2E_FLAGS[@]}"} \ | |
| -v "$REPO_ROOT:/app" \ | |
| -v "$NM_VOLUME:/app/node_modules" \ | |
| -w /app \ | |
| -e CI=true \ | |
| -e E2E_GPU_AVAILABLE="${E2E_GPU_AVAILABLE:-$GPU_AVAILABLE}" \ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,30 @@ import { defineConfig } from '@playwright/test'; | |
| * Serves the built application via a lightweight static server and runs real | ||
| * browser tests against it — no mocks, no fakes, no fake DOM. | ||
| */ | ||
|
|
||
| /** | ||
| * Chromium launch args for WebGPU support. | ||
| * | ||
| * Local Docker runs (e2e/run-local.sh): | ||
| * /dev/dri is passed to the container for Intel/AMD GPU access. The run | ||
| * script sets E2E_GPU_AVAILABLE=1 automatically when /dev/dri is present, | ||
| * which drops --use-gl=swiftshader and lets Chromium use hardware Vulkan | ||
| * (Intel ANV / AMD RADV). | ||
| * | ||
| * Without GPU (lavapipe fallback): | ||
| * --use-gl=swiftshader forces the Mesa software Vulkan rasterizer. | ||
| * WebGPU still works; inference falls back to WASM. | ||
|
Comment on lines
+19
to
+21
|
||
| */ | ||
| const gpuArgs = [ | ||
| '--enable-gpu', | ||
| '--ignore-gpu-blocklist', | ||
| '--enable-unsafe-webgpu', | ||
| '--disable-gpu-sandbox', | ||
| // Use SwiftShader (software GL) when no GPU is available. | ||
| // Dropped when E2E_GPU_AVAILABLE=1 (set by run-local.sh on /dev/dri systems). | ||
| ...( process.env.E2E_GPU_AVAILABLE ? [] : ['--use-gl=swiftshader'] ), | ||
| ]; | ||
|
|
||
| export default defineConfig({ | ||
| testDir: './e2e', | ||
| outputDir: './e2e-results', | ||
|
|
@@ -27,6 +51,12 @@ export default defineConfig({ | |
| screenshot: 'on', | ||
| trace: 'retain-on-failure', | ||
| headless: true, | ||
| /* Enable WebGPU and hardware-acceleration hints. | ||
| * On systems with Intel/AMD GPU: hardware Vulkan via /dev/dri passthrough. | ||
| * Without GPU: Mesa lavapipe (software Vulkan) via SwiftShader flag. */ | ||
| launchOptions: { | ||
| args: gpuArgs, | ||
| }, | ||
| }, | ||
|
|
||
| projects: [ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Playwright base image version (
v1.50.1-jammy) is far behind the repo’s@playwright/testversion (currently^1.58.2). Version mismatches between the runner and the preinstalled browsers/drivers can cause flaky or broken E2E runs. Update the image tag to match the Playwright version used by the repo (and consider pinningplaywright/@playwright/testconsistently).