mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 09:36:08 +00:00
fix(ci): make the suites run under node, and start MinIO as a step
Both failures were environment-specific and invisible locally. The vitest projects only ever ran under bun here, because the containers used for local runs have no node at all. On a GitHub runner the vitest bin's `#!/usr/bin/env node` shebang wins, and node's ESM resolver cannot resolve the extensionless 'next/server' that next-auth/lib/env.js imports, so all 17 api suites died with ERR_MODULE_NOT_FOUND. The next-auth inline rule that the unit project already carried is now declared at the root so every project inherits it. All three projects verified under node as well as bun. The e2e job could never start: a GitHub Actions `services:` block cannot pass a command to its container, and the MinIO entrypoint requires `server /data`, so the container printed its usage text and exited. MinIO now starts as a step with `docker run`, which means the job can no longer run inside a container, which in turn removes the reason the Playwright image was needed at all. The browser is installed on the runner instead, so the image tag no longer has to be kept in lockstep with the npm package.
This commit is contained in:
+48
-51
@@ -78,19 +78,13 @@ jobs:
|
||||
e2e:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [check]
|
||||
container:
|
||||
# Must stay pinned to the installed @playwright/test version, because the
|
||||
# image carries the matching browser build and Playwright refuses a
|
||||
# mismatched pair. Microsoft publishes the image a while after the npm
|
||||
# release, which is why package.json pins 1.61.1 rather than the newer
|
||||
# 1.62.0: no v1.62.0-noble image exists yet. Bump both together, and check
|
||||
# the tag is published first:
|
||||
# curl -sI https://mcr.microsoft.com/v2/playwright/manifests/v1.61.1-noble
|
||||
image: mcr.microsoft.com/playwright:v1.61.1-noble
|
||||
# Chromium needs a real /dev/shm in a container.
|
||||
options: --ipc=host
|
||||
# No --user override on purpose: the image has no bun, and installing one
|
||||
# needs root. The runner is ephemeral, so root-owned files do no harm.
|
||||
# Runs directly on the runner rather than in the Playwright container image.
|
||||
# Two reasons, both learned the hard way. MinIO cannot be a `services:` entry
|
||||
# (see the step that starts it below), and starting it as a step needs a
|
||||
# docker CLI, which a container job does not have. And the Playwright image
|
||||
# ships neither bun nor unzip, so bun had to be installed through npm and the
|
||||
# image tag had to be kept in lockstep with the npm package. Installing the
|
||||
# browser here costs about a minute and removes all of that.
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
@@ -98,32 +92,15 @@ jobs:
|
||||
POSTGRES_USER: openframe
|
||||
POSTGRES_PASSWORD: openframe
|
||||
POSTGRES_DB: openframe_test
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd "pg_isready -U openframe -d openframe_test"
|
||||
--health-interval 2s
|
||||
--health-timeout 3s
|
||||
--health-retries 30
|
||||
# Object storage for video-upload.spec.ts. The browser PUTs the file
|
||||
# straight at the presigned URL, so there is nothing to mock at that
|
||||
# boundary from inside a browser. Mirrors the minio-test service in
|
||||
# docker-compose.test.yml.
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
env:
|
||||
MINIO_ROOT_USER: openframe
|
||||
MINIO_ROOT_PASSWORD: openframe-test-secret
|
||||
# lib/r2.ts signs with `region: 'auto'`, so MinIO has to accept it.
|
||||
MINIO_REGION_NAME: auto
|
||||
options: >-
|
||||
--health-cmd "mc ready local"
|
||||
--health-interval 2s
|
||||
--health-timeout 3s
|
||||
--health-retries 30
|
||||
env:
|
||||
# This job runs inside a container, so it shares a network with its
|
||||
# services and reaches them by service name. No published ports are
|
||||
# involved, which is why there are no `ports:` blocks above.
|
||||
DATABASE_URL: postgresql://openframe:openframe@postgres:5432/openframe_test?schema=public
|
||||
DATABASE_URL: postgresql://openframe:openframe@localhost:5432/openframe_test?schema=public
|
||||
# The Playwright web server builds and starts the app, and `next build`
|
||||
# does not run with NODE_ENV=test, so it never picks up `.env.test`. These
|
||||
# values are therefore set on the job itself. Port 3100 matches
|
||||
@@ -149,40 +126,60 @@ jobs:
|
||||
OPENFRAME_REQUIRE_INVITE_CODE: 'true'
|
||||
INVITE_CODE: test-invite
|
||||
TRUSTED_PROXY_MODE: none
|
||||
# Direct video uploads, pointed at the MinIO service. Without these the
|
||||
# `Direct Upload` tab is not rendered and video-upload.spec.ts fails on its
|
||||
# first assertion rather than silently testing nothing.
|
||||
# Direct video uploads, pointed at the MinIO container started below.
|
||||
# Without these the `Direct Upload` tab is not rendered and
|
||||
# video-upload.spec.ts fails on its first assertion rather than silently
|
||||
# testing nothing. The browser PUTs the file straight at the presigned URL,
|
||||
# so the app and the browser have to agree on this host, and both run on
|
||||
# the runner.
|
||||
OPENFRAME_ENABLE_S3_VIDEO_UPLOADS: 'true'
|
||||
OPENFRAME_ENABLE_BUNNY_UPLOADS: 'false'
|
||||
R2_ENDPOINT: http://minio:9000
|
||||
R2_ENDPOINT: http://localhost:9000
|
||||
R2_ACCESS_KEY_ID: openframe
|
||||
R2_SECRET_ACCESS_KEY: openframe-test-secret
|
||||
R2_BUCKET_NAME: openframe-test
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install bun
|
||||
# oven-sh/setup-bun cannot be used inside this container: it unpacks a
|
||||
# zip archive and the Playwright image ships no unzip. It ships node and
|
||||
# npm, so npm installs the bun binary instead. bun is needed both for
|
||||
# `bun run test:e2e` and for the web server command in
|
||||
# playwright.config.ts.
|
||||
run: npm install --global bun
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun install
|
||||
- name: Create .env.test from the committed example
|
||||
run: |
|
||||
cp .env.test.example .env.test
|
||||
printf '\nDATABASE_URL=%s\n' "$DATABASE_URL" >> .env.test
|
||||
- name: Start MinIO
|
||||
# Not a `services:` entry, because a service block cannot pass a command
|
||||
# to the container and the MinIO entrypoint requires `server /data`.
|
||||
# Without arguments the container prints its usage text, exits, and the
|
||||
# job dies at "Failed to initialize container minio/minio:latest".
|
||||
run: |
|
||||
docker run -d --name minio -p 9000:9000 \
|
||||
-e MINIO_ROOT_USER="$R2_ACCESS_KEY_ID" \
|
||||
-e MINIO_ROOT_PASSWORD="$R2_SECRET_ACCESS_KEY" \
|
||||
-e MINIO_REGION_NAME=auto \
|
||||
minio/minio:latest server /data
|
||||
for _ in $(seq 1 60); do
|
||||
if curl -sf http://localhost:9000/minio/health/live >/dev/null; then
|
||||
echo 'minio is ready'
|
||||
exit 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
echo 'minio did not become ready within 60 seconds' >&2
|
||||
docker logs minio >&2
|
||||
exit 1
|
||||
- name: Create the MinIO bucket
|
||||
# Nothing at runtime creates it: ensureR2BucketExists() lives in
|
||||
# scripts/self-host-bootstrap.ts, not on the request path, so a missing
|
||||
# bucket would surface as a presigned PUT returning NoSuchBucket. The
|
||||
# Playwright image has no mc, so this goes through the same image the
|
||||
# service container uses.
|
||||
# bucket would surface as a presigned PUT returning NoSuchBucket.
|
||||
run: |
|
||||
curl -sSfL -o /usr/local/bin/mc https://dl.min.io/client/mc/release/linux-amd64/mc
|
||||
chmod +x /usr/local/bin/mc
|
||||
mc alias set ciminio "$R2_ENDPOINT" "$R2_ACCESS_KEY_ID" "$R2_SECRET_ACCESS_KEY"
|
||||
mc mb --ignore-existing "ciminio/$R2_BUCKET_NAME"
|
||||
curl -sSfL -o "$RUNNER_TEMP/mc" https://dl.min.io/client/mc/release/linux-amd64/mc
|
||||
chmod +x "$RUNNER_TEMP/mc"
|
||||
"$RUNNER_TEMP/mc" alias set ciminio "$R2_ENDPOINT" "$R2_ACCESS_KEY_ID" "$R2_SECRET_ACCESS_KEY"
|
||||
"$RUNNER_TEMP/mc" mb --ignore-existing "ciminio/$R2_BUCKET_NAME"
|
||||
- name: Install the Playwright browser
|
||||
# Only chromium: playwright.config.ts runs a desktop Chromium project and
|
||||
# a Pixel 7 project, and the mobile one is Chromium too.
|
||||
run: bunx playwright install --with-deps chromium
|
||||
# No `bun run test:db:bootstrap` step: tests/e2e/global-setup.ts calls the
|
||||
# same setup function before the web server starts, and also clears the
|
||||
# rate_limits table so a retry does not inherit a spent window.
|
||||
|
||||
+14
-10
@@ -5,6 +5,20 @@ import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
export default defineConfig({
|
||||
plugins: [tsconfigPaths()],
|
||||
test: {
|
||||
server: {
|
||||
deps: {
|
||||
// Anything reaching lib/auth.ts pulls in next-auth, whose lib/env.js imports
|
||||
// the extensionless specifier 'next/server'. Node's ESM resolver cannot
|
||||
// resolve that, so the module has to go through Vite's resolver instead of
|
||||
// being externalised. Bun resolves it either way, which is why this is easy
|
||||
// to miss: the containers used locally have no node at all, so vitest runs
|
||||
// under bun there, while on a GitHub runner the vitest bin's
|
||||
// `#!/usr/bin/env node` shebang wins and every suite that touches auth dies
|
||||
// with ERR_MODULE_NOT_FOUND. Declared at the root so all three projects
|
||||
// inherit it through `extends: true`.
|
||||
inline: [/next-auth/],
|
||||
},
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
extends: true,
|
||||
@@ -12,16 +26,6 @@ export default defineConfig({
|
||||
name: 'unit',
|
||||
environment: 'node',
|
||||
include: ['tests/unit/**/*.test.ts'],
|
||||
server: {
|
||||
deps: {
|
||||
// lib/auth.ts pulls in next-auth, whose lib/env.js imports
|
||||
// 'next/server'. Node's ESM resolver cannot resolve that extensionless
|
||||
// specifier, so the module has to go through Vite's resolver instead
|
||||
// of being externalised. Bun resolves it either way; this keeps the
|
||||
// suite runnable under plain Node too, which is how coverage runs.
|
||||
inline: [/next-auth/],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user