Acceptance Tests: run locally (AI runbook)¶
This document captures the exact, working setup used by AI on 2026-01-22 to run the Gherkin/Playwright acceptance tests locally against a locally running API + web app.
It exists so future AI (or humans) can re-run acceptance tests without rediscovering the same environment pitfalls.
Prerequisites¶
- Rancher Desktop installed (used to provide a Docker daemon on this machine).
- Docker Desktop was not available on this machine (
open -a Dockerfailed), so Rancher Desktop was used instead. - Node + pnpm installed.
- Verified on this machine:
node v24.3.0,pnpm 9.0.0. curl,ncavailable.- This repo checked out (Nx workspace).
High-level overview¶
- Start a Docker daemon (Rancher Desktop).
- Ensure Postgres exists and is reachable.
- Apply Prisma migrations to a dedicated schema (important workaround).
- Start API with required env vars (important: some webhook secrets are
getOrThrow()). - Start web (Vite) configured to call local API.
- Run acceptance tests (Playwright-BDD). The suite will:
- verify
/healthand the web URL - seed data through
/api/v1/test-seeding/* - run tests
- cleanup through
/api/v1/test-seeding/cleanup
1) Start Rancher Desktop (Docker daemon)¶
Start Rancher Desktop:
open -a "Rancher Desktop"
Wait until Docker is ready:
for i in $(seq 1 90); do
docker ps >/dev/null 2>&1 && echo "Docker is ready" && exit 0
sleep 2
done
echo "Docker did not become ready in time" && exit 1
2) PostgreSQL¶
Important note: database name vs schema¶
On this machine there was already a host Postgres reachable on localhost:5432 with a database named forma3d_connect.
When trying to use a separate database like forma3d_connect_test, Prisma commands failed with:
permission denied to create database- and/or
P1003: Database ... does not exist
To avoid needing CREATE DATABASE, we applied migrations into a separate schema inside the existing DB:
- DB:
forma3d_connect - schema:
forma3d_connect_test
This is the main “gotcha” that future runs should keep.
Optional: verify port is open¶
nc -zv 127.0.0.1 5432
If you need to run Postgres in Docker (fallback)¶
If you do not already have a working Postgres on localhost:5432, run one in Docker:
docker rm -f forma3d-connect-postgres >/dev/null 2>&1 || true
docker run -d \
--name forma3d-connect-postgres \
-e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=forma3d_connect \
-p 5432:5432 \
postgres:16
Wait until it’s ready:
for i in $(seq 1 60); do
docker exec forma3d-connect-postgres pg_isready -U postgres -h localhost >/dev/null 2>&1 && echo "Postgres is ready" && exit 0
sleep 1
done
echo "Postgres not ready" && exit 1
3) Prisma migrations (schema-based)¶
Run migrations into a dedicated schema:
export DATABASE_URL='postgresql://postgres@localhost:5432/forma3d_connect?schema=forma3d_connect_test'
pnpm prisma generate
pnpm prisma migrate deploy
Notes:
prisma migrate deployis used (same approach as CI), and it worked with the schema-basedDATABASE_URL.- The acceptance tests do their own test data seeding via API endpoints; you don’t need
pnpm prisma db seedfor acceptance tests.
4) Start the API locally¶
Critical env vars¶
The API uses ConfigService.getOrThrow() for some webhook secrets. Even if you don’t use these integrations locally, the app will crash without them.
This set worked:
export DATABASE_URL='postgresql://postgres@localhost:5432/forma3d_connect?schema=forma3d_connect_test'
export APP_PORT='3000'
export APP_URL='http://localhost:3000'
export FRONTEND_URL='http://localhost:4200'
export NODE_ENV='development'
export RATE_LIMIT_DISABLED='true'
# API key required (the API is fail-closed when INTERNAL_API_KEY is missing)
export INTERNAL_API_KEY='local-dev-key'
# Required due to getOrThrow() usage
export SIMPLYPRINT_WEBHOOK_SECRET='local-simplyprint-webhook-secret'
export SHOPIFY_WEBHOOK_SECRET='local-shopify-webhook-secret'
export SHOPIFY_SHOP_DOMAIN='example.myshopify.com'
export SHOPIFY_API_VERSION='2024-01'
export SHOPIFY_ACCESS_TOKEN='local-shopify-access-token'
Start command¶
In this run, starting the API via Nx had issues with “waiting for api:serve:development in another nx process”, so the built output was started directly:
node dist/apps/api/main.js
Verify it’s up:
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/health
Expected: 200
5) Start the web app locally (Vite)¶
Web runs on port 4200 (configured in apps/web/vite.config.mts).
export VITE_API_URL='http://localhost:3000'
pnpm nx dev web
Verify it’s up:
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:4200/
Expected: 200 (or another non-5xx response if the app serves HTML)
6) Run acceptance tests locally¶
The acceptance-tests Nx project defines a local configuration that targets:
STAGING_API_URL=http://localhost:3000STAGING_WEB_URL=http://localhost:4200
Run:
export STAGING_API_URL='http://localhost:3000'
export STAGING_WEB_URL='http://localhost:4200'
export INTERNAL_API_KEY='local-dev-key'
# Optional: force local-like behavior (no CI retries)
export CI=''
pnpm nx run acceptance-tests:test
Expected output ends with:
80 passed- global teardown cleanup via API
What “seeding” means in this context¶
Acceptance tests seed data in Playwright global setup (apps/acceptance-tests/src/support/global-setup.ts) by calling API endpoints:
GET /api/v1/test-seeding/statusDELETE /api/v1/test-seeding/cleanupPOST /api/v1/test-seeding/seed-all
So as long as the API is running and INTERNAL_API_KEY matches, test data will be created automatically before the suite starts.
Troubleshooting¶
API fails to start with “Configuration key ... does not exist”¶
This happens when a module/guard calls configService.getOrThrow(...).
Fix: set the missing env var(s). In this run, the minimum needed were:
SIMPLYPRINT_WEBHOOK_SECRETSHOPIFY_WEBHOOK_SECRETSHOPIFY_SHOP_DOMAINSHOPIFY_API_VERSIONSHOPIFY_ACCESS_TOKEN
Prisma migrate deploy fails with “permission denied to create database”¶
Avoid creating a database; use a schema in an existing DB instead:
export DATABASE_URL='postgresql://postgres@localhost:5432/forma3d_connect?schema=forma3d_connect_test'
pnpm prisma migrate deploy
Acceptance tests time out on Orders/Mappings UI elements¶
In this repo, most API endpoints are protected by the API key guard. The web app must include the API key for read calls too (orders/mappings/logs/dashboard/shipping).
If UI tests fail with missing rows/filters/search inputs while API tests pass, the likely cause is “web app is calling protected endpoints without X-API-Key”.
Quick “one shot” copy/paste (assuming Postgres already exists)¶
# 0) Docker (Rancher Desktop)
open -a "Rancher Desktop"
for i in $(seq 1 90); do docker ps >/dev/null 2>&1 && break; sleep 2; done
# 1) Prisma schema migrations
export DATABASE_URL='postgresql://postgres@localhost:5432/forma3d_connect?schema=forma3d_connect_test'
pnpm prisma generate
pnpm prisma migrate deploy
# 2) API
export APP_PORT='3000' APP_URL='http://localhost:3000' FRONTEND_URL='http://localhost:4200' NODE_ENV='development' RATE_LIMIT_DISABLED='true'
export INTERNAL_API_KEY='local-dev-key'
export SIMPLYPRINT_WEBHOOK_SECRET='local-simplyprint-webhook-secret'
export SHOPIFY_WEBHOOK_SECRET='local-shopify-webhook-secret' SHOPIFY_SHOP_DOMAIN='example.myshopify.com' SHOPIFY_API_VERSION='2024-01' SHOPIFY_ACCESS_TOKEN='local-shopify-access-token'
node dist/apps/api/main.js
# 3) Web (in another terminal)
export VITE_API_URL='http://localhost:3000'
pnpm nx dev web
# 4) Acceptance tests (in another terminal)
export STAGING_API_URL='http://localhost:3000' STAGING_WEB_URL='http://localhost:4200' INTERNAL_API_KEY='local-dev-key' CI=''
pnpm nx run acceptance-tests:test