fix(tests): raise migration-boot hook timeout pins to the 120s default (#900)

The 3.97.0-beta.0 release PR (#899) failed its backend Tests job on
slideshowPublic.test.js: bootCrmDb's full migration chain crossed the
suite's explicit 30s beforeAll timeout argument on a slow runner. #860
raised the config default and the jest.setTimeout pins to 120s, but
hook-ARGUMENT pins override the config default and were left behind —
same time-bomb, different syntax.

Every beforeAll that boots the migration chain and pinned 30s/60s is
raised to 120000 (16 suites). Untouched on purpose: the three suites
whose pinned hooks don't run migrations (webhookDelivery,
imageProcessor.storage, storageBackend) and publicQuotes' 30s pin on
the rate-limit lockout test — neither grows with the migration chain.

No test logic changed.

Co-authored-by: Paul Nothaft <paul@MacStudio-von-Paul.local>
This commit is contained in:
Paul Nothaft
2026-07-29 12:38:26 +02:00
committed by GitHub
parent 564e816bec
commit d9ad982373
16 changed files with 21 additions and 21 deletions
@@ -21,7 +21,7 @@ beforeAll(async () => {
({ db, cleanup, tmpDir } = await bootCrmDb());
process.env.STORAGE_PATH = tmpDir; // isolate file collection to the temp dir
({ createPicpeak } = require('../../src/services/picpeakExportService'));
}, 60000);
}, 120000);
afterAll(async () => {
await cleanup();
@@ -28,7 +28,7 @@ beforeAll(async () => {
({ importFromPicpeak, validateManifest } = require('../../src/services/picpeakImportService'));
const role = await db('roles').where({ name: 'super_admin' }).first();
superAdminRoleId = role.id;
}, 60000);
}, 120000);
afterAll(async () => {
await cleanup();
@@ -20,7 +20,7 @@ let cleanup;
beforeAll(async () => {
({ db, cleanup } = await bootCrmDb());
}, 60000);
}, 120000);
afterAll(async () => {
if (cleanup) await cleanup();
@@ -27,7 +27,7 @@ beforeAll(async () => {
setupService = require('../../src/services/setupService');
({ getAppSetting, upsertAppSetting } = require('../../src/utils/appSettings'));
app = buildRouteApp('/api/setup', require('../../src/routes/setup'));
}, 60000);
}, 120000);
afterAll(async () => {
await cleanup();
@@ -83,7 +83,7 @@ describe('admin CRM routes — auth + permission gate', () => {
// Invalid: signed with a different secret. adminAuth must reject.
const jwt = require('jsonwebtoken');
invalidToken = jwt.sign({ id: adminId, type: 'admin' }, 'WRONG-SECRET', { issuer: 'picpeak-auth' });
}, 60000);
}, 120000);
afterAll(async () => {
if (cleanup) await cleanup();
@@ -105,7 +105,7 @@ describe('admin event QR endpoints', () => {
expect(res.status).toBe(200);
expect(res.headers['content-type']).toBe('application/pdf');
expect(res.body.slice(0, 4).toString()).toBe('%PDF');
}, 30000);
}, 120000);
it('409s when the event has no share link', async () => {
// events.share_link is NOT NULL — an empty string is the closest real-world
+1 -1
View File
@@ -95,7 +95,7 @@ beforeAll(async () => {
({ db, cleanup } = await bootCrmDb());
adminApp = buildRouteApp('/api/admin/auth', require('../../src/routes/adminAuth'));
authApp = buildRouteApp('/api/auth', require('../../src/routes/auth'));
}, 60000);
}, 120000);
afterAll(async () => {
if (cleanup) await cleanup();
@@ -51,7 +51,7 @@ describe('publicContracts routes', () => {
contractId = inserted[0]?.id ?? inserted[0];
app = buildRouteApp('/api/public/contracts', require('../../src/routes/publicContracts'));
}, 60000);
}, 120000);
afterAll(async () => {
if (cleanup) await cleanup();
@@ -33,7 +33,7 @@ describe('publicPaymentCheck routes', () => {
({ db, cleanup } = await bootCrmDb());
await seedMinimal(db);
app = buildRouteApp('/api/public/payment-check', require('../../src/routes/publicPaymentCheck'));
}, 60000);
}, 120000);
afterAll(async () => {
if (cleanup) await cleanup();
@@ -60,7 +60,7 @@ describe('publicQuotes routes', () => {
quoteId = inserted[0]?.id ?? inserted[0];
app = buildRouteApp('/api/public/quotes', require('../../src/routes/publicQuotes'));
}, 60000);
}, 120000);
afterAll(async () => {
if (cleanup) await cleanup();
@@ -75,7 +75,7 @@ describe('admin Live Slideshow endpoints', () => {
app.use((err, req, res, next) => {
res.status(err.statusCode || err.status || 500).json({ error: err.message, code: err.code });
});
}, 30000);
}, 120000);
afterAll(async () => { await cleanup(); });
@@ -67,11 +67,11 @@ async function insertEvent(db, over = {}) {
describe('public Live Slideshow routes', () => {
let db; let cleanup; let app;
// bootCrmDb runs the full migration set against a fresh SQLite file, which
// takes <2s locally but has been observed to exceed Jest's default 5s
// `beforeAll` timeout on slower GitHub Actions runners (~5.4s — runner-to-
// runner I/O variance). Raise the hook timeout so this doesn't intermittently
// block PRs on CI; doesn't affect happy-path local runs.
// bootCrmDb runs the full migration set against a fresh SQLite file. The
// chain keeps growing, and a 30s pin here blocked the 3.97.0-beta.0
// release PR on a slow runner. Hook-argument timeouts OVERRIDE the 120s
// jest.config default (same trap as the jest.setTimeout pins raised in
// #860) — keep this at 120000, matching the config.
beforeAll(async () => {
({ db, cleanup } = await bootCrmDb());
await seedMinimal(db);
@@ -86,7 +86,7 @@ describe('public Live Slideshow routes', () => {
app.use((err, req, res, next) => {
res.status(err.statusCode || err.status || 500).json({ error: err.message, code: err.code });
});
}, 30000);
}, 120000);
afterAll(async () => { await cleanup(); });
@@ -27,7 +27,7 @@ let db; let cleanup;
beforeAll(async () => {
({ db, cleanup } = await bootCrmDb());
}, 30000);
}, 120000);
afterAll(async () => { if (cleanup) await cleanup(); });
@@ -48,7 +48,7 @@ describe('userManagementService — activate + delete (#574 follow-up)', () => {
is_active: 1, created_at: new Date(),
}).returning('id');
targetId = targetInsert[0]?.id ?? targetInsert[0];
}, 60000);
}, 120000);
afterAll(async () => {
if (cleanup) await cleanup();
@@ -115,7 +115,7 @@ beforeAll(async () => {
}).returning('id');
photoIds.push(r[0]?.id ?? r[0]);
}
}, 30000);
}, 120000);
afterAll(async () => { if (cleanup) await cleanup(); });
@@ -87,7 +87,7 @@ beforeAll(async () => {
uploaded_at: new Date().toISOString(),
}).returning('id');
photoId = r[0]?.id ?? r[0];
}, 30000);
}, 120000);
afterAll(async () => { if (cleanup) await cleanup(); });