Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
207ebf64f3 | ||
|
|
7ff191314c |
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "flyer-crawler",
|
"name": "flyer-crawler",
|
||||||
"version": "0.9.42",
|
"version": "0.9.39",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "flyer-crawler",
|
"name": "flyer-crawler",
|
||||||
"version": "0.9.42",
|
"version": "0.9.39",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bull-board/api": "^6.14.2",
|
"@bull-board/api": "^6.14.2",
|
||||||
"@bull-board/express": "^6.14.2",
|
"@bull-board/express": "^6.14.2",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "flyer-crawler",
|
"name": "flyer-crawler",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.9.42",
|
"version": "0.9.39",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "concurrently \"npm:start:dev\" \"vite\"",
|
"dev": "concurrently \"npm:start:dev\" \"vite\"",
|
||||||
|
|||||||
@@ -523,7 +523,7 @@ CREATE TABLE IF NOT EXISTS public.recipes (
|
|||||||
updated_at TIMESTAMPTZ DEFAULT now() NOT NULL,
|
updated_at TIMESTAMPTZ DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT recipes_name_check CHECK (TRIM(name) <> '')
|
CONSTRAINT recipes_name_check CHECK (TRIM(name) <> '')
|
||||||
);
|
);
|
||||||
-- CONSTRAINT recipes_photo_url_check CHECK (photo_url IS NULL OR photo_url ~* '^https://?.*')
|
-- CONSTRAINT recipes_photo_url_check CHECK (photo_url IS NULL OR photo_url ~* '^https://?.*')
|
||||||
COMMENT ON TABLE public.recipes IS 'Stores recipes that can be used to generate shopping lists.';
|
COMMENT ON TABLE public.recipes IS 'Stores recipes that can be used to generate shopping lists.';
|
||||||
COMMENT ON COLUMN public.recipes.servings IS 'The number of servings this recipe yields.';
|
COMMENT ON COLUMN public.recipes.servings IS 'The number of servings this recipe yields.';
|
||||||
COMMENT ON COLUMN public.recipes.original_recipe_id IS 'If this recipe is a variation of another, this points to the original.';
|
COMMENT ON COLUMN public.recipes.original_recipe_id IS 'If this recipe is a variation of another, this points to the original.';
|
||||||
|
|||||||
@@ -1056,7 +1056,7 @@ describe('AI Service (Server)', () => {
|
|||||||
// Default success mocks. Use createMockFlyer for a more complete mock.
|
// Default success mocks. Use createMockFlyer for a more complete mock.
|
||||||
vi.mocked(dbModule.flyerRepo.findFlyerByChecksum).mockResolvedValue(undefined);
|
vi.mocked(dbModule.flyerRepo.findFlyerByChecksum).mockResolvedValue(undefined);
|
||||||
vi.mocked(processAndSaveImage).mockResolvedValue('processed.jpg');
|
vi.mocked(processAndSaveImage).mockResolvedValue('processed.jpg');
|
||||||
vi.mocked(generateFlyerIcon).mockResolvedValue('https://example.com/icon.jpg');
|
vi.mocked(generateFlyerIcon).mockResolvedValue('icon.jpg');
|
||||||
vi.mocked(createFlyerAndItems).mockResolvedValue({
|
vi.mocked(createFlyerAndItems).mockResolvedValue({
|
||||||
flyer: {
|
flyer: {
|
||||||
flyer_id: 100,
|
flyer_id: 100,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ describe('FlyerDataTransformer', () => {
|
|||||||
vi.stubEnv('PORT', ''); // Ensure this is not used
|
vi.stubEnv('PORT', ''); // Ensure this is not used
|
||||||
|
|
||||||
// Provide a default mock implementation for generateFlyerIcon
|
// Provide a default mock implementation for generateFlyerIcon
|
||||||
vi.mocked(generateFlyerIcon).mockResolvedValue('https://example.com/icon-flyer-page-1.webp');
|
vi.mocked(generateFlyerIcon).mockResolvedValue('icon-flyer-page-1.webp');
|
||||||
vi.mocked(getBaseUrl).mockReturnValue('https://example.com');
|
vi.mocked(getBaseUrl).mockReturnValue('https://example.com');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ describe('FlyerDataTransformer', () => {
|
|||||||
const checksum = 'checksum-def-456';
|
const checksum = 'checksum-def-456';
|
||||||
// No userId provided
|
// No userId provided
|
||||||
|
|
||||||
vi.mocked(generateFlyerIcon).mockResolvedValue('https://example.com/icon-another.webp');
|
vi.mocked(generateFlyerIcon).mockResolvedValue('icon-another.webp');
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const { flyerData, itemsForDb } = await transformer.transform(
|
const { flyerData, itemsForDb } = await transformer.transform(
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ describe('FlyerProcessingService', () => {
|
|||||||
vi.mocked(mockedDb.personalizationRepo.getAllMasterItems).mockResolvedValue([]);
|
vi.mocked(mockedDb.personalizationRepo.getAllMasterItems).mockResolvedValue([]);
|
||||||
});
|
});
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.mocked(generateFlyerIcon).mockResolvedValue('https://example.com/icon-flyer.webp');
|
vi.mocked(generateFlyerIcon).mockResolvedValue('icon-flyer.webp');
|
||||||
});
|
});
|
||||||
|
|
||||||
const createMockJob = (data: Partial<FlyerJobData>): Job<FlyerJobData> => {
|
const createMockJob = (data: Partial<FlyerJobData>): Job<FlyerJobData> => {
|
||||||
@@ -217,7 +217,7 @@ describe('FlyerProcessingService', () => {
|
|||||||
imagePaths: [{ path: '/tmp/flyer-processed.jpeg', mimetype: 'image/jpeg' }],
|
imagePaths: [{ path: '/tmp/flyer-processed.jpeg', mimetype: 'image/jpeg' }],
|
||||||
createdImagePaths: ['/tmp/flyer-processed.jpeg'],
|
createdImagePaths: ['/tmp/flyer-processed.jpeg'],
|
||||||
});
|
});
|
||||||
vi.mocked(generateFlyerIcon).mockResolvedValue('https://example.com/icon-flyer.webp');
|
vi.mocked(generateFlyerIcon).mockResolvedValue('icon-flyer.webp');
|
||||||
|
|
||||||
const result = await service.processJob(job);
|
const result = await service.processJob(job);
|
||||||
|
|
||||||
@@ -276,7 +276,7 @@ describe('FlyerProcessingService', () => {
|
|||||||
],
|
],
|
||||||
createdImagePaths: createdPaths,
|
createdImagePaths: createdPaths,
|
||||||
});
|
});
|
||||||
vi.mocked(generateFlyerIcon).mockResolvedValue('https://example.com/icon-flyer-1.webp');
|
vi.mocked(generateFlyerIcon).mockResolvedValue('icon-flyer-1.webp');
|
||||||
|
|
||||||
await service.processJob(job);
|
await service.processJob(job);
|
||||||
|
|
||||||
@@ -429,7 +429,7 @@ describe('FlyerProcessingService', () => {
|
|||||||
imagePaths: [{ path: convertedPath, mimetype: 'image/png' }],
|
imagePaths: [{ path: convertedPath, mimetype: 'image/png' }],
|
||||||
createdImagePaths: [convertedPath],
|
createdImagePaths: [convertedPath],
|
||||||
});
|
});
|
||||||
vi.mocked(generateFlyerIcon).mockResolvedValue('https://example.com/icon-flyer-converted.webp');
|
vi.mocked(generateFlyerIcon).mockResolvedValue('icon-flyer-converted.webp');
|
||||||
|
|
||||||
await service.processJob(job);
|
await service.processJob(job);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/tests/integration/admin.integration.test.ts
|
// src/tests/integration/admin.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, beforeEach, afterAll, vi } from 'vitest';
|
import { describe, it, expect, beforeAll, beforeEach, afterAll } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
import { getPool } from '../../services/db/connection.db';
|
import { getPool } from '../../services/db/connection.db';
|
||||||
import type { UserProfile } from '../../types';
|
import type { UserProfile } from '../../types';
|
||||||
import { createAndLoginUser, TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers';
|
import { createAndLoginUser, TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers';
|
||||||
@@ -9,9 +10,9 @@ import { cleanupDb } from '../utils/cleanup';
|
|||||||
/**
|
/**
|
||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
const request = supertest(app);
|
||||||
|
|
||||||
describe('Admin API Routes Integration Tests', () => {
|
describe('Admin API Routes Integration Tests', () => {
|
||||||
let request: ReturnType<typeof supertest>;
|
|
||||||
let adminToken: string;
|
let adminToken: string;
|
||||||
let adminUser: UserProfile;
|
let adminUser: UserProfile;
|
||||||
let regularUser: UserProfile;
|
let regularUser: UserProfile;
|
||||||
@@ -20,10 +21,6 @@ describe('Admin API Routes Integration Tests', () => {
|
|||||||
const createdStoreIds: number[] = [];
|
const createdStoreIds: number[] = [];
|
||||||
|
|
||||||
beforeAll(async () => {
|
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
|
// 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.
|
// Using unique emails to prevent test pollution from other integration test files.
|
||||||
({ user: adminUser, token: adminToken } = await createAndLoginUser({
|
({ user: adminUser, token: adminToken } = await createAndLoginUser({
|
||||||
@@ -43,7 +40,6 @@ describe('Admin API Routes Integration Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
vi.unstubAllEnvs();
|
|
||||||
await cleanupDb({
|
await cleanupDb({
|
||||||
userIds: createdUserIds,
|
userIds: createdUserIds,
|
||||||
storeIds: createdStoreIds,
|
storeIds: createdStoreIds,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/tests/integration/ai.integration.test.ts
|
// src/tests/integration/ai.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { createAndLoginUser } from '../utils/testHelpers';
|
import { createAndLoginUser } from '../utils/testHelpers';
|
||||||
@@ -11,6 +12,8 @@ import { cleanupFiles } from '../utils/cleanupFiles';
|
|||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const request = supertest(app);
|
||||||
|
|
||||||
interface TestGeolocationCoordinates {
|
interface TestGeolocationCoordinates {
|
||||||
latitude: number;
|
latitude: number;
|
||||||
longitude: number;
|
longitude: number;
|
||||||
@@ -23,15 +26,10 @@ interface TestGeolocationCoordinates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('AI API Routes Integration Tests', () => {
|
describe('AI API Routes Integration Tests', () => {
|
||||||
let request: ReturnType<typeof supertest>;
|
|
||||||
let authToken: string;
|
let authToken: string;
|
||||||
let testUserId: string;
|
let testUserId: string;
|
||||||
|
|
||||||
beforeAll(async () => {
|
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.
|
// Create and log in as a new user for authenticated tests.
|
||||||
const { token, user } = await createAndLoginUser({ fullName: 'AI Tester', request });
|
const { token, user } = await createAndLoginUser({ fullName: 'AI Tester', request });
|
||||||
authToken = token;
|
authToken = token;
|
||||||
@@ -39,7 +37,6 @@ describe('AI API Routes Integration Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
vi.unstubAllEnvs();
|
|
||||||
// 1. Clean up database records
|
// 1. Clean up database records
|
||||||
await cleanupDb({ userIds: [testUserId] });
|
await cleanupDb({ userIds: [testUserId] });
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/tests/integration/auth.integration.test.ts
|
// src/tests/integration/auth.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
import { createAndLoginUser, TEST_PASSWORD } from '../utils/testHelpers';
|
import { createAndLoginUser, TEST_PASSWORD } from '../utils/testHelpers';
|
||||||
import { cleanupDb } from '../utils/cleanup';
|
import { cleanupDb } from '../utils/cleanup';
|
||||||
import type { UserProfile } from '../../types';
|
import type { UserProfile } from '../../types';
|
||||||
@@ -9,6 +10,8 @@ import type { UserProfile } from '../../types';
|
|||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const request = supertest(app);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These are integration tests that verify the authentication flow against a running backend server.
|
* 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.
|
* Make sure your Express server is running before executing these tests.
|
||||||
@@ -16,16 +19,11 @@ import type { UserProfile } from '../../types';
|
|||||||
* To run only these tests: `vitest run src/tests/auth.integration.test.ts`
|
* To run only these tests: `vitest run src/tests/auth.integration.test.ts`
|
||||||
*/
|
*/
|
||||||
describe('Authentication API Integration', () => {
|
describe('Authentication API Integration', () => {
|
||||||
let request: ReturnType<typeof supertest>;
|
|
||||||
let testUserEmail: string;
|
let testUserEmail: string;
|
||||||
let testUser: UserProfile;
|
let testUser: UserProfile;
|
||||||
const createdUserIds: string[] = [];
|
const createdUserIds: string[] = [];
|
||||||
|
|
||||||
beforeAll(async () => {
|
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.
|
// Use a unique email for this test suite to prevent collisions with other tests.
|
||||||
const email = `auth-integration-test-${Date.now()}@example.com`;
|
const email = `auth-integration-test-${Date.now()}@example.com`;
|
||||||
({ user: testUser } = await createAndLoginUser({ email, fullName: 'Auth Test User', request }));
|
({ user: testUser } = await createAndLoginUser({ email, fullName: 'Auth Test User', request }));
|
||||||
@@ -34,7 +32,6 @@ describe('Authentication API Integration', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
vi.unstubAllEnvs();
|
|
||||||
await cleanupDb({ userIds: createdUserIds });
|
await cleanupDb({ userIds: createdUserIds });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/tests/integration/budget.integration.test.ts
|
// src/tests/integration/budget.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
import { createAndLoginUser } from '../utils/testHelpers';
|
import { createAndLoginUser } from '../utils/testHelpers';
|
||||||
import { cleanupDb } from '../utils/cleanup';
|
import { cleanupDb } from '../utils/cleanup';
|
||||||
import type { UserProfile, Budget } from '../../types';
|
import type { UserProfile, Budget } from '../../types';
|
||||||
@@ -10,8 +11,9 @@ import { getPool } from '../../services/db/connection.db';
|
|||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const request = supertest(app);
|
||||||
|
|
||||||
describe('Budget API Routes Integration Tests', () => {
|
describe('Budget API Routes Integration Tests', () => {
|
||||||
let request: ReturnType<typeof supertest>;
|
|
||||||
let testUser: UserProfile;
|
let testUser: UserProfile;
|
||||||
let authToken: string;
|
let authToken: string;
|
||||||
let testBudget: Budget;
|
let testBudget: Budget;
|
||||||
@@ -19,10 +21,6 @@ describe('Budget API Routes Integration Tests', () => {
|
|||||||
const createdBudgetIds: number[] = [];
|
const createdBudgetIds: number[] = [];
|
||||||
|
|
||||||
beforeAll(async () => {
|
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
|
// 1. Create a user for the tests
|
||||||
const { user, token } = await createAndLoginUser({
|
const { user, token } = await createAndLoginUser({
|
||||||
email: `budget-user-${Date.now()}@example.com`,
|
email: `budget-user-${Date.now()}@example.com`,
|
||||||
@@ -52,7 +50,6 @@ describe('Budget API Routes Integration Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
vi.unstubAllEnvs();
|
|
||||||
// Clean up all created resources
|
// Clean up all created resources
|
||||||
await cleanupDb({
|
await cleanupDb({
|
||||||
userIds: createdUserIds,
|
userIds: createdUserIds,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/tests/integration/flyer-processing.integration.test.ts
|
// src/tests/integration/flyer-processing.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi, beforeEach } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll, vi, beforeEach } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as db from '../../services/db/index.db';
|
import * as db from '../../services/db/index.db';
|
||||||
@@ -21,6 +22,8 @@ import sharp from 'sharp';
|
|||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const request = supertest(app);
|
||||||
|
|
||||||
const { mockExtractCoreData } = vi.hoisted(() => ({
|
const { mockExtractCoreData } = vi.hoisted(() => ({
|
||||||
mockExtractCoreData: vi.fn(),
|
mockExtractCoreData: vi.fn(),
|
||||||
}));
|
}));
|
||||||
@@ -47,7 +50,6 @@ vi.mock('../../services/db/index.db', async (importOriginal) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Flyer Processing Background Job Integration Test', () => {
|
describe('Flyer Processing Background Job Integration Test', () => {
|
||||||
let request: ReturnType<typeof supertest>;
|
|
||||||
const createdUserIds: string[] = [];
|
const createdUserIds: string[] = [];
|
||||||
const createdFlyerIds: number[] = [];
|
const createdFlyerIds: number[] = [];
|
||||||
const createdFilePaths: string[] = [];
|
const createdFilePaths: string[] = [];
|
||||||
@@ -55,12 +57,7 @@ describe('Flyer Processing Background Job Integration Test', () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
// FIX: Stub FRONTEND_URL to ensure valid absolute URLs (http://...) are generated
|
// FIX: Stub FRONTEND_URL to ensure valid absolute URLs (http://...) are generated
|
||||||
// for the database, satisfying the 'url_check' constraint.
|
// 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');
|
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.
|
// FIX: Reset mocks before each test to ensure isolation.
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
// src/tests/integration/flyer.integration.test.ts
|
// src/tests/integration/flyer.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
import { getPool } from '../../services/db/connection.db';
|
import { getPool } from '../../services/db/connection.db';
|
||||||
|
import app from '../../../server';
|
||||||
import type { Flyer, FlyerItem } from '../../types';
|
import type { Flyer, FlyerItem } from '../../types';
|
||||||
import { cleanupDb } from '../utils/cleanup';
|
import { cleanupDb } from '../utils/cleanup';
|
||||||
import { TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers';
|
import { TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers';
|
||||||
@@ -13,16 +14,12 @@ import { TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers';
|
|||||||
describe('Public Flyer API Routes Integration Tests', () => {
|
describe('Public Flyer API Routes Integration Tests', () => {
|
||||||
let flyers: Flyer[] = [];
|
let flyers: Flyer[] = [];
|
||||||
// Use a supertest instance for all requests in this file
|
// Use a supertest instance for all requests in this file
|
||||||
let request: ReturnType<typeof supertest>;
|
const request = supertest(app);
|
||||||
let testStoreId: number;
|
let testStoreId: number;
|
||||||
let createdFlyerId: number;
|
let createdFlyerId: number;
|
||||||
|
|
||||||
// Fetch flyers once before all tests in this suite to use in subsequent tests.
|
// Fetch flyers once before all tests in this suite to use in subsequent tests.
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
vi.stubEnv('FRONTEND_URL', 'https://example.com');
|
|
||||||
const app = (await import('../../../server')).default;
|
|
||||||
request = supertest(app);
|
|
||||||
|
|
||||||
// Ensure at least one flyer exists
|
// Ensure at least one flyer exists
|
||||||
const storeRes = await getPool().query(
|
const storeRes = await getPool().query(
|
||||||
`INSERT INTO public.stores (name) VALUES ('Integration Test Store') RETURNING store_id`,
|
`INSERT INTO public.stores (name) VALUES ('Integration Test Store') RETURNING store_id`,
|
||||||
@@ -48,7 +45,6 @@ describe('Public Flyer API Routes Integration Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
vi.unstubAllEnvs();
|
|
||||||
// Clean up the test data created in beforeAll to prevent polluting the test database.
|
// Clean up the test data created in beforeAll to prevent polluting the test database.
|
||||||
await cleanupDb({
|
await cleanupDb({
|
||||||
flyerIds: [createdFlyerId],
|
flyerIds: [createdFlyerId],
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/tests/integration/gamification.integration.test.ts
|
// src/tests/integration/gamification.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import { getPool } from '../../services/db/connection.db';
|
import { getPool } from '../../services/db/connection.db';
|
||||||
@@ -25,6 +26,8 @@ import { cleanupFiles } from '../utils/cleanupFiles';
|
|||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const request = supertest(app);
|
||||||
|
|
||||||
const { mockExtractCoreData } = vi.hoisted(() => ({
|
const { mockExtractCoreData } = vi.hoisted(() => ({
|
||||||
mockExtractCoreData: vi.fn(),
|
mockExtractCoreData: vi.fn(),
|
||||||
}));
|
}));
|
||||||
@@ -50,7 +53,6 @@ vi.mock('../../utils/imageProcessor', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Gamification Flow Integration Test', () => {
|
describe('Gamification Flow Integration Test', () => {
|
||||||
let request: ReturnType<typeof supertest>;
|
|
||||||
let testUser: UserProfile;
|
let testUser: UserProfile;
|
||||||
let authToken: string;
|
let authToken: string;
|
||||||
const createdFlyerIds: number[] = [];
|
const createdFlyerIds: number[] = [];
|
||||||
@@ -58,12 +60,6 @@ describe('Gamification Flow Integration Test', () => {
|
|||||||
const createdStoreIds: number[] = [];
|
const createdStoreIds: number[] = [];
|
||||||
|
|
||||||
beforeAll(async () => {
|
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.
|
// Create a new user specifically for this test suite to ensure a clean slate.
|
||||||
({ user: testUser, token: authToken } = await createAndLoginUser({
|
({ user: testUser, token: authToken } = await createAndLoginUser({
|
||||||
email: `gamification-user-${Date.now()}@example.com`,
|
email: `gamification-user-${Date.now()}@example.com`,
|
||||||
@@ -71,6 +67,10 @@ describe('Gamification Flow Integration Test', () => {
|
|||||||
request,
|
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.
|
// Setup default mock response for the AI service's extractCoreDataFromFlyerImage method.
|
||||||
mockExtractCoreData.mockResolvedValue({
|
mockExtractCoreData.mockResolvedValue({
|
||||||
store_name: 'Gamification Test Store',
|
store_name: 'Gamification Test Store',
|
||||||
@@ -90,7 +90,6 @@ describe('Gamification Flow Integration Test', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
vi.unstubAllEnvs();
|
|
||||||
await cleanupDb({
|
await cleanupDb({
|
||||||
userIds: testUser ? [testUser.user.user_id] : [],
|
userIds: testUser ? [testUser.user.user_id] : [],
|
||||||
flyerIds: createdFlyerIds,
|
flyerIds: createdFlyerIds,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/tests/integration/notification.integration.test.ts
|
// src/tests/integration/notification.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
import { createAndLoginUser } from '../utils/testHelpers';
|
import { createAndLoginUser } from '../utils/testHelpers';
|
||||||
import { cleanupDb } from '../utils/cleanup';
|
import { cleanupDb } from '../utils/cleanup';
|
||||||
import type { UserProfile, Notification } from '../../types';
|
import type { UserProfile, Notification } from '../../types';
|
||||||
@@ -10,17 +11,14 @@ import { getPool } from '../../services/db/connection.db';
|
|||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const request = supertest(app);
|
||||||
|
|
||||||
describe('Notification API Routes Integration Tests', () => {
|
describe('Notification API Routes Integration Tests', () => {
|
||||||
let request: ReturnType<typeof supertest>;
|
|
||||||
let testUser: UserProfile;
|
let testUser: UserProfile;
|
||||||
let authToken: string;
|
let authToken: string;
|
||||||
const createdUserIds: string[] = [];
|
const createdUserIds: string[] = [];
|
||||||
|
|
||||||
beforeAll(async () => {
|
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
|
// 1. Create a user for the tests
|
||||||
const { user, token } = await createAndLoginUser({
|
const { user, token } = await createAndLoginUser({
|
||||||
email: `notification-user-${Date.now()}@example.com`,
|
email: `notification-user-${Date.now()}@example.com`,
|
||||||
@@ -48,7 +46,6 @@ describe('Notification API Routes Integration Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
vi.unstubAllEnvs();
|
|
||||||
// Notifications are deleted via CASCADE when the user is deleted.
|
// Notifications are deleted via CASCADE when the user is deleted.
|
||||||
await cleanupDb({
|
await cleanupDb({
|
||||||
userIds: createdUserIds,
|
userIds: createdUserIds,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/tests/integration/price.integration.test.ts
|
// src/tests/integration/price.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
import { getPool } from '../../services/db/connection.db';
|
import { getPool } from '../../services/db/connection.db';
|
||||||
import { TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers';
|
import { TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers';
|
||||||
|
|
||||||
@@ -8,8 +9,9 @@ import { TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers';
|
|||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const request = supertest(app);
|
||||||
|
|
||||||
describe('Price History API Integration Test (/api/price-history)', () => {
|
describe('Price History API Integration Test (/api/price-history)', () => {
|
||||||
let request: ReturnType<typeof supertest>;
|
|
||||||
let masterItemId: number;
|
let masterItemId: number;
|
||||||
let storeId: number;
|
let storeId: number;
|
||||||
let flyerId1: number;
|
let flyerId1: number;
|
||||||
@@ -17,10 +19,6 @@ describe('Price History API Integration Test (/api/price-history)', () => {
|
|||||||
let flyerId3: number;
|
let flyerId3: number;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
vi.stubEnv('FRONTEND_URL', 'https://example.com');
|
|
||||||
const app = (await import('../../../server')).default;
|
|
||||||
request = supertest(app);
|
|
||||||
|
|
||||||
const pool = getPool();
|
const pool = getPool();
|
||||||
|
|
||||||
// 1. Create a master grocery item
|
// 1. Create a master grocery item
|
||||||
@@ -73,7 +71,6 @@ describe('Price History API Integration Test (/api/price-history)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
vi.unstubAllEnvs();
|
|
||||||
const pool = getPool();
|
const pool = getPool();
|
||||||
// The CASCADE on the tables should handle flyer_items.
|
// 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`.
|
// The delete on flyers cascades to flyer_items, which fires a trigger `recalculate_price_history_on_flyer_item_delete`.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/tests/integration/public.routes.integration.test.ts
|
// src/tests/integration/public.routes.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
import type {
|
import type {
|
||||||
Flyer,
|
Flyer,
|
||||||
FlyerItem,
|
FlyerItem,
|
||||||
@@ -19,19 +20,16 @@ import { createAndLoginUser, TEST_EXAMPLE_DOMAIN } from '../utils/testHelpers';
|
|||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const request = supertest(app);
|
||||||
|
|
||||||
describe('Public API Routes Integration Tests', () => {
|
describe('Public API Routes Integration Tests', () => {
|
||||||
// Shared state for tests
|
// Shared state for tests
|
||||||
let request: ReturnType<typeof supertest>;
|
|
||||||
let testUser: UserProfile;
|
let testUser: UserProfile;
|
||||||
let testRecipe: Recipe;
|
let testRecipe: Recipe;
|
||||||
let testFlyer: Flyer;
|
let testFlyer: Flyer;
|
||||||
let testStoreId: number;
|
let testStoreId: number;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
vi.stubEnv('FRONTEND_URL', 'https://example.com');
|
|
||||||
const app = (await import('../../../server')).default;
|
|
||||||
request = supertest(app);
|
|
||||||
|
|
||||||
const pool = getPool();
|
const pool = getPool();
|
||||||
// Create a user to own the recipe
|
// Create a user to own the recipe
|
||||||
const userEmail = `public-routes-user-${Date.now()}@example.com`;
|
const userEmail = `public-routes-user-${Date.now()}@example.com`;
|
||||||
@@ -79,7 +77,6 @@ describe('Public API Routes Integration Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
vi.unstubAllEnvs();
|
|
||||||
await cleanupDb({
|
await cleanupDb({
|
||||||
userIds: testUser ? [testUser.user.user_id] : [],
|
userIds: testUser ? [testUser.user.user_id] : [],
|
||||||
recipeIds: testRecipe ? [testRecipe.recipe_id] : [],
|
recipeIds: testRecipe ? [testRecipe.recipe_id] : [],
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/tests/integration/recipe.integration.test.ts
|
// src/tests/integration/recipe.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
import { createAndLoginUser } from '../utils/testHelpers';
|
import { createAndLoginUser } from '../utils/testHelpers';
|
||||||
import { cleanupDb } from '../utils/cleanup';
|
import { cleanupDb } from '../utils/cleanup';
|
||||||
import type { UserProfile, Recipe, RecipeComment } from '../../types';
|
import type { UserProfile, Recipe, RecipeComment } from '../../types';
|
||||||
@@ -12,8 +13,9 @@ import { aiService } from '../../services/aiService.server';
|
|||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const request = supertest(app);
|
||||||
|
|
||||||
describe('Recipe API Routes Integration Tests', () => {
|
describe('Recipe API Routes Integration Tests', () => {
|
||||||
let request: ReturnType<typeof supertest>;
|
|
||||||
let testUser: UserProfile;
|
let testUser: UserProfile;
|
||||||
let authToken: string;
|
let authToken: string;
|
||||||
let testRecipe: Recipe;
|
let testRecipe: Recipe;
|
||||||
@@ -21,10 +23,6 @@ describe('Recipe API Routes Integration Tests', () => {
|
|||||||
const createdRecipeIds: number[] = [];
|
const createdRecipeIds: number[] = [];
|
||||||
|
|
||||||
beforeAll(async () => {
|
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
|
// Create a user to own the recipe and perform authenticated actions
|
||||||
const { user, token } = await createAndLoginUser({
|
const { user, token } = await createAndLoginUser({
|
||||||
email: `recipe-user-${Date.now()}@example.com`,
|
email: `recipe-user-${Date.now()}@example.com`,
|
||||||
@@ -50,7 +48,6 @@ describe('Recipe API Routes Integration Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
vi.unstubAllEnvs();
|
|
||||||
// Clean up all created resources
|
// Clean up all created resources
|
||||||
await cleanupDb({
|
await cleanupDb({
|
||||||
userIds: createdUserIds,
|
userIds: createdUserIds,
|
||||||
|
|||||||
@@ -1,23 +1,13 @@
|
|||||||
// src/tests/integration/server.integration.test.ts
|
// src/tests/integration/server.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
describe('Server Initialization Smoke Test', () => {
|
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', () => {
|
it('should import the server app without crashing', () => {
|
||||||
// This test's primary purpose is to ensure that all top-level code in `server.ts`
|
// 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,
|
// can execute without throwing an error. This catches issues like syntax errors,
|
||||||
|
|||||||
@@ -1,23 +1,13 @@
|
|||||||
// src/tests/integration/system.integration.test.ts
|
// src/tests/integration/system.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
describe('System API Routes Integration Tests', () => {
|
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', () => {
|
describe('GET /api/system/pm2-status', () => {
|
||||||
it('should return a status for PM2', async () => {
|
it('should return a status for PM2', async () => {
|
||||||
const request = supertest(app);
|
const request = supertest(app);
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
// src/tests/integration/user.integration.test.ts
|
// src/tests/integration/user.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
|
import app from '../../../server';
|
||||||
import { logger } from '../../services/logger.server';
|
import { logger } from '../../services/logger.server';
|
||||||
import { getPool } from '../../services/db/connection.db';
|
import { getPool } from '../../services/db/connection.db';
|
||||||
import type { UserProfile, MasterGroceryItem, ShoppingList } from '../../types';
|
import type { UserProfile, MasterGroceryItem, ShoppingList } from '../../types';
|
||||||
@@ -14,8 +15,9 @@ import { cleanupFiles } from '../utils/cleanupFiles';
|
|||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const request = supertest(app);
|
||||||
|
|
||||||
describe('User API Routes Integration Tests', () => {
|
describe('User API Routes Integration Tests', () => {
|
||||||
let request: ReturnType<typeof supertest>;
|
|
||||||
let testUser: UserProfile;
|
let testUser: UserProfile;
|
||||||
let authToken: string;
|
let authToken: string;
|
||||||
const createdUserIds: string[] = [];
|
const createdUserIds: string[] = [];
|
||||||
@@ -23,10 +25,6 @@ describe('User API Routes Integration Tests', () => {
|
|||||||
// Before any tests run, create a new user and log them in.
|
// 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.
|
// The token will be used for all subsequent API calls in this test suite.
|
||||||
beforeAll(async () => {
|
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 email = `user-test-${Date.now()}@example.com`;
|
||||||
const { user, token } = await createAndLoginUser({ email, fullName: 'Test User', request });
|
const { user, token } = await createAndLoginUser({ email, fullName: 'Test User', request });
|
||||||
testUser = user;
|
testUser = user;
|
||||||
@@ -37,7 +35,6 @@ describe('User API Routes Integration Tests', () => {
|
|||||||
// After all tests, clean up by deleting the created user.
|
// After all tests, clean up by deleting the created user.
|
||||||
// This now cleans up ALL users created by this test suite to prevent pollution.
|
// This now cleans up ALL users created by this test suite to prevent pollution.
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
vi.unstubAllEnvs();
|
|
||||||
await cleanupDb({ userIds: createdUserIds });
|
await cleanupDb({ userIds: createdUserIds });
|
||||||
|
|
||||||
// Safeguard to clean up any avatar files created during tests.
|
// Safeguard to clean up any avatar files created during tests.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/tests/integration/user.routes.integration.test.ts
|
// src/tests/integration/user.routes.integration.test.ts
|
||||||
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
|
import app from '../../../server';
|
||||||
import type { UserProfile } from '../../types';
|
import type { UserProfile } from '../../types';
|
||||||
import { createAndLoginUser } from '../utils/testHelpers';
|
import { createAndLoginUser } from '../utils/testHelpers';
|
||||||
import { cleanupDb } from '../utils/cleanup';
|
import { cleanupDb } from '../utils/cleanup';
|
||||||
@@ -9,18 +10,15 @@ import { cleanupDb } from '../utils/cleanup';
|
|||||||
* @vitest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const request = supertest(app);
|
||||||
|
|
||||||
describe('User Routes Integration Tests (/api/users)', () => {
|
describe('User Routes Integration Tests (/api/users)', () => {
|
||||||
let request: ReturnType<typeof supertest>;
|
|
||||||
let authToken = '';
|
let authToken = '';
|
||||||
let testUser: UserProfile;
|
let testUser: UserProfile;
|
||||||
const createdUserIds: string[] = [];
|
const createdUserIds: string[] = [];
|
||||||
|
|
||||||
// Authenticate once before all tests in this suite to get a JWT.
|
// Authenticate once before all tests in this suite to get a JWT.
|
||||||
beforeAll(async () => {
|
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.
|
// Use the helper to create and log in a user in one step.
|
||||||
const { user, token } = await createAndLoginUser({
|
const { user, token } = await createAndLoginUser({
|
||||||
fullName: 'User Routes Test User',
|
fullName: 'User Routes Test User',
|
||||||
@@ -32,7 +30,6 @@ describe('User Routes Integration Tests (/api/users)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
vi.unstubAllEnvs();
|
|
||||||
await cleanupDb({ userIds: createdUserIds });
|
await cleanupDb({ userIds: createdUserIds });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// src/tests/setup/integration-global-setup.ts
|
// src/tests/setup/integration-global-setup.ts
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import type { Server } from 'http';
|
import type { Server } from 'http';
|
||||||
|
import app from '../../../server'; // Import the Express app
|
||||||
import { logger } from '../../services/logger.server';
|
import { logger } from '../../services/logger.server';
|
||||||
import { getPool } from '../../services/db/connection.db';
|
import { getPool } from '../../services/db/connection.db';
|
||||||
|
|
||||||
@@ -12,9 +13,6 @@ let globalPool: ReturnType<typeof getPool> | null = null;
|
|||||||
export async function setup() {
|
export async function setup() {
|
||||||
// Ensure we are in the correct environment for these tests.
|
// Ensure we are in the correct environment for these tests.
|
||||||
process.env.NODE_ENV = 'test';
|
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 ---`);
|
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.
|
// The integration setup is now the single source of truth for preparing the test DB.
|
||||||
@@ -32,10 +30,6 @@ export async function setup() {
|
|||||||
console.log(`[PID:${process.pid}] Initializing global database pool...`);
|
console.log(`[PID:${process.pid}] Initializing global database pool...`);
|
||||||
globalPool = getPool();
|
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.
|
// Programmatically start the server within the same process.
|
||||||
const port = process.env.PORT || 3001;
|
const port = process.env.PORT || 3001;
|
||||||
await new Promise<void>((resolve) => {
|
await new Promise<void>((resolve) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user