fix unit tests
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 12m5s

This commit is contained in:
2025-12-29 17:18:52 -08:00
parent a94b2a97b1
commit 517a268307
5 changed files with 83 additions and 74 deletions

View File

@@ -12,11 +12,10 @@ vi.mock('util', async (importOriginal) => {
const actual = await importOriginal<typeof import('util')>(); const actual = await importOriginal<typeof import('util')>();
return { return {
...actual, ...actual,
default: actual,
promisify: (fn: Function) => { promisify: (fn: Function) => {
return (...args: any[]) => { return (...args: any[]) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fn(...args, (err: Error | null, stdout: unknown, stderr: unknown) => { fn(...args, (err: Error | null, stdout: string, stderr: string) => {
if (err) { if (err) {
// Attach stdout/stderr to the error object to mimic child_process.exec behavior // Attach stdout/stderr to the error object to mimic child_process.exec behavior
Object.assign(err, { stdout, stderr }); Object.assign(err, { stdout, stderr });
@@ -41,7 +40,6 @@ vi.mock('child_process', () => {
}); });
return { return {
default: { exec: mockExec },
exec: mockExec, exec: mockExec,
}; };
}); });

View File

@@ -127,12 +127,21 @@ describe('AnalyticsService', () => {
throw new Error('Processing failed'); throw new Error('Processing failed');
}); // "Successfully generated..." }); // "Successfully generated..."
const promise = service.processWeeklyReportJob(job); // Wrap the async operation that is expected to reject in a function.
// This prevents an "unhandled rejection" error by ensuring the `expect.rejects`
// is actively waiting for the promise to reject when the timers are advanced.
const testFunction = async () => {
const promise = service.processWeeklyReportJob(job);
// Advance timers to trigger the part of the code that throws.
await vi.advanceTimersByTimeAsync(30000);
// Await the promise to allow the rejection to be caught by `expect.rejects`.
await promise;
};
await vi.advanceTimersByTimeAsync(30000); // Now, assert that the entire operation rejects as expected.
await expect(testFunction()).rejects.toThrow('Processing failed');
await expect(promise).rejects.toThrow('Processing failed');
// Verify the side effect (error logging) after the rejection is confirmed.
expect(mockLoggerInstance.error).toHaveBeenCalledWith( expect(mockLoggerInstance.error).toHaveBeenCalledWith(
expect.objectContaining({ expect.objectContaining({
err: expect.any(Error), err: expect.any(Error),

View File

@@ -1,70 +1,16 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'; import { describe, it, expect, vi, beforeEach } from 'vitest';
// Set environment variables before importing the service
process.env.JWT_SECRET = 'test-secret';
process.env.FRONTEND_URL = 'http://localhost:3000';
import { authService } from './authService';
import * as bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import crypto from 'crypto';
import { userRepo, adminRepo } from './db/index.db';
import { UniqueConstraintError } from './db/errors.db'; import { UniqueConstraintError } from './db/errors.db';
import { logger } from './logger.server';
import { sendPasswordResetEmail } from './emailService.server';
import type { UserProfile } from '../types'; import type { UserProfile } from '../types';
// Mock dependencies
vi.mock('bcrypt');
vi.mock('jsonwebtoken');
vi.mock('crypto', () => ({
default: {
randomBytes: vi.fn().mockReturnValue({
toString: vi.fn().mockReturnValue('mocked-random-string'),
}),
},
}));
vi.mock('./db/index.db', () => ({
userRepo: {
createUser: vi.fn(),
saveRefreshToken: vi.fn(),
findUserByEmail: vi.fn(),
createPasswordResetToken: vi.fn(),
getValidResetTokens: vi.fn(),
updateUserPassword: vi.fn(),
deleteResetToken: vi.fn(),
findUserByRefreshToken: vi.fn(),
findUserProfileById: vi.fn(),
deleteRefreshToken: vi.fn(),
},
adminRepo: {
logActivity: vi.fn(),
},
}));
vi.mock('./logger.server', () => ({
logger: {
info: vi.fn(),
error: vi.fn(),
warn: vi.fn(),
debug: vi.fn(),
},
}));
vi.mock('./emailService.server', () => ({
sendPasswordResetEmail: vi.fn(),
}));
vi.mock('./db/connection.db', () => ({
getPool: vi.fn(),
}));
vi.mock('../utils/authUtils', () => ({
validatePasswordStrength: vi.fn(),
}));
describe('AuthService', () => { describe('AuthService', () => {
let authService: typeof import('./authService').authService;
let bcrypt: typeof import('bcrypt');
let jwt: typeof import('jsonwebtoken');
let userRepo: typeof import('./db/index.db').userRepo;
let adminRepo: typeof import('./db/index.db').adminRepo;
let logger: typeof import('./logger.server').logger;
let sendPasswordResetEmail: typeof import('./emailService.server').sendPasswordResetEmail;
const reqLog = {}; // Mock request logger object const reqLog = {}; // Mock request logger object
const mockUser = { const mockUser = {
user_id: 'user-123', user_id: 'user-123',
@@ -76,8 +22,59 @@ describe('AuthService', () => {
role: 'user', role: 'user',
} as unknown as UserProfile; } as unknown as UserProfile;
beforeEach(() => { beforeEach(async () => {
vi.clearAllMocks(); vi.clearAllMocks();
vi.resetModules();
// Set environment variables before any modules are imported
process.env.JWT_SECRET = 'test-secret';
process.env.FRONTEND_URL = 'http://localhost:3000';
// Mock all dependencies before dynamically importing the service
vi.mock('bcrypt');
vi.mock('jsonwebtoken');
vi.mock('crypto', () => ({
default: {
randomBytes: vi.fn().mockReturnValue({
toString: vi.fn().mockReturnValue('mocked-random-string'),
}),
},
}));
vi.mock('./db/index.db', () => ({
userRepo: {
createUser: vi.fn(),
saveRefreshToken: vi.fn(),
findUserByEmail: vi.fn(),
createPasswordResetToken: vi.fn(),
getValidResetTokens: vi.fn(),
updateUserPassword: vi.fn(),
deleteResetToken: vi.fn(),
findUserByRefreshToken: vi.fn(),
findUserProfileById: vi.fn(),
deleteRefreshToken: vi.fn(),
},
adminRepo: {
logActivity: vi.fn(),
},
}));
vi.mock('./logger.server', () => ({
logger: { info: vi.fn(), error: vi.fn(), warn: vi.fn(), debug: vi.fn() },
}));
vi.mock('./emailService.server', () => ({
sendPasswordResetEmail: vi.fn(),
}));
vi.mock('./db/connection.db', () => ({ getPool: vi.fn() }));
vi.mock('../utils/authUtils', () => ({ validatePasswordStrength: vi.fn() }));
// Dynamically import modules to get the mocked versions and the service instance
authService = (await import('./authService')).authService;
bcrypt = await import('bcrypt');
jwt = await import('jsonwebtoken');
const dbModule = await import('./db/index.db');
userRepo = dbModule.userRepo;
adminRepo = dbModule.adminRepo;
logger = (await import('./logger.server')).logger;
sendPasswordResetEmail = (await import('./emailService.server')).sendPasswordResetEmail;
}); });
describe('registerUser', () => { describe('registerUser', () => {

View File

@@ -242,7 +242,10 @@ export class FlyerProcessingService {
// Mark subsequent critical stages as skipped // Mark subsequent critical stages as skipped
for (let i = errorStageIndex + 1; i < stagesToReport.length; i++) { for (let i = errorStageIndex + 1; i < stagesToReport.length; i++) {
if (stagesToReport[i].critical) { if (stagesToReport[i].critical) {
stagesToReport[i] = { ...stagesToReport[i], status: 'skipped' }; // When a stage is skipped, we don't need its previous 'detail' property.
// This creates a clean 'skipped' state object by removing `detail` and keeping the rest.
const { detail, ...restOfStage } = stagesToReport[i];
stagesToReport[i] = { ...restOfStage, status: 'skipped' };
} }
} }
} }

View File

@@ -1,3 +1,4 @@
// src/services/systemService.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest'; import { describe, it, expect, vi, beforeEach } from 'vitest';
import { exec, type ExecException } from 'child_process'; import { exec, type ExecException } from 'child_process';
import { logger } from './logger.server'; import { logger } from './logger.server';
@@ -35,10 +36,11 @@ vi.mock('util', async (importOriginal) => {
}); });
// Mock child_process // Mock child_process
vi.mock('child_process', () => { vi.mock('child_process', async (importOriginal) => {
const mockExec = vi.fn(); const actual = await importOriginal<typeof import('child_process')>();
return { return {
exec: mockExec, ...actual,
exec: vi.fn(),
}; };
}); });