many fixes resultnig from latest refactoring
Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 5m46s
Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 5m46s
This commit is contained in:
@@ -9,15 +9,16 @@ vi.mock('node-cron', () => ({ default: { schedule: mockCronSchedule } }));
|
||||
|
||||
import { BackgroundJobService, startBackgroundJobs } from './backgroundJobService';
|
||||
import type { Queue } from 'bullmq';
|
||||
import { WatchedItemDeal } from '../types';
|
||||
import { AdminUserView } from './db/admin.db';
|
||||
|
||||
describe('Background Job Service', () => {
|
||||
// Create mock dependencies that will be injected into the service
|
||||
const mockDbService = {
|
||||
createBulkNotifications: vi.fn(),
|
||||
const mockPersonalizationRepo = {
|
||||
getBestSalePricesForAllUsers: vi.fn(),
|
||||
};
|
||||
const mockNotificationRepo = {
|
||||
createBulkNotifications: vi.fn(),
|
||||
};
|
||||
|
||||
const mockEmailQueue = {
|
||||
add: vi.fn(),
|
||||
};
|
||||
@@ -47,27 +48,27 @@ describe('Background Job Service', () => {
|
||||
];
|
||||
|
||||
// Instantiate the service with mock dependencies for each test run
|
||||
const service = new BackgroundJobService(mockDbService as any, mockEmailQueue as unknown as Queue<any>, mockLogger);
|
||||
const service = new BackgroundJobService(mockPersonalizationRepo as any, mockNotificationRepo as any, mockEmailQueue as unknown as Queue<any>, mockLogger);
|
||||
|
||||
it('should do nothing if no deals are found for any user', async () => {
|
||||
mockDbService.getBestSalePricesForAllUsers.mockResolvedValue([]);
|
||||
mockPersonalizationRepo.getBestSalePricesForAllUsers.mockResolvedValue([]);
|
||||
|
||||
await service.runDailyDealCheck();
|
||||
|
||||
expect(mockLogger.info).toHaveBeenCalledWith('[BackgroundJob] Starting daily deal check for all users...');
|
||||
expect(mockLogger.info).toHaveBeenCalledWith('[BackgroundJob] No deals found for any watched items. Skipping.');
|
||||
expect(mockDbService.getBestSalePricesForAllUsers).toHaveBeenCalledTimes(1);
|
||||
expect(mockPersonalizationRepo.getBestSalePricesForAllUsers).toHaveBeenCalledTimes(1);
|
||||
expect(mockEmailQueue.add).not.toHaveBeenCalled();
|
||||
expect(mockDbService.createBulkNotifications).not.toHaveBeenCalled();
|
||||
expect(mockNotificationRepo.createBulkNotifications).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should create notifications and enqueue emails when deals are found', async () => {
|
||||
mockDbService.getBestSalePricesForAllUsers.mockResolvedValue(mockDealsForAllUsers);
|
||||
mockPersonalizationRepo.getBestSalePricesForAllUsers.mockResolvedValue(mockDealsForAllUsers);
|
||||
|
||||
await service.runDailyDealCheck();
|
||||
|
||||
// Check that it fetched all deals once
|
||||
expect(mockDbService.getBestSalePricesForAllUsers).toHaveBeenCalledTimes(1);
|
||||
expect(mockPersonalizationRepo.getBestSalePricesForAllUsers).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Check that email jobs were enqueued for both users
|
||||
expect(mockEmailQueue.add).toHaveBeenCalledTimes(2);
|
||||
@@ -80,8 +81,8 @@ describe('Background Job Service', () => {
|
||||
expect(secondEmailJob[1].html).toContain('Bread');
|
||||
|
||||
// Check that in-app notifications were created for both users
|
||||
expect(mockDbService.createBulkNotifications).toHaveBeenCalledTimes(1);
|
||||
const notificationPayload = mockDbService.createBulkNotifications.mock.calls[0][0];
|
||||
expect(mockNotificationRepo.createBulkNotifications).toHaveBeenCalledTimes(1);
|
||||
const notificationPayload = mockNotificationRepo.createBulkNotifications.mock.calls[0][0];
|
||||
expect(notificationPayload).toHaveLength(2);
|
||||
// Use expect.arrayContaining to be order-agnostic.
|
||||
expect(notificationPayload).toEqual(expect.arrayContaining([
|
||||
@@ -99,7 +100,7 @@ describe('Background Job Service', () => {
|
||||
});
|
||||
|
||||
it('should handle and log errors for individual users without stopping the process', async () => {
|
||||
mockDbService.getBestSalePricesForAllUsers.mockResolvedValue(mockDealsForAllUsers);
|
||||
mockPersonalizationRepo.getBestSalePricesForAllUsers.mockResolvedValue(mockDealsForAllUsers);
|
||||
// Simulate the email queue failing for the first user but succeeding for the second
|
||||
mockEmailQueue.add
|
||||
.mockRejectedValueOnce(new Error('Email queue is down'))
|
||||
@@ -116,13 +117,13 @@ describe('Background Job Service', () => {
|
||||
// Check that it still processed user 2 successfully
|
||||
// The email queue add should be attempted for both users.
|
||||
expect(mockEmailQueue.add).toHaveBeenCalledTimes(2);
|
||||
expect(mockDbService.createBulkNotifications).toHaveBeenCalledTimes(1);
|
||||
expect(mockDbService.createBulkNotifications.mock.calls[0][0]).toHaveLength(1); // Only one notification created
|
||||
expect(mockDbService.createBulkNotifications.mock.calls[0][0][0].user_id).toBe('user-2');
|
||||
expect(mockNotificationRepo.createBulkNotifications).toHaveBeenCalledTimes(1);
|
||||
expect(mockNotificationRepo.createBulkNotifications.mock.calls[0][0]).toHaveLength(1); // Only one notification created
|
||||
expect(mockNotificationRepo.createBulkNotifications.mock.calls[0][0][0].user_id).toBe('user-2');
|
||||
});
|
||||
|
||||
it('should log a critical error if getBestSalePricesForAllUsers fails', async () => {
|
||||
mockDbService.getBestSalePricesForAllUsers.mockRejectedValue(new Error('Critical DB Failure'));
|
||||
mockPersonalizationRepo.getBestSalePricesForAllUsers.mockRejectedValue(new Error('Critical DB Failure'));
|
||||
await expect(service.runDailyDealCheck()).rejects.toThrow('Critical DB Failure');
|
||||
expect(mockLogger.error).toHaveBeenCalledWith(
|
||||
'[BackgroundJob] A critical error occurred during the daily deal check:',
|
||||
@@ -139,23 +140,28 @@ describe('Background Job Service', () => {
|
||||
const mockAnalyticsQueue = {
|
||||
add: vi.fn(),
|
||||
} as unknown as Queue;
|
||||
const mockWeeklyAnalyticsQueue = {
|
||||
add: vi.fn(),
|
||||
} as unknown as Queue;
|
||||
|
||||
beforeEach(() => {
|
||||
mockCronSchedule.mockClear();
|
||||
vi.mocked(mockBackgroundJobService.runDailyDealCheck).mockClear();
|
||||
vi.mocked(mockAnalyticsQueue.add).mockClear();
|
||||
vi.mocked(mockWeeklyAnalyticsQueue.add).mockClear();
|
||||
});
|
||||
|
||||
it('should schedule two cron jobs with the correct schedules', () => {
|
||||
startBackgroundJobs(mockBackgroundJobService, mockAnalyticsQueue);
|
||||
it('should schedule three cron jobs with the correct schedules', () => {
|
||||
startBackgroundJobs(mockBackgroundJobService, mockAnalyticsQueue, mockWeeklyAnalyticsQueue);
|
||||
|
||||
expect(mockCronSchedule).toHaveBeenCalledTimes(2);
|
||||
expect(mockCronSchedule).toHaveBeenCalledTimes(3);
|
||||
expect(mockCronSchedule).toHaveBeenCalledWith('0 2 * * *', expect.any(Function));
|
||||
expect(mockCronSchedule).toHaveBeenCalledWith('0 3 * * *', expect.any(Function));
|
||||
expect(mockCronSchedule).toHaveBeenCalledWith('0 4 * * 0', expect.any(Function));
|
||||
});
|
||||
|
||||
it('should call runDailyDealCheck when the first cron job function is executed', async () => {
|
||||
startBackgroundJobs(mockBackgroundJobService, mockAnalyticsQueue);
|
||||
startBackgroundJobs(mockBackgroundJobService, mockAnalyticsQueue, mockWeeklyAnalyticsQueue);
|
||||
|
||||
// Get the callback function for the first cron job
|
||||
const dailyDealCheckCallback = mockCronSchedule.mock.calls[0][1];
|
||||
@@ -167,7 +173,7 @@ describe('Background Job Service', () => {
|
||||
it('should log an error and release the lock if runDailyDealCheck fails', async () => {
|
||||
const jobError = new Error('Cron job failed');
|
||||
vi.mocked(mockBackgroundJobService.runDailyDealCheck).mockRejectedValue(jobError);
|
||||
startBackgroundJobs(mockBackgroundJobService, mockAnalyticsQueue);
|
||||
startBackgroundJobs(mockBackgroundJobService, mockAnalyticsQueue, mockWeeklyAnalyticsQueue);
|
||||
|
||||
const dailyDealCheckCallback = mockCronSchedule.mock.calls[0][1];
|
||||
await dailyDealCheckCallback();
|
||||
@@ -189,7 +195,7 @@ describe('Background Job Service', () => {
|
||||
// Make the first call hang indefinitely
|
||||
vi.mocked(mockBackgroundJobService.runDailyDealCheck).mockReturnValue(new Promise(() => {}));
|
||||
|
||||
startBackgroundJobs(mockBackgroundJobService, mockAnalyticsQueue);
|
||||
startBackgroundJobs(mockBackgroundJobService, mockAnalyticsQueue, mockWeeklyAnalyticsQueue);
|
||||
const dailyDealCheckCallback = mockCronSchedule.mock.calls[0][1];
|
||||
|
||||
// Trigger the job once, it will hang
|
||||
@@ -204,7 +210,7 @@ describe('Background Job Service', () => {
|
||||
});
|
||||
|
||||
it('should enqueue an analytics job when the second cron job function is executed', async () => {
|
||||
startBackgroundJobs(mockBackgroundJobService, mockAnalyticsQueue);
|
||||
startBackgroundJobs(mockBackgroundJobService, mockAnalyticsQueue, mockWeeklyAnalyticsQueue);
|
||||
|
||||
const analyticsJobCallback = mockCronSchedule.mock.calls[1][1];
|
||||
await analyticsJobCallback();
|
||||
@@ -215,7 +221,7 @@ describe('Background Job Service', () => {
|
||||
it('should log an error if enqueuing the analytics job fails', async () => {
|
||||
const queueError = new Error('Redis is down');
|
||||
vi.mocked(mockAnalyticsQueue.add).mockRejectedValue(queueError);
|
||||
startBackgroundJobs(mockBackgroundJobService, mockAnalyticsQueue);
|
||||
startBackgroundJobs(mockBackgroundJobService, mockAnalyticsQueue, mockWeeklyAnalyticsQueue);
|
||||
|
||||
const analyticsJobCallback = mockCronSchedule.mock.calls[1][1];
|
||||
await analyticsJobCallback();
|
||||
|
||||
Reference in New Issue
Block a user