69edee36fc
The backend job normally finishes in about 3 minutes — the last eight runs on main were 2.6 to 3.4 — but it is the only one that boots Postgres and runs the full integration suite, so it is the only one exposed to runner contention. The observed spread has reached 9.2 minutes against a 10-minute cap, and release PR #1088 was cancelled at 10.3 with every test in the log passing and jest still running. That failure mode is expensive out of proportion to how often it happens: a cancelled job is a red X on a branch that is actually green, so it costs a diagnosis and a re-run each time, and it lands on release PRs because those are the ones that run when everything else does. The cap is a runaway guard rather than a performance budget, so 20 buys real headroom over the worst run seen while still killing a genuinely hung suite well inside the hour GitHub would otherwise allow. frontend and ml keep 10: they finish in seconds and have never been close. Co-authored-by: Paul Nothaft <paul@MacStudio-von-Paul.local>
157 lines
5.9 KiB
YAML
157 lines
5.9 KiB
YAML
name: Tests
|
|
|
|
# Runs the backend Jest suite and the frontend Vitest suite on every PR.
|
|
# Both suites already exist and cover the CRM service layer (quoteService,
|
|
# contractService, invoiceService.*, customerHoursService, eventService.
|
|
# calendar) plus the photo / settings / OG / auth surface — wiring them
|
|
# into CI makes regressions visible at PR time instead of post-merge.
|
|
#
|
|
# Six backend suites are excluded via --testPathIgnorePatterns. They
|
|
# fail on `upstream/beta` too (pre-existing mock/infra issues, NOT CRM
|
|
# regressions). Excluding them here keeps CI green from day 1; revisit
|
|
# each individually as its own fix.
|
|
#
|
|
# Triggers on any change that could affect either suite. The backend
|
|
# job intentionally omits frontend paths and vice versa so unrelated
|
|
# PRs don't pay both build costs.
|
|
|
|
on:
|
|
push:
|
|
branches: [main, beta, stable]
|
|
pull_request:
|
|
branches: [main, beta, stable]
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
backend:
|
|
runs-on: ubuntu-latest
|
|
# 20, not 10. This job normally finishes in ~3 minutes, but it is the only
|
|
# one that boots Postgres and runs the full integration suite, so it is the
|
|
# only one exposed to runner contention — observed spread has reached 9.2
|
|
# minutes, and a release PR (#1088) was cancelled at 10.3 with every test
|
|
# passing and jest still running. A cancelled job reads as a red X on a
|
|
# green branch, which costs a re-run and a diagnosis every time it happens.
|
|
#
|
|
# The cap is a runaway guard, not a performance budget; 20 leaves real
|
|
# headroom over the worst observed run while still killing a hung suite
|
|
# well inside the hour GitHub would otherwise allow. frontend and ml keep
|
|
# 10 — they take seconds and have never come close.
|
|
timeout-minutes: 20
|
|
|
|
# The .picpeak restore suites gate their real-Postgres cases behind
|
|
# PICPEAK_PG_TEST_URL and `describe.skip` themselves out when it is
|
|
# unset — so until now they never ran here. That hid the half that
|
|
# matters: sequence resync, operator/role preservation across a
|
|
# cross-instance restore, and (with #1041) whether a SQLite-shaped
|
|
# row actually lands in Postgres with the right STORED VALUES rather
|
|
# than merely not throwing. Everything else in the suite still runs
|
|
# on SQLite; this service only un-gates those cases.
|
|
services:
|
|
postgres:
|
|
image: postgres:15-alpine
|
|
env:
|
|
POSTGRES_USER: picpeak
|
|
POSTGRES_PASSWORD: testpass
|
|
POSTGRES_DB: picpeak_test
|
|
options: >-
|
|
--health-cmd "pg_isready -U picpeak -d picpeak_test"
|
|
--health-interval 2s
|
|
--health-timeout 2s
|
|
--health-retries 30
|
|
ports:
|
|
- 5432:5432
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '22'
|
|
cache: 'npm'
|
|
cache-dependency-path: backend/package-lock.json
|
|
|
|
- name: Install backend deps
|
|
working-directory: ./backend
|
|
run: npm ci
|
|
|
|
- name: Run Jest suite
|
|
working-directory: ./backend
|
|
env:
|
|
# backupService tests would otherwise try a real S3 round-trip.
|
|
# The S3 path itself is covered separately by the integration
|
|
# suite when MinIO is provisioned.
|
|
SKIP_S3_TESTS: 'true'
|
|
# Un-gates the real-Postgres cases in the .picpeak restore suites
|
|
# (see the `services:` note above). Absent it they silently skip.
|
|
PICPEAK_PG_TEST_URL: 'postgres://picpeak:testpass@127.0.0.1:5432/picpeak_test'
|
|
run: |
|
|
# Excluded suites — fail on upstream/beta too, tracked
|
|
# separately as test-infra debt:
|
|
# adminSettings.logo — supertest fixture
|
|
# integration/adminPhotos.reference — supertest fixture
|
|
# integration/webhookDelivery — supertest fixture
|
|
# services/backupService.enhanced — knex mock chain
|
|
# routes/__tests__/adminAuth — supertest fixture
|
|
# (adminNotifications was excluded; #597 fix re-enables it.)
|
|
npx jest \
|
|
--testPathIgnorePatterns='/node_modules/|adminSettings\.logo\.test|integration/adminPhotos\.reference|integration/webhookDelivery|backupService\.enhanced|routes/__tests__/adminAuth' \
|
|
--ci
|
|
|
|
frontend:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '22'
|
|
cache: 'npm'
|
|
cache-dependency-path: frontend/package-lock.json
|
|
|
|
- name: Install frontend deps
|
|
working-directory: ./frontend
|
|
run: npm ci
|
|
|
|
- name: Run Vitest suite
|
|
working-directory: ./frontend
|
|
run: npm test -- --run
|
|
|
|
# Optional face-detection sidecar (#1074). Runs on every PR regardless of
|
|
# whether the feature is enabled anywhere — these tests need no model
|
|
# weights (they stub the pipeline out) and cover the auth boundary, the
|
|
# request guards and the alignment geometry, which is where a mistake is a
|
|
# security problem or a silent accuracy problem rather than a visible bug.
|
|
ml:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
# Matches ml/Dockerfile's base image, so a wheel that resolves here
|
|
# resolves in the image too.
|
|
python-version: '3.12'
|
|
cache: 'pip'
|
|
cache-dependency-path: ml/requirements.txt
|
|
|
|
- name: Install ml deps
|
|
working-directory: ./ml
|
|
run: pip install -r requirements.txt pytest httpx
|
|
|
|
- name: Run pytest suite
|
|
working-directory: ./ml
|
|
run: python -m pytest tests/ -q
|