Files
qqq-frontend-next/scripts/e2e-server.mjs
T
james.maes 604c44c7b9 ci: run the mocked e2e suite, src/lib coverage and Storybook on every PR (#709)
- .github/workflows/ci.yml: three parallel jobs on pull_request and
  pushes to main/develop, none needing a backend:
  unit (typecheck, lint, test:coverage), e2e (pnpm build, then the
  mocked Playwright suite against the standalone server, chromium) and
  storybook (build-storybook).
- Mocked e2e reliability:
  - saved-views.spec mocked /qqq/v1/processes/<name>/init with a JSON
    `values` field, but the app posts saved-view processes to the
    registered route (/processes/<name>/init) with one multipart field
    per value, so three tests saw no views. The mocks now match the
    real request.
  - playwright.config: QQQ_E2E_SERVER=production serves the `pnpm build`
    standalone output (scripts/e2e-server.mjs) instead of compiling
    routes on first hit; QQQ_E2E_PORT picks the port; retries 0 so a
    flaky test fails instead of passing on retry; trace kept on failure.
  - 104/104 pass; 520/520 with --repeat-each=5 --workers=4.
- vitest.config: coverage thresholds for src/lib just under the measured
  82.8/75.65/89.87/84.42 (statements/branches/functions/lines), and
  higher per-folder floors for src/lib/api and src/lib/utils.
- Storybook: silence Rollup's per-module "use client" directive and
  sourcemap-location warnings (100 lines per build).
- playwright-report/index.html and test-results/.last-run.json were
  committed despite being ignored; untracked.
2026-09-25 16:55:07 -05:00

28 lines
1.3 KiB
JavaScript

/*
* Copyright 2026 QRun.IO, Inc.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0
*/
// Serves the production standalone build (`pnpm build`) for the mocked e2e suite. No backend
// runs: the specs answer every API call with page.route mocks (tests/e2e/api-mocks.ts).
import { spawn } from 'node:child_process'
import { cpSync, existsSync } from 'node:fs'
import path from 'node:path'
const standalone = path.resolve('.next/standalone')
if (!existsSync(path.join(standalone, 'server.js'))) {
console.error('No standalone build in .next/standalone; run `pnpm build` first.')
process.exit(1)
}
cpSync(path.resolve('.next/static'), path.join(standalone, '.next/static'), { recursive: true })
cpSync(path.resolve('public'), path.join(standalone, 'public'), { recursive: true })
const server = spawn('node', ['server.js'], {
cwd: standalone,
stdio: 'inherit',
env: { ...process.env, NODE_ENV: 'production', HOSTNAME: '127.0.0.1', PORT: process.env.QQQ_E2E_PORT ?? '3000' },
})
for (const signal of ['SIGINT', 'SIGTERM']) process.on(signal, () => server.kill('SIGTERM'))
server.on('exit', (code) => process.exit(code ?? 1))