Skip to content

test: E2E

test: E2E #23

Workflow file for this run

name: CI
on:
push:
branches: [master, main]
pull_request:
branches: [master, main]
jobs:
lint-and-typecheck:
name: Lint & Typecheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
# Repo .npmrc sets `ignore-scripts=true` for local-dev safety. CI is a
# controlled environment and tsx/esbuild rely on the postinstall fallback
# to fetch the platform binary (`@esbuild/<os>-<arch>`) when optional-dep
# resolution doesn't pick it up — so we re-enable scripts here.
- name: Install dependencies
env:
npm_config_ignore_scripts: 'false'
run: npm install --legacy-peer-deps --include=optional
- name: Typecheck
run: npm run typecheck
- name: Build
run: npm run build
- name: Test (unit) + coverage
run: npm run test:coverage
- name: Upload unit coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-unit
path: coverage/lcov.info
if-no-files-found: warn
# Surfaces unused exports / orphaned files / unused deps. `--no-exit-code`
# so the report is informational; flip to required once the baseline
# is enforced.
- name: Knip (unused-code report)
run: npm run knip
# Production-only audit so we don't trip on devDependency-only CVEs that
# never ship to consumers. `high` level matches the publish-gate bar.
- name: npm audit (production deps)
run: npm run audit:prod
test-integration:
name: Integration Tests
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: multitenancy_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 5s
--health-timeout 5s
--health-retries 10
redis:
image: redis:7.0.5-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 10
# mock-oauth2-server publishes a wire-compliant OIDC discovery
# doc + JWKS + token endpoint. Used by
# tests/integration/services/sso_oidc_real.spec.ts to prove the
# package's SSO codepath interops with a real third-party OIDC
# implementation (not just the in-spec fake IdP that mirrors our
# assumptions). Skips silently when `MOCK_OIDC_BASE_URL` is unset.
# (MinIO can't run as a service container because GitHub Actions
# doesn't allow CMD overrides — see the `Start MinIO` step below.)
mock-oidc:
image: ghcr.io/navikt/mock-oauth2-server:2.1.10
ports:
- 8080:8080
env:
TZ: UTC
NODE_ENV: test
HOST: 127.0.0.1
PORT: 3333
APP_KEY: a-32-character-long-secret-key!!
LOG_LEVEL: error
TENANT_HEADER_KEY: x-tenant-id
DB_HOST: 127.0.0.1
DB_PORT: 5432
DB_USER: postgres
DB_PASSWORD: postgres
DB_DATABASE: multitenancy_test
REDIS_HOST: 127.0.0.1
REDIS_PORT: 6379
QUEUE_REDIS_HOST: 127.0.0.1
QUEUE_REDIS_PORT: 6379
QUEUE_REDIS_DB: 1
CACHE_REDIS_HOST: 127.0.0.1
CACHE_REDIS_PORT: 6379
CACHE_REDIS_DB: 2
# Optional: a Stripe *test-mode* key (sk_test_…). When set, the
# real-API smoke test (tests/integration/billing/stripe_real_smoke.spec.ts)
# runs and verifies every Stripe SDK call-site against the live test
# endpoint instead of MockStripe. When unset/empty the test reports
# itself skipped (visibly, not silently). Add it under
# Settings → Secrets and variables → Actions as STRIPE_TEST_API_KEY.
STRIPE_TEST_API_KEY: ${{ secrets.STRIPE_TEST_API_KEY }}
# Real S3-compatible store (MinIO running on localhost) — drives
# the BackupService S3 roundtrip spec. Removing these env vars
# makes the spec skip rather than fail.
BACKUP_S3_ENDPOINT: http://127.0.0.1:9000
BACKUP_S3_BUCKET: lasagna-test
BACKUP_S3_REGION: us-east-1
AWS_ACCESS_KEY_ID: minioadmin
AWS_SECRET_ACCESS_KEY: minioadmin
# Real OIDC server (mock-oauth2-server running as service
# container) — drives the SsoService interop spec. `default` is
# the issuer path mock-oauth2-server uses for unspecified
# issuers.
MOCK_OIDC_BASE_URL: http://127.0.0.1:8080/default
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
- name: Install dependencies
env:
npm_config_ignore_scripts: 'false'
run: npm install --legacy-peer-deps --include=optional
# GitHub Actions `services:` doesn't allow CMD overrides, so we
# can't put minio there directly — `minio/minio` boots into a
# `--help` listing without `server /data`. Run it as a regular
# docker container instead, then probe its readiness endpoint
# before the tests start.
- name: Start MinIO (S3-compatible)
run: |
docker run -d --rm --name lasagna-minio \
-p 9000:9000 \
-e MINIO_ROOT_USER=minioadmin \
-e MINIO_ROOT_PASSWORD=minioadmin \
minio/minio:latest server /data
for i in 1 2 3 4 5 6 7 8 9 10; do
if curl -fsS http://127.0.0.1:9000/minio/health/ready > /dev/null; then
echo "minio ready"; exit 0
fi
sleep 1
done
echo "minio failed to become ready"; docker logs lasagna-minio; exit 1
# mock-oauth2-server runs as a service container above. Probe its
# discovery doc to fail fast if the image changed its boot
# behaviour rather than letting individual specs hang.
- name: Probe mock-oauth2-server
run: |
for i in 1 2 3 4 5 6 7 8 9 10; do
if curl -fsS "$MOCK_OIDC_BASE_URL/.well-known/openid-configuration" > /dev/null; then
echo "mock-oidc ready"; exit 0
fi
sleep 1
done
echo "mock-oidc failed to become ready"; exit 1
- name: Test (integration) + coverage
run: npm run test:integration:coverage
- name: Upload integration coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-integration
path: coverage/lcov.info
if-no-files-found: warn
test-e2e-demo:
name: E2E (demo app)
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: app
POSTGRES_PASSWORD: app
POSTGRES_DB: lasagna_demo
ports:
- 55432:5432
options: >-
--health-cmd "pg_isready -U app -d lasagna_demo"
--health-interval 5s
--health-timeout 5s
--health-retries 10
redis:
image: redis:7-alpine
ports:
- 56379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 10
mailcatcher:
image: schickling/mailcatcher
ports:
- 1025:1025
- 1080:1080
env:
TZ: UTC
NODE_ENV: development
HOST: 127.0.0.1
PORT: 3333
APP_KEY: a-32-character-long-secret-key!!
LOG_LEVEL: error
TENANT_HEADER_KEY: x-tenant-id
APP_DOMAIN: localhost
DB_HOST: 127.0.0.1
DB_PORT: 55432
DB_USER: app
DB_PASSWORD: app
DB_DATABASE: lasagna_demo
REDIS_HOST: 127.0.0.1
REDIS_PORT: 56379
QUEUE_REDIS_HOST: 127.0.0.1
QUEUE_REDIS_PORT: 56379
QUEUE_REDIS_DB: 1
CACHE_REDIS_HOST: 127.0.0.1
CACHE_REDIS_PORT: 56379
CACHE_REDIS_DB: 2
BACKUP_STORAGE_PATH: ./storage/backups
DEMO_ADMIN_TOKEN: demo-admin-token-change-me
MAILCATCHER_HOST: 127.0.0.1
MAILCATCHER_PORT: 1025
MAIL_FROM_ADDRESS: demo@example.test
MAIL_FROM_NAME: Demo Multitenancy
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
# `pg_dump` / `pg_restore` / `psql` on PATH so backups_real.spec.ts +
# the import / clone tests run instead of skipping. The suite skips
# gracefully when these are absent, but we want them green in CI.
- name: Install postgresql-client
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends postgresql-client
- name: Install dependencies
env:
npm_config_ignore_scripts: 'false'
run: npm install --legacy-peer-deps --include=optional
# Demo's `@adonisjs-lasagna/saas-tenancy` is a workspace symlink that
# resolves through `build/`, so a fresh build is mandatory before the
# e2e suite imports from it.
- name: Build package
run: npm run build
- name: Backoffice setup (creates backoffice schema + tenants table)
working-directory: examples/api
run: npx tsx ace.ts backoffice:setup
- name: Run e2e suite
working-directory: examples/api
run: npx tsx ace.ts test e2e