Compare commits

...

12 Commits

Author SHA1 Message Date
Gitea Actions
aefd57e57b ci: Bump version to 0.1.12 [skip ci] 2025-12-26 08:12:15 +05:00
2ca4eb47ac Merge branch 'main' of https://gitea.projectium.com/torbo/flyer-crawler.projectium.com
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 11m39s
2025-12-25 19:11:25 -08:00
a4fe30da22 not sure why those errors got removed we'll see 2025-12-25 19:11:00 -08:00
Gitea Actions
abab7fd25e ci: Bump version to 0.1.11 [skip ci] 2025-12-26 07:33:29 +05:00
53dd26d2d9 Merge branch 'main' of https://gitea.projectium.com/torbo/flyer-crawler.projectium.com
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 12m34s
2025-12-25 18:32:56 -08:00
ab3da0336c more route work - fuck you ai 2025-12-25 18:32:14 -08:00
Gitea Actions
ed6d6349a2 ci: Bump version to 0.1.10 [skip ci] 2025-12-26 06:54:19 +05:00
d4db2a709a Merge branch 'main' of https://gitea.projectium.com/torbo/flyer-crawler.projectium.com
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 47s
2025-12-25 17:53:28 -08:00
508583809b minor sql fix in schema check 2025-12-25 17:53:21 -08:00
Gitea Actions
6b1f7e7590 ci: Bump version to 0.1.9 [skip ci] 2025-12-26 03:46:16 +05:00
07bb31f4fb Merge branch 'main' of https://gitea.projectium.com/torbo/flyer-crawler.projectium.com
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 13m29s
2025-12-25 14:45:29 -08:00
a42fb76da8 minor sql fix in schema check 2025-12-25 14:45:22 -08:00
23 changed files with 88 additions and 67 deletions

View File

@@ -283,7 +283,7 @@ jobs:
echo "WARNING: No schema hash found in the test database."
echo "This is expected for a first-time deployment. The hash will be set after a successful deployment."
echo "--- Debug: Dumping schema_info table ---"
PGPASSWORD="$DB_PASSWORD" psql -v ON_ERROR_STOP=0 -h "$DB_HOST" -p 5432 -U "$DB_USER" -d "$DB_NAME" -c "SELECT * FROM public.schema_info;" || true
PGPASSWORD="$DB_PASSWORD" psql -v ON_ERROR_STOP=0 -h "$DB_HOST" -p 5432 -U "$DB_USER" -d "$DB_NAME" -P pager=off -c "SELECT * FROM public.schema_info;" || true
echo "----------------------------------------"
# We allow the deployment to continue, but a manual schema update is required.
# You could choose to fail here by adding `exit 1`.

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "flyer-crawler",
"version": "0.1.8",
"version": "0.1.12",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "flyer-crawler",
"version": "0.1.8",
"version": "0.1.12",
"dependencies": {
"@bull-board/api": "^6.14.2",
"@bull-board/express": "^6.14.2",

View File

@@ -1,7 +1,7 @@
{
"name": "flyer-crawler",
"private": true,
"version": "0.1.8",
"version": "0.1.12",
"type": "module",
"scripts": {
"dev": "concurrently \"npm:start:dev\" \"vite\"",

View File

@@ -15,16 +15,19 @@ import type { Logger } from 'pino';
// Create a mock logger that we can inject into requests and assert against.
// We only mock the methods we intend to spy on. The rest of the complex Pino
// Logger type is satisfied by casting, which is a common and clean testing practice.
const mockLogger = {
error: vi.fn(),
warn: vi.fn(),
info: vi.fn(),
debug: vi.fn(),
fatal: vi.fn(),
trace: vi.fn(),
silent: vi.fn(),
child: vi.fn().mockReturnThis(),
} as unknown as Logger;
const { mockLogger } = vi.hoisted(() => {
const mockLogger = {
error: vi.fn(),
warn: vi.fn(),
info: vi.fn(),
debug: vi.fn(),
fatal: vi.fn(),
trace: vi.fn(),
silent: vi.fn(),
child: vi.fn().mockReturnThis(),
};
return { mockLogger };
});
// Mock the global logger as a fallback, though our tests will focus on req.log
vi.mock('../services/logger.server', () => ({ logger: mockLogger }));
@@ -37,7 +40,7 @@ const app = express();
app.use(express.json());
// Add a middleware to inject our mock logger into each request as `req.log`
app.use((req: Request, res: Response, next: NextFunction) => {
req.log = mockLogger;
req.log = mockLogger as unknown as Logger;
next();
});
@@ -106,7 +109,10 @@ describe('errorHandler Middleware', () => {
it('should return a generic 500 error for a standard Error object', async () => {
const response = await supertest(app).get('/generic-error');
expect(response.status).toBe(500);
expect(response.body).toEqual({ message: 'A generic server error occurred.' });
// In test/dev, we now expect a stack trace for 5xx errors.
expect(response.body.message).toBe('A generic server error occurred.');
expect(response.body.stack).toBeDefined();
expect(response.body.stack).toEqual(expect.any(String));
expect(mockLogger.error).toHaveBeenCalledWith(
expect.objectContaining({
err: expect.any(Error),
@@ -229,7 +235,10 @@ describe('errorHandler Middleware', () => {
const response = await supertest(app).get('/db-error-500');
expect(response.status).toBe(500);
expect(response.body).toEqual({ message: 'A database connection issue occurred.' });
// In test/dev, we now expect a stack trace for 5xx errors.
expect(response.body.message).toBe('A database connection issue occurred.');
expect(response.body.stack).toBeDefined();
expect(response.body.stack).toEqual(expect.any(String));
expect(mockLogger.error).toHaveBeenCalledWith(
expect.objectContaining({
err: expect.any(DatabaseError),

View File

@@ -63,6 +63,6 @@ export const errorHandler = (err: Error, req: Request, res: Response, next: Next
return res.status(500).json({ message: 'An internal server error occurred.' });
}
// In development, send more details for easier debugging.
// In non-production environments (dev, test, etc.), send more details for easier debugging.
return res.status(500).json({ message: err.message, stack: err.stack });
};

View File

@@ -13,7 +13,6 @@ import {
import type { SuggestedCorrection, Brand, UserProfile, UnmatchedFlyerItem } from '../types';
import { NotFoundError } from '../services/db/errors.db'; // This can stay, it's a type/class not a module with side effects.
import { createTestApp } from '../tests/utils/createTestApp';
import { mockLogger } from '../tests/utils/mockLogger';
// Mock the file upload middleware to allow testing the controller's internal check
vi.mock('../middleware/fileUpload.middleware', () => ({
@@ -96,8 +95,9 @@ vi.mock('@bull-board/express', () => ({
}));
// Mock the logger
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Mock the passport middleware

View File

@@ -6,7 +6,6 @@ import { createMockUserProfile } from '../tests/utils/mockFactories';
import type { Job } from 'bullmq';
import type { UserProfile } from '../types';
import { createTestApp } from '../tests/utils/createTestApp';
import { mockLogger } from '../tests/utils/mockLogger';
// Mock the background job service to control its methods.
vi.mock('../services/backgroundJobService', () => ({
@@ -66,8 +65,9 @@ import {
} from '../services/queueService.server';
// Mock the logger
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Mock the passport middleware

View File

@@ -5,7 +5,6 @@ import type { Request, Response, NextFunction } from 'express';
import { createMockUserProfile } from '../tests/utils/mockFactories';
import type { UserProfile } from '../types';
import { createTestApp } from '../tests/utils/createTestApp';
import { mockLogger } from '../tests/utils/mockLogger';
vi.mock('../services/db/index.db', () => ({
adminRepo: {
@@ -45,8 +44,9 @@ import adminRouter from './admin.routes';
import { adminRepo } from '../services/db/index.db';
// Mock the logger
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Mock the passport middleware

View File

@@ -4,7 +4,6 @@ import supertest from 'supertest';
import type { Request, Response, NextFunction } from 'express';
import { createMockUserProfile } from '../tests/utils/mockFactories';
import { createTestApp } from '../tests/utils/createTestApp';
import { mockLogger } from '../tests/utils/mockLogger';
// Mock dependencies
vi.mock('../services/geocodingService.server', () => ({
@@ -50,8 +49,9 @@ import adminRouter from './admin.routes';
import { geocodingService } from '../services/geocodingService.server';
// Mock the logger
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Mock the passport middleware

View File

@@ -6,7 +6,6 @@ import { createMockUserProfile, createMockAdminUserView } from '../tests/utils/m
import type { UserProfile, Profile } from '../types';
import { NotFoundError } from '../services/db/errors.db';
import { createTestApp } from '../tests/utils/createTestApp';
import { mockLogger } from '../tests/utils/mockLogger';
vi.mock('../services/db/index.db', () => ({
adminRepo: {
@@ -44,8 +43,9 @@ vi.mock('@bull-board/express', () => ({
}));
// Mock the logger
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Import the router AFTER all mocks are defined.

View File

@@ -55,8 +55,9 @@ import aiRouter from './ai.routes';
import { flyerQueue } from '../services/queueService.server';
// Mock the logger to keep test output clean
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Mock the passport module to control authentication for different tests.

View File

@@ -9,7 +9,6 @@ import {
createMockUserProfile,
createMockUserWithPasswordHash,
} from '../tests/utils/mockFactories';
import { mockLogger } from '../tests/utils/mockLogger';
// --- FIX: Hoist passport mocks to be available for vi.mock ---
const passportMocks = vi.hoisted(() => {
@@ -111,8 +110,9 @@ vi.mock('../services/db/connection.db', () => ({
}));
// Mock the logger
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Mock the email service
@@ -144,6 +144,8 @@ import { UniqueConstraintError } from '../services/db/errors.db'; // Import actu
import express from 'express';
import { errorHandler } from '../middleware/errorHandler'; // Assuming this exists
const { mockLogger } = await import('../tests/utils/mockLogger');
const app = express();
app.use(express.json());
app.use(cookieParser()); // Mount BEFORE router

View File

@@ -7,7 +7,6 @@ import {
createMockBudget,
createMockSpendingByCategory,
} from '../tests/utils/mockFactories';
import { mockLogger } from '../tests/utils/mockLogger';
import { createTestApp } from '../tests/utils/createTestApp';
import { ForeignKeyConstraintError, NotFoundError } from '../services/db/errors.db';
// 1. Mock the Service Layer directly.
@@ -26,8 +25,9 @@ vi.mock('../services/db/index.db', () => ({
}));
// Mock the logger to keep test output clean
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Import the router and mocked DB AFTER all mocks are defined.

View File

@@ -4,7 +4,6 @@ import supertest from 'supertest';
import type { Request, Response, NextFunction } from 'express';
import { createMockUserProfile, createMockWatchedItemDeal } from '../tests/utils/mockFactories';
import type { WatchedItemDeal } from '../types';
import { mockLogger } from '../tests/utils/mockLogger';
import { createTestApp } from '../tests/utils/createTestApp';
// 1. Mock the Service Layer directly.
@@ -17,10 +16,12 @@ vi.mock('../services/db/deals.db', () => ({
// Import the router and mocked repo AFTER all mocks are defined.
import dealsRouter from './deals.routes';
import { dealsRepo } from '../services/db/deals.db';
import { mockLogger } from '../tests/utils/mockLogger';
// Mock the logger to keep test output clean
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Mock the passport middleware

View File

@@ -23,8 +23,9 @@ import * as db from '../services/db/index.db';
import { mockLogger } from '../tests/utils/mockLogger';
// Mock the logger to keep test output clean
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Define a reusable matcher for the logger object.

View File

@@ -27,8 +27,9 @@ import gamificationRouter from './gamification.routes';
import * as db from '../services/db/index.db';
// Mock the logger to keep test output clean
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Use vi.hoisted to create mutable mock function references.

View File

@@ -32,8 +32,9 @@ import healthRouter from './health.routes';
import * as dbConnection from '../services/db/connection.db';
// Mock the logger to keep test output clean.
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Cast the mocked import to a Mocked type for type-safe access to mock functions.

View File

@@ -56,7 +56,6 @@ import {
createMockUserProfile,
createMockUserWithPasswordHash,
} from '../tests/utils/mockFactories';
import { mockLogger } from '../tests/utils/mockLogger';
// Mock dependencies before importing the passport configuration
vi.mock('../services/db/index.db', () => ({
@@ -74,9 +73,10 @@ vi.mock('../services/db/index.db', () => ({
const mockedDb = db as Mocked<typeof db>;
vi.mock('../services/logger.server', () => ({
// This mock is used by the module under test and can be imported in the test file.
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
// Note: We need to await the import inside the factory
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Mock bcrypt for password comparisons

View File

@@ -6,7 +6,6 @@ import {
createMockDietaryRestriction,
createMockAppliance,
} from '../tests/utils/mockFactories';
import { mockLogger } from '../tests/utils/mockLogger';
import { createTestApp } from '../tests/utils/createTestApp';
// 1. Mock the Service Layer directly.
@@ -21,10 +20,12 @@ vi.mock('../services/db/index.db', () => ({
// Import the router and mocked DB AFTER all mocks are defined.
import personalizationRouter from './personalization.routes';
import * as db from '../services/db/index.db';
import { mockLogger } from '../tests/utils/mockLogger';
// Mock the logger to keep test output clean
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
describe('Personalization Routes (/api/personalization)', () => {

View File

@@ -12,8 +12,9 @@ vi.mock('../services/db/price.db', () => ({
}));
// Mock the logger to keep test output clean
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Import the router AFTER other setup.

View File

@@ -1,7 +1,6 @@
// src/routes/recipe.routes.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
import supertest from 'supertest';
import { mockLogger } from '../tests/utils/mockLogger';
import { createMockRecipe, createMockRecipeComment } from '../tests/utils/mockFactories';
import { NotFoundError } from '../services/db/errors.db';
import { createTestApp } from '../tests/utils/createTestApp';
@@ -20,10 +19,12 @@ vi.mock('../services/db/index.db', () => ({
// Import the router and mocked DB AFTER all mocks are defined.
import recipeRouter from './recipe.routes';
import * as db from '../services/db/index.db';
import { mockLogger } from '../tests/utils/mockLogger';
// Mock the logger to keep test output clean
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Import the mocked db module to control its functions in tests

View File

@@ -1,7 +1,6 @@
// src/routes/stats.routes.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
import supertest from 'supertest';
import { mockLogger } from '../tests/utils/mockLogger';
import { createTestApp } from '../tests/utils/createTestApp';
// 1. Mock the Service Layer directly.
@@ -14,10 +13,12 @@ vi.mock('../services/db/index.db', () => ({
// Import the router and mocked DB AFTER all mocks are defined.
import statsRouter from './stats.routes';
import * as db from '../services/db/index.db';
import { mockLogger } from '../tests/utils/mockLogger';
// Mock the logger to keep test output clean
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
const expectLogger = expect.objectContaining({

View File

@@ -86,8 +86,9 @@ vi.mock('bcrypt', () => {
});
// Mock the logger
vi.mock('../services/logger.server', () => ({
logger: mockLogger,
vi.mock('../services/logger.server', async () => ({
// Use async import to avoid hoisting issues with mockLogger
logger: (await import('../tests/utils/mockLogger')).mockLogger,
}));
// Import the router and other modules AFTER mocks are established