From 6b2079ef2c44b13d1079ad199574ed18563b8c0e Mon Sep 17 00:00:00 2001 From: Torben Sorensen Date: Mon, 5 Jan 2026 22:38:21 -0800 Subject: [PATCH] fix the dang integration tests --- src/tests/integration/admin.integration.test.ts | 10 +++++++--- src/tests/integration/ai.integration.test.ts | 11 +++++++---- src/tests/integration/auth.integration.test.ts | 11 +++++++---- src/tests/integration/budget.integration.test.ts | 11 +++++++---- .../flyer-processing.integration.test.ts | 9 ++++++--- src/tests/integration/flyer.integration.test.ts | 10 +++++++--- .../integration/gamification.integration.test.ts | 15 ++++++++------- .../integration/notification.integration.test.ts | 11 +++++++---- src/tests/integration/price.integration.test.ts | 11 +++++++---- .../integration/public.routes.integration.test.ts | 11 +++++++---- src/tests/integration/recipe.integration.test.ts | 9 ++++++--- src/tests/integration/server.integration.test.ts | 14 ++++++++++++-- src/tests/integration/system.integration.test.ts | 14 ++++++++++++-- src/tests/integration/user.integration.test.ts | 11 +++++++---- .../integration/user.routes.integration.test.ts | 11 +++++++---- src/tests/setup/integration-global-setup.ts | 8 +++++++- 16 files changed, 121 insertions(+), 56 deletions(-) diff --git a/src/tests/integration/admin.integration.test.ts b/src/tests/integration/admin.integration.test.ts index b458ced4..7caf9335 100644 --- a/src/tests/integration/admin.integration.test.ts +++ b/src/tests/integration/admin.integration.test.ts @@ -1,7 +1,6 @@ // src/tests/integration/admin.integration.test.ts -import { describe, it, expect, beforeAll, beforeEach, afterAll } from 'vitest'; +import { describe, it, expect, beforeAll, beforeEach, afterAll, vi } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; import { getPool } from '../../services/db/connection.db'; import type { UserProfile } from '../../types'; import { createAndLoginUser, TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers'; @@ -10,9 +9,9 @@ import { cleanupDb } from '../utils/cleanup'; /** * @vitest-environment node */ -const request = supertest(app); describe('Admin API Routes Integration Tests', () => { + let request: ReturnType; let adminToken: string; let adminUser: UserProfile; let regularUser: UserProfile; @@ -21,6 +20,10 @@ describe('Admin API Routes Integration Tests', () => { const createdStoreIds: number[] = []; beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + const app = (await import('../../../server')).default; + request = supertest(app); + // Create a fresh admin user and a regular user for this test suite // Using unique emails to prevent test pollution from other integration test files. ({ user: adminUser, token: adminToken } = await createAndLoginUser({ @@ -40,6 +43,7 @@ describe('Admin API Routes Integration Tests', () => { }); afterAll(async () => { + vi.unstubAllEnvs(); await cleanupDb({ userIds: createdUserIds, storeIds: createdStoreIds, diff --git a/src/tests/integration/ai.integration.test.ts b/src/tests/integration/ai.integration.test.ts index d26dc9a3..f95ec9c7 100644 --- a/src/tests/integration/ai.integration.test.ts +++ b/src/tests/integration/ai.integration.test.ts @@ -1,7 +1,6 @@ // src/tests/integration/ai.integration.test.ts -import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; import fs from 'node:fs/promises'; import path from 'path'; import { createAndLoginUser } from '../utils/testHelpers'; @@ -12,8 +11,6 @@ import { cleanupFiles } from '../utils/cleanupFiles'; * @vitest-environment node */ -const request = supertest(app); - interface TestGeolocationCoordinates { latitude: number; longitude: number; @@ -26,10 +23,15 @@ interface TestGeolocationCoordinates { } describe('AI API Routes Integration Tests', () => { + let request: ReturnType; let authToken: string; let testUserId: string; beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + const app = (await import('../../../server')).default; + request = supertest(app); + // Create and log in as a new user for authenticated tests. const { token, user } = await createAndLoginUser({ fullName: 'AI Tester', request }); authToken = token; @@ -37,6 +39,7 @@ describe('AI API Routes Integration Tests', () => { }); afterAll(async () => { + vi.unstubAllEnvs(); // 1. Clean up database records await cleanupDb({ userIds: [testUserId] }); diff --git a/src/tests/integration/auth.integration.test.ts b/src/tests/integration/auth.integration.test.ts index 7a0a7db3..970aecf1 100644 --- a/src/tests/integration/auth.integration.test.ts +++ b/src/tests/integration/auth.integration.test.ts @@ -1,7 +1,6 @@ // src/tests/integration/auth.integration.test.ts -import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; import { createAndLoginUser, TEST_PASSWORD } from '../utils/testHelpers'; import { cleanupDb } from '../utils/cleanup'; import type { UserProfile } from '../../types'; @@ -10,8 +9,6 @@ import type { UserProfile } from '../../types'; * @vitest-environment node */ -const request = supertest(app); - /** * These are integration tests that verify the authentication flow against a running backend server. * Make sure your Express server is running before executing these tests. @@ -19,11 +16,16 @@ const request = supertest(app); * To run only these tests: `vitest run src/tests/auth.integration.test.ts` */ describe('Authentication API Integration', () => { + let request: ReturnType; let testUserEmail: string; let testUser: UserProfile; const createdUserIds: string[] = []; beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + const app = (await import('../../../server')).default; + request = supertest(app); + // Use a unique email for this test suite to prevent collisions with other tests. const email = `auth-integration-test-${Date.now()}@example.com`; ({ user: testUser } = await createAndLoginUser({ email, fullName: 'Auth Test User', request })); @@ -32,6 +34,7 @@ describe('Authentication API Integration', () => { }); afterAll(async () => { + vi.unstubAllEnvs(); await cleanupDb({ userIds: createdUserIds }); }); diff --git a/src/tests/integration/budget.integration.test.ts b/src/tests/integration/budget.integration.test.ts index d3a2ec3f..36930962 100644 --- a/src/tests/integration/budget.integration.test.ts +++ b/src/tests/integration/budget.integration.test.ts @@ -1,7 +1,6 @@ // src/tests/integration/budget.integration.test.ts -import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; import { createAndLoginUser } from '../utils/testHelpers'; import { cleanupDb } from '../utils/cleanup'; import type { UserProfile, Budget } from '../../types'; @@ -11,9 +10,8 @@ import { getPool } from '../../services/db/connection.db'; * @vitest-environment node */ -const request = supertest(app); - describe('Budget API Routes Integration Tests', () => { + let request: ReturnType; let testUser: UserProfile; let authToken: string; let testBudget: Budget; @@ -21,6 +19,10 @@ describe('Budget API Routes Integration Tests', () => { const createdBudgetIds: number[] = []; beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + const app = (await import('../../../server')).default; + request = supertest(app); + // 1. Create a user for the tests const { user, token } = await createAndLoginUser({ email: `budget-user-${Date.now()}@example.com`, @@ -50,6 +52,7 @@ describe('Budget API Routes Integration Tests', () => { }); afterAll(async () => { + vi.unstubAllEnvs(); // Clean up all created resources await cleanupDb({ userIds: createdUserIds, diff --git a/src/tests/integration/flyer-processing.integration.test.ts b/src/tests/integration/flyer-processing.integration.test.ts index 69196553..8d857ca2 100644 --- a/src/tests/integration/flyer-processing.integration.test.ts +++ b/src/tests/integration/flyer-processing.integration.test.ts @@ -1,7 +1,6 @@ // src/tests/integration/flyer-processing.integration.test.ts import { describe, it, expect, beforeAll, afterAll, vi, beforeEach } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; import fs from 'node:fs/promises'; import path from 'path'; import * as db from '../../services/db/index.db'; @@ -22,8 +21,6 @@ import sharp from 'sharp'; * @vitest-environment node */ -const request = supertest(app); - const { mockExtractCoreData } = vi.hoisted(() => ({ mockExtractCoreData: vi.fn(), })); @@ -50,6 +47,7 @@ vi.mock('../../services/db/index.db', async (importOriginal) => { }); describe('Flyer Processing Background Job Integration Test', () => { + let request: ReturnType; const createdUserIds: string[] = []; const createdFlyerIds: number[] = []; const createdFilePaths: string[] = []; @@ -57,7 +55,12 @@ describe('Flyer Processing Background Job Integration Test', () => { beforeAll(async () => { // FIX: Stub FRONTEND_URL to ensure valid absolute URLs (http://...) are generated // for the database, satisfying the 'url_check' constraint. + // IMPORTANT: This must run BEFORE the app is imported so workers inherit the env var. vi.stubEnv('FRONTEND_URL', 'https://example.com'); + + const appModule = await import('../../../server'); + const app = appModule.default; + request = supertest(app); }); // FIX: Reset mocks before each test to ensure isolation. diff --git a/src/tests/integration/flyer.integration.test.ts b/src/tests/integration/flyer.integration.test.ts index c134599f..438caee9 100644 --- a/src/tests/integration/flyer.integration.test.ts +++ b/src/tests/integration/flyer.integration.test.ts @@ -1,8 +1,7 @@ // src/tests/integration/flyer.integration.test.ts -import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; import { getPool } from '../../services/db/connection.db'; -import app from '../../../server'; import type { Flyer, FlyerItem } from '../../types'; import { cleanupDb } from '../utils/cleanup'; import { TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers'; @@ -14,12 +13,16 @@ import { TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers'; describe('Public Flyer API Routes Integration Tests', () => { let flyers: Flyer[] = []; // Use a supertest instance for all requests in this file - const request = supertest(app); + let request: ReturnType; let testStoreId: number; let createdFlyerId: number; // Fetch flyers once before all tests in this suite to use in subsequent tests. beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + const app = (await import('../../../server')).default; + request = supertest(app); + // Ensure at least one flyer exists const storeRes = await getPool().query( `INSERT INTO public.stores (name) VALUES ('Integration Test Store') RETURNING store_id`, @@ -45,6 +48,7 @@ describe('Public Flyer API Routes Integration Tests', () => { }); afterAll(async () => { + vi.unstubAllEnvs(); // Clean up the test data created in beforeAll to prevent polluting the test database. await cleanupDb({ flyerIds: [createdFlyerId], diff --git a/src/tests/integration/gamification.integration.test.ts b/src/tests/integration/gamification.integration.test.ts index 75d41dad..e000a933 100644 --- a/src/tests/integration/gamification.integration.test.ts +++ b/src/tests/integration/gamification.integration.test.ts @@ -1,7 +1,6 @@ // src/tests/integration/gamification.integration.test.ts import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; import path from 'path'; import fs from 'node:fs/promises'; import { getPool } from '../../services/db/connection.db'; @@ -26,8 +25,6 @@ import { cleanupFiles } from '../utils/cleanupFiles'; * @vitest-environment node */ -const request = supertest(app); - const { mockExtractCoreData } = vi.hoisted(() => ({ mockExtractCoreData: vi.fn(), })); @@ -53,6 +50,7 @@ vi.mock('../../utils/imageProcessor', async () => { }); describe('Gamification Flow Integration Test', () => { + let request: ReturnType; let testUser: UserProfile; let authToken: string; const createdFlyerIds: number[] = []; @@ -60,6 +58,12 @@ describe('Gamification Flow Integration Test', () => { const createdStoreIds: number[] = []; beforeAll(async () => { + // Stub environment variables for URL generation in the background worker. + // This needs to be in beforeAll to ensure it's set before any code that might use it is imported. + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + const app = (await import('../../../server')).default; + request = supertest(app); + // Create a new user specifically for this test suite to ensure a clean slate. ({ user: testUser, token: authToken } = await createAndLoginUser({ email: `gamification-user-${Date.now()}@example.com`, @@ -67,10 +71,6 @@ describe('Gamification Flow Integration Test', () => { request, })); - // Stub environment variables for URL generation in the background worker. - // This needs to be in beforeAll to ensure it's set before any code that might use it is imported. - vi.stubEnv('FRONTEND_URL', 'https://example.com'); - // Setup default mock response for the AI service's extractCoreDataFromFlyerImage method. mockExtractCoreData.mockResolvedValue({ store_name: 'Gamification Test Store', @@ -90,6 +90,7 @@ describe('Gamification Flow Integration Test', () => { }); afterAll(async () => { + vi.unstubAllEnvs(); await cleanupDb({ userIds: testUser ? [testUser.user.user_id] : [], flyerIds: createdFlyerIds, diff --git a/src/tests/integration/notification.integration.test.ts b/src/tests/integration/notification.integration.test.ts index 53dd116c..51c69097 100644 --- a/src/tests/integration/notification.integration.test.ts +++ b/src/tests/integration/notification.integration.test.ts @@ -1,7 +1,6 @@ // src/tests/integration/notification.integration.test.ts -import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; import { createAndLoginUser } from '../utils/testHelpers'; import { cleanupDb } from '../utils/cleanup'; import type { UserProfile, Notification } from '../../types'; @@ -11,14 +10,17 @@ import { getPool } from '../../services/db/connection.db'; * @vitest-environment node */ -const request = supertest(app); - describe('Notification API Routes Integration Tests', () => { + let request: ReturnType; let testUser: UserProfile; let authToken: string; const createdUserIds: string[] = []; beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + const app = (await import('../../../server')).default; + request = supertest(app); + // 1. Create a user for the tests const { user, token } = await createAndLoginUser({ email: `notification-user-${Date.now()}@example.com`, @@ -46,6 +48,7 @@ describe('Notification API Routes Integration Tests', () => { }); afterAll(async () => { + vi.unstubAllEnvs(); // Notifications are deleted via CASCADE when the user is deleted. await cleanupDb({ userIds: createdUserIds, diff --git a/src/tests/integration/price.integration.test.ts b/src/tests/integration/price.integration.test.ts index 1a2b7310..41fe3485 100644 --- a/src/tests/integration/price.integration.test.ts +++ b/src/tests/integration/price.integration.test.ts @@ -1,7 +1,6 @@ // src/tests/integration/price.integration.test.ts -import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; import { getPool } from '../../services/db/connection.db'; import { TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers'; @@ -9,9 +8,8 @@ import { TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers'; * @vitest-environment node */ -const request = supertest(app); - describe('Price History API Integration Test (/api/price-history)', () => { + let request: ReturnType; let masterItemId: number; let storeId: number; let flyerId1: number; @@ -19,6 +17,10 @@ describe('Price History API Integration Test (/api/price-history)', () => { let flyerId3: number; beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + const app = (await import('../../../server')).default; + request = supertest(app); + const pool = getPool(); // 1. Create a master grocery item @@ -71,6 +73,7 @@ describe('Price History API Integration Test (/api/price-history)', () => { }); afterAll(async () => { + vi.unstubAllEnvs(); const pool = getPool(); // The CASCADE on the tables should handle flyer_items. // The delete on flyers cascades to flyer_items, which fires a trigger `recalculate_price_history_on_flyer_item_delete`. diff --git a/src/tests/integration/public.routes.integration.test.ts b/src/tests/integration/public.routes.integration.test.ts index 7755ba44..37ca5e06 100644 --- a/src/tests/integration/public.routes.integration.test.ts +++ b/src/tests/integration/public.routes.integration.test.ts @@ -1,7 +1,6 @@ // src/tests/integration/public.routes.integration.test.ts -import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; import type { Flyer, FlyerItem, @@ -20,16 +19,19 @@ import { createAndLoginUser, TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers'; * @vitest-environment node */ -const request = supertest(app); - describe('Public API Routes Integration Tests', () => { // Shared state for tests + let request: ReturnType; let testUser: UserProfile; let testRecipe: Recipe; let testFlyer: Flyer; let testStoreId: number; beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + const app = (await import('../../../server')).default; + request = supertest(app); + const pool = getPool(); // Create a user to own the recipe const userEmail = `public-routes-user-${Date.now()}@example.com`; @@ -77,6 +79,7 @@ describe('Public API Routes Integration Tests', () => { }); afterAll(async () => { + vi.unstubAllEnvs(); await cleanupDb({ userIds: testUser ? [testUser.user.user_id] : [], recipeIds: testRecipe ? [testRecipe.recipe_id] : [], diff --git a/src/tests/integration/recipe.integration.test.ts b/src/tests/integration/recipe.integration.test.ts index 21a24db4..824c3463 100644 --- a/src/tests/integration/recipe.integration.test.ts +++ b/src/tests/integration/recipe.integration.test.ts @@ -1,7 +1,6 @@ // src/tests/integration/recipe.integration.test.ts import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; import { createAndLoginUser } from '../utils/testHelpers'; import { cleanupDb } from '../utils/cleanup'; import type { UserProfile, Recipe, RecipeComment } from '../../types'; @@ -13,9 +12,8 @@ import { aiService } from '../../services/aiService.server'; * @vitest-environment node */ -const request = supertest(app); - describe('Recipe API Routes Integration Tests', () => { + let request: ReturnType; let testUser: UserProfile; let authToken: string; let testRecipe: Recipe; @@ -23,6 +21,10 @@ describe('Recipe API Routes Integration Tests', () => { const createdRecipeIds: number[] = []; beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + const app = (await import('../../../server')).default; + request = supertest(app); + // Create a user to own the recipe and perform authenticated actions const { user, token } = await createAndLoginUser({ email: `recipe-user-${Date.now()}@example.com`, @@ -48,6 +50,7 @@ describe('Recipe API Routes Integration Tests', () => { }); afterAll(async () => { + vi.unstubAllEnvs(); // Clean up all created resources await cleanupDb({ userIds: createdUserIds, diff --git a/src/tests/integration/server.integration.test.ts b/src/tests/integration/server.integration.test.ts index d804de38..dacc3ace 100644 --- a/src/tests/integration/server.integration.test.ts +++ b/src/tests/integration/server.integration.test.ts @@ -1,13 +1,23 @@ // src/tests/integration/server.integration.test.ts -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; /** * @vitest-environment node */ describe('Server Initialization Smoke Test', () => { + let app: any; + + beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + app = (await import('../../../server')).default; + }); + + afterAll(() => { + vi.unstubAllEnvs(); + }); + it('should import the server app without crashing', () => { // This test's primary purpose is to ensure that all top-level code in `server.ts` // can execute without throwing an error. This catches issues like syntax errors, diff --git a/src/tests/integration/system.integration.test.ts b/src/tests/integration/system.integration.test.ts index 3c642f28..16682e86 100644 --- a/src/tests/integration/system.integration.test.ts +++ b/src/tests/integration/system.integration.test.ts @@ -1,13 +1,23 @@ // src/tests/integration/system.integration.test.ts -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; /** * @vitest-environment node */ describe('System API Routes Integration Tests', () => { + let app: any; + + beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + app = (await import('../../../server')).default; + }); + + afterAll(() => { + vi.unstubAllEnvs(); + }); + describe('GET /api/system/pm2-status', () => { it('should return a status for PM2', async () => { const request = supertest(app); diff --git a/src/tests/integration/user.integration.test.ts b/src/tests/integration/user.integration.test.ts index 48dbb22e..4c813fa7 100644 --- a/src/tests/integration/user.integration.test.ts +++ b/src/tests/integration/user.integration.test.ts @@ -1,9 +1,8 @@ // src/tests/integration/user.integration.test.ts -import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; import path from 'path'; import fs from 'node:fs/promises'; -import app from '../../../server'; import { logger } from '../../services/logger.server'; import { getPool } from '../../services/db/connection.db'; import type { UserProfile, MasterGroceryItem, ShoppingList } from '../../types'; @@ -15,9 +14,8 @@ import { cleanupFiles } from '../utils/cleanupFiles'; * @vitest-environment node */ -const request = supertest(app); - describe('User API Routes Integration Tests', () => { + let request: ReturnType; let testUser: UserProfile; let authToken: string; const createdUserIds: string[] = []; @@ -25,6 +23,10 @@ describe('User API Routes Integration Tests', () => { // Before any tests run, create a new user and log them in. // The token will be used for all subsequent API calls in this test suite. beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + const app = (await import('../../../server')).default; + request = supertest(app); + const email = `user-test-${Date.now()}@example.com`; const { user, token } = await createAndLoginUser({ email, fullName: 'Test User', request }); testUser = user; @@ -35,6 +37,7 @@ describe('User API Routes Integration Tests', () => { // After all tests, clean up by deleting the created user. // This now cleans up ALL users created by this test suite to prevent pollution. afterAll(async () => { + vi.unstubAllEnvs(); await cleanupDb({ userIds: createdUserIds }); // Safeguard to clean up any avatar files created during tests. diff --git a/src/tests/integration/user.routes.integration.test.ts b/src/tests/integration/user.routes.integration.test.ts index e74dd9eb..625f81ed 100644 --- a/src/tests/integration/user.routes.integration.test.ts +++ b/src/tests/integration/user.routes.integration.test.ts @@ -1,7 +1,6 @@ // src/tests/integration/user.routes.integration.test.ts -import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import supertest from 'supertest'; -import app from '../../../server'; import type { UserProfile } from '../../types'; import { createAndLoginUser } from '../utils/testHelpers'; import { cleanupDb } from '../utils/cleanup'; @@ -10,15 +9,18 @@ import { cleanupDb } from '../utils/cleanup'; * @vitest-environment node */ -const request = supertest(app); - describe('User Routes Integration Tests (/api/users)', () => { + let request: ReturnType; let authToken = ''; let testUser: UserProfile; const createdUserIds: string[] = []; // Authenticate once before all tests in this suite to get a JWT. beforeAll(async () => { + vi.stubEnv('FRONTEND_URL', 'https://example.com'); + const app = (await import('../../../server')).default; + request = supertest(app); + // Use the helper to create and log in a user in one step. const { user, token } = await createAndLoginUser({ fullName: 'User Routes Test User', @@ -30,6 +32,7 @@ describe('User Routes Integration Tests (/api/users)', () => { }); afterAll(async () => { + vi.unstubAllEnvs(); await cleanupDb({ userIds: createdUserIds }); }); diff --git a/src/tests/setup/integration-global-setup.ts b/src/tests/setup/integration-global-setup.ts index 510387e1..a75456bf 100644 --- a/src/tests/setup/integration-global-setup.ts +++ b/src/tests/setup/integration-global-setup.ts @@ -1,7 +1,6 @@ // src/tests/setup/integration-global-setup.ts import { execSync } from 'child_process'; import type { Server } from 'http'; -import app from '../../../server'; // Import the Express app import { logger } from '../../services/logger.server'; import { getPool } from '../../services/db/connection.db'; @@ -13,6 +12,9 @@ let globalPool: ReturnType | null = null; export async function setup() { // Ensure we are in the correct environment for these tests. process.env.NODE_ENV = 'test'; + // Fix: Set the FRONTEND_URL globally for the test server instance + process.env.FRONTEND_URL = 'https://example.com'; + console.log(`\n--- [PID:${process.pid}] Running Integration Test GLOBAL Setup ---`); // The integration setup is now the single source of truth for preparing the test DB. @@ -30,6 +32,10 @@ export async function setup() { console.log(`[PID:${process.pid}] Initializing global database pool...`); globalPool = getPool(); + // Fix: Dynamic import AFTER env vars are set + const appModule = await import('../../../server'); + const app = appModule.default; + // Programmatically start the server within the same process. const port = process.env.PORT || 3001; await new Promise((resolve) => {