fix(ci): integration tests + e2e workflows green again

Two unrelated root-causes were keeping the Integration tests and e2e
workflows red on every push to main since `d8c549e` (50+ runs).

1. Integration: `.github/workflows/integration.yml` had `ENCRYPTION_KEY:
   0000…` as a bare YAML scalar. YAML 1.2 parses a run of zeros as the
   integer 0 — so the runner exported `ENCRYPTION_KEY=0`, and
   `decodeKey()` rejected it as "must be hex (>= 32 chars) or base64
   (32 bytes)". 6 tests in admin-backups-* and integration-status
   failed at module load. Quoting the value forces a literal string.

2. e2e: the global-setup seeded user had `onboarding_tour_completed`
   left at its default `false`, so the spotlight tour mounted a
   full-viewport `role="dialog"` overlay (z-index 200) on every
   authenticated spec. Playwright's hit-test then caught the tour's
   skip-button instead of the intended target — every spec that
   clicked sidebar / quick-add / logo timed out. Setting the column
   to `true` in the upsert keeps the tour off the dashboard for the
   rest of the suite. The two `onboarding-flicker.spec.ts` mocks
   that fulfil `/api/auth/me` from inside the spec also need the
   field, since they replace the seeded payload.

Workflow change is comment + quoted strings only — no secrets, no
runtime cost.
This commit is contained in:
Marc-André Bombeck committed 2026-05-10 00:20:48 +02:00
1 parent 2611bb4fae
commit fbcd1062a5
3 files changed
+29 -7

No files matched your search

+9 -3
View File
@@ -29,6 +29,12 @@ jobs:
# The integration suite boots a Postgres testcontainer and points
# Prisma at it via DATABASE_URL set inside `tests/integration/setup.ts`.
# These env vars satisfy code paths that read them at module load.
API_TOKEN_HMAC_KEY: integration-tests-do-not-use-in-prod
ENCRYPTION_KEY: 0000000000000000000000000000000000000000000000000000000000000000
SESSION_SECRET: integration-tests
#
# ENCRYPTION_KEY MUST be quoted: YAML 1.2 parses an unquoted run of
# zeros as the integer 0, which then arrives in `process.env` as the
# string "0" — failing crypto's hex/base64 length check and breaking
# the backups + integration-status suites for 50+ runs (regression
# since v1.4.13). Quoting forces a literal scalar.
API_TOKEN_HMAC_KEY: "integration-tests-do-not-use-in-prod"
ENCRYPTION_KEY: "0000000000000000000000000000000000000000000000000000000000000000"
SESSION_SECRET: "integration-tests"
+6
View File
@@ -46,6 +46,7 @@ test.describe("dashboard onboarding card flicker guard", () => {
gender: "MALE",
timezone: "Europe/Berlin",
onboardingCompletedAt: "2025-01-01T00:00:00.000Z",
onboardingTourCompleted: true,
gravatarUrl: null,
glucoseUnit: "mg/dL",
},
@@ -138,6 +139,11 @@ test.describe("dashboard onboarding card flicker guard", () => {
gender: null,
timezone: "Europe/Berlin",
onboardingCompletedAt: null,
// Suppress the spotlight tour overlay during this spec so
// the onboarding-card visibility probe is not occluded by
// the tour's z-200 dialog. The tour itself is exercised by
// a dedicated spec — not in scope here.
onboardingTourCompleted: true,
gravatarUrl: null,
glucoseUnit: "mg/dL",
},
+14 -4
View File
@@ -89,7 +89,14 @@ export default async function globalSetup(config: FullConfig): Promise<void> {
// SET clause clears any leftover Codex / insights state from a
// previous run so the "Settings → AI" spec sees the disconnected
// baseline; we also stamp `onboarding_completed_at` so the auth
// shell does not bounce the user to /onboarding.
// shell does not bounce the user to /onboarding, AND set
// `onboarding_tour_completed = true` so the spotlight tour does
// NOT auto-launch on the dashboard. Without that flag the tour
// mounts a full-viewport `role="dialog"` overlay with `z-index:200`
// that intercepts every pointer event — every authenticated spec
// that tries to click a header / sidebar / quick-add button times
// out (50+ failed CI runs since v1.4.13). Specs that need the
// tour can opt back in by mocking `/api/auth/me`.
await pool.query(
`INSERT INTO users
(id, username, email, password_hash, role,
@@ -97,13 +104,15 @@ export default async function globalSetup(config: FullConfig): Promise<void> {
height_cm, date_of_birth, gender,
codex_connection_status,
insights_privacy_mode,
onboarding_completed_at)
onboarding_completed_at,
onboarding_tour_completed)
VALUES ($1, $2, $3, $4, $5,
$6, $6,
180, $7, 'MALE',
'disconnected',
'aggregated',
$6)
$6,
true)
ON CONFLICT (username) DO UPDATE SET
email = EXCLUDED.email,
password_hash = EXCLUDED.password_hash,
@@ -119,7 +128,8 @@ export default async function globalSetup(config: FullConfig): Promise<void> {
codex_connection_status = 'disconnected',
insights_cached_at = NULL,
insights_cached_text = NULL,
onboarding_completed_at = EXCLUDED.onboarding_completed_at`,
onboarding_completed_at = EXCLUDED.onboarding_completed_at,
onboarding_tour_completed = EXCLUDED.onboarding_tour_completed`,
[
cuid(),
E2E_USER.username,