mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix(server): close the notification-send teardown race in tests
This commit is contained in:
@@ -74,6 +74,10 @@ beforeAll(async () => {
|
||||
nestApp = await buildApp();
|
||||
app = nestApp.getHttpAdapter().getInstance();
|
||||
if (!fs.existsSync(uploadsDir)) fs.mkdirSync(uploadsDir, { recursive: true });
|
||||
// Warm the notificationService module: notifyCollab does a fire-and-forget
|
||||
// dynamic import of it, and a cold load can otherwise race the worker
|
||||
// teardown ("Cannot load ... after the environment was torn down").
|
||||
await import('../../src/services/notificationService');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -58,6 +58,10 @@ beforeAll(async () => {
|
||||
runMigrations(testDb);
|
||||
nestApp = await buildApp();
|
||||
app = nestApp.getHttpAdapter().getInstance();
|
||||
// Warm the notificationService module: notifyTagged does a fire-and-forget
|
||||
// dynamic import of it, and a cold load can otherwise race the worker
|
||||
// teardown ("Cannot load ... after the environment was torn down").
|
||||
await import('../../src/services/notificationService');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -67,6 +67,10 @@ beforeAll(async () => {
|
||||
runMigrations(testDb);
|
||||
nestApp = await buildApp();
|
||||
app = nestApp.getHttpAdapter().getInstance();
|
||||
// Warm the notificationService module: notifyInvite does a fire-and-forget
|
||||
// dynamic import of it, and a cold load can otherwise race the worker
|
||||
// teardown ("Cannot load ... after the environment was torn down").
|
||||
await import('../../src/services/notificationService');
|
||||
});
|
||||
beforeEach(() => {
|
||||
resetTestDb(testDb);
|
||||
|
||||
@@ -75,6 +75,10 @@ beforeAll(async () => {
|
||||
runMigrations(testDb);
|
||||
nestApp = await buildApp();
|
||||
app = nestApp.getHttpAdapter().getInstance();
|
||||
// Warm the notificationService module: sendInvite/shareCalendar do a
|
||||
// fire-and-forget dynamic import of it, and a cold load can otherwise race
|
||||
// the worker teardown ("Cannot load ... after the environment was torn down").
|
||||
await import('../../src/services/notificationService');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
+17
-1
@@ -1,9 +1,25 @@
|
||||
// Global test setup — runs before every test file.
|
||||
// Environment variables must be set before any module import so that
|
||||
// config.ts, database.ts, etc. pick them up at import time.
|
||||
// config.ts, database.ts, etc. pick them up at import time. (Importing from
|
||||
// 'vitest' itself is safe: it is externalized and pulls in no app modules.)
|
||||
import { afterEach } from 'vitest';
|
||||
|
||||
// Fixed encryption key (64 hex chars = 32 bytes) for at-rest crypto in tests
|
||||
process.env.ENCRYPTION_KEY = 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2';
|
||||
process.env.NODE_ENV = 'test';
|
||||
process.env.COOKIE_SECURE = 'false';
|
||||
process.env.LOG_LEVEL = 'error'; // suppress info/debug logs in test output
|
||||
|
||||
// Several services fire notification sends as unawaited dynamic-import chains
|
||||
// (`import('…/notificationService').then(({ send }) => send(…).catch(…))`).
|
||||
// Give those chains one macrotask turn to settle after every test, while the
|
||||
// suite's DB and the worker environment are still alive — otherwise the last
|
||||
// test in a file can leave the chain pending into worker teardown ("Cannot
|
||||
// load ... after the environment was torn down"). Under the default "stack"
|
||||
// hook order this afterEach runs after each test's own afterEach and before
|
||||
// the suite's afterAll, i.e. before any afterAll closes its test DB.
|
||||
// setImmediate is captured up front because some suites install fake timers.
|
||||
const realSetImmediate = globalThis.setImmediate;
|
||||
afterEach(async () => {
|
||||
await new Promise((resolve) => realSetImmediate(resolve));
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeAll, beforeEach } from 'vitest';
|
||||
|
||||
const { dbMock } = vi.hoisted(() => {
|
||||
const stmt = { get: vi.fn(() => ({ id: 42 })), all: vi.fn(() => []), run: vi.fn() };
|
||||
@@ -12,6 +12,8 @@ import type { PermissionsService } from '../../../src/nest/permissions/permissio
|
||||
|
||||
const { broadcast } = vi.hoisted(() => ({ broadcast: vi.fn() }));
|
||||
vi.mock('../../../src/websocket', () => ({ broadcast }));
|
||||
// notifyInvite fires a notification via a dynamic import — keep it out of unit scope
|
||||
vi.mock('../../../src/services/notificationService', () => ({ send: vi.fn().mockResolvedValue(undefined) }));
|
||||
const checkPermission = vi.fn(() => true);
|
||||
const permissionsStub = { checkPermission } as unknown as PermissionsService;
|
||||
|
||||
@@ -48,6 +50,12 @@ const reservationsStub = { list: () => [] } as unknown as ReservationsService;
|
||||
const daysStub = { list: () => ({ days: [1] }), listAccommodations: () => [] } as unknown as DaysService;
|
||||
function svc() { return new TripsService(new DatabaseService(dbConn), todoStub, packingStub, filesStub, reservationsStub, daysStub, permissionsStub, budgetStub); }
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
beforeAll(async () => {
|
||||
// Warm the (mocked) notificationService module: notifyInvite does a
|
||||
// fire-and-forget dynamic import of it, and a cold load can otherwise race
|
||||
// the worker teardown ("Cannot load ... after the environment was torn down").
|
||||
await import('../../../src/services/notificationService');
|
||||
});
|
||||
|
||||
describe('TripsService (wrapper delegation + bundle/copy/notify helpers)', () => {
|
||||
it('delegates the simple wrappers to tripService', async () => {
|
||||
|
||||
Reference in New Issue
Block a user