Files
flyer-crawler.projectium.com/src/services/analyticsService.server.test.ts
Torben Sorensen 52dba6f890
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Has been cancelled
moar!
2025-12-29 20:16:02 -08:00

153 lines
4.7 KiB
TypeScript

// src/services/analyticsService.server.test.ts
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { AnalyticsService } from './analyticsService.server';
import { logger } from './logger.server';
import type { Job } from 'bullmq';
import type { AnalyticsJobData, WeeklyAnalyticsJobData } from '../types/job-data';
// Mock logger
vi.mock('./logger.server', () => ({
logger: {
child: vi.fn(),
info: vi.fn(),
error: vi.fn(),
},
}));
describe('AnalyticsService', () => {
let service: AnalyticsService;
let mockLoggerInstance: any;
beforeEach(() => {
vi.clearAllMocks();
vi.useFakeTimers();
// Setup mock logger instance returned by child()
mockLoggerInstance = {
info: vi.fn(),
error: vi.fn(),
warn: vi.fn(),
debug: vi.fn(),
};
vi.mocked(logger.child).mockReturnValue(mockLoggerInstance);
service = new AnalyticsService();
});
afterEach(() => {
vi.useRealTimers();
});
const createMockJob = <T>(data: T): Job<T> =>
({
id: 'job-123',
name: 'analytics-job',
data,
attemptsMade: 1,
updateProgress: vi.fn(),
} as unknown as Job<T>);
describe('processDailyReportJob', () => {
it('should process successfully', async () => {
const job = createMockJob<AnalyticsJobData>({ reportDate: '2023-10-27' } as AnalyticsJobData);
const promise = service.processDailyReportJob(job);
// Fast-forward time to bypass the 10s delay
await vi.advanceTimersByTimeAsync(10000);
const result = await promise;
expect(result).toEqual({ status: 'success', reportDate: '2023-10-27' });
expect(logger.child).toHaveBeenCalledWith(
expect.objectContaining({
jobId: 'job-123',
reportDate: '2023-10-27',
}),
);
expect(mockLoggerInstance.info).toHaveBeenCalledWith('Picked up daily analytics job.');
expect(mockLoggerInstance.info).toHaveBeenCalledWith(
'Successfully generated report for 2023-10-27.',
);
});
it('should handle failure when reportDate is FAIL', async () => {
const job = createMockJob<AnalyticsJobData>({ reportDate: 'FAIL' } as AnalyticsJobData);
const promise = service.processDailyReportJob(job);
await expect(promise).rejects.toThrow('This is a test failure for the analytics job.');
expect(mockLoggerInstance.error).toHaveBeenCalledWith(
expect.objectContaining({
err: expect.any(Error),
attemptsMade: 1,
}),
'Daily analytics job failed.',
);
});
});
describe('processWeeklyReportJob', () => {
it('should process successfully', async () => {
const job = createMockJob<WeeklyAnalyticsJobData>({
reportYear: 2023,
reportWeek: 43,
} as WeeklyAnalyticsJobData);
const promise = service.processWeeklyReportJob(job);
await vi.advanceTimersByTimeAsync(30000);
const result = await promise;
expect(result).toEqual({ status: 'success', reportYear: 2023, reportWeek: 43 });
expect(logger.child).toHaveBeenCalledWith(
expect.objectContaining({
jobId: 'job-123',
reportYear: 2023,
reportWeek: 43,
}),
);
expect(mockLoggerInstance.info).toHaveBeenCalledWith('Picked up weekly analytics job.');
expect(mockLoggerInstance.info).toHaveBeenCalledWith(
'Successfully generated weekly report for week 43, 2023.',
);
});
it('should handle errors during processing', async () => {
const job = createMockJob<WeeklyAnalyticsJobData>({
reportYear: 2023,
reportWeek: 43,
} as WeeklyAnalyticsJobData);
// Make the second info call throw to simulate an error inside the try block
mockLoggerInstance.info
.mockImplementationOnce(() => {}) // "Picked up..."
.mockImplementationOnce(() => {
throw new Error('Processing failed');
}); // "Successfully generated..."
// Get the promise from the service method.
const promise = service.processWeeklyReportJob(job);
// Capture the expectation promise BEFORE triggering the rejection.
const expectation = expect(promise).rejects.toThrow('Processing failed');
// Advance timers to trigger the part of the code that throws.
await vi.advanceTimersByTimeAsync(30000);
// Await the expectation to ensure assertions ran.
await expectation;
// Verify the side effect (error logging) after the rejection is confirmed.
expect(mockLoggerInstance.error).toHaveBeenCalledWith(
expect.objectContaining({
err: expect.any(Error),
attemptsMade: 1,
}),
'Weekly analytics job failed.',
);
});
});
});