Files
flyer-crawler.projectium.com/src/services/flyerPersistenceService.server.test.ts
Torben Sorensen eee7f36756
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 30m53s
switch to instantiating the pm2 worker in the testing threads
2026-01-06 20:56:39 -08:00

142 lines
4.3 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { FlyerPersistenceService } from './flyerPersistenceService.server';
import { withTransaction } from './db/connection.db';
import { createFlyerAndItems } from './db/flyer.db';
import { AdminRepository } from './db/admin.db';
import type { FlyerInsert, FlyerItemInsert, Flyer } from '../types';
import type { Logger } from 'pino';
import type { PoolClient } from 'pg';
// Mock dependencies
vi.mock('./db/connection.db', () => ({
withTransaction: vi.fn(),
}));
vi.mock('./db/flyer.db', () => ({
createFlyerAndItems: vi.fn(),
}));
vi.mock('./db/admin.db', () => ({
AdminRepository: vi.fn(),
}));
describe('FlyerPersistenceService', () => {
let service: FlyerPersistenceService;
let mockLogger: Logger;
let mockClient: PoolClient;
beforeEach(() => {
vi.clearAllMocks();
service = new FlyerPersistenceService();
mockLogger = {
info: vi.fn(),
error: vi.fn(),
warn: vi.fn(),
debug: vi.fn(),
child: vi.fn().mockReturnThis(),
} as unknown as Logger;
mockClient = { query: vi.fn() } as unknown as PoolClient;
// Mock withTransaction to execute the callback immediately with a mock client
vi.mocked(withTransaction).mockImplementation(async (callback) => {
return callback(mockClient);
});
});
describe('saveFlyer', () => {
const mockFlyerData = {
file_name: 'test.jpg',
store_name: 'Test Store',
image_url: 'http://example.com/image.jpg',
icon_url: 'http://example.com/icon.jpg',
checksum: 'abc',
status: 'processed',
item_count: 0,
} as FlyerInsert;
const mockItemsForDb: FlyerItemInsert[] = [];
const mockCreatedFlyer = {
flyer_id: 1,
file_name: 'test.jpg',
store_id: 10,
// ... other fields
} as Flyer;
const mockCreatedItems: any[] = [];
it('should save flyer and items, and log activity if userId is provided', async () => {
const userId = 'user-123';
vi.mocked(createFlyerAndItems).mockResolvedValue({
flyer: mockCreatedFlyer,
items: mockCreatedItems,
});
const mockLogActivity = vi.fn();
// Mock the AdminRepository constructor to return an object with logActivity
vi.mocked(AdminRepository).mockImplementation(() => ({
logActivity: mockLogActivity,
} as any));
const result = await service.saveFlyer(mockFlyerData, mockItemsForDb, userId, mockLogger);
expect(withTransaction).toHaveBeenCalled();
expect(createFlyerAndItems).toHaveBeenCalledWith(
mockFlyerData,
mockItemsForDb,
mockLogger,
mockClient
);
expect(mockLogger.info).toHaveBeenCalledWith(
expect.stringContaining('Successfully processed flyer')
);
// Verify AdminRepository usage
expect(AdminRepository).toHaveBeenCalledWith(mockClient);
expect(mockLogActivity).toHaveBeenCalledWith(
expect.objectContaining({
userId,
action: 'flyer_processed',
displayText: `Processed a new flyer for ${mockFlyerData.store_name}.`,
details: { flyerId: mockCreatedFlyer.flyer_id, storeName: mockFlyerData.store_name },
}),
mockLogger
);
expect(result).toEqual(mockCreatedFlyer);
});
it('should save flyer and items, but NOT log activity if userId is undefined', async () => {
const userId = undefined;
vi.mocked(createFlyerAndItems).mockResolvedValue({
flyer: mockCreatedFlyer,
items: mockCreatedItems,
});
const mockLogActivity = vi.fn();
vi.mocked(AdminRepository).mockImplementation(() => ({
logActivity: mockLogActivity,
} as any));
const result = await service.saveFlyer(mockFlyerData, mockItemsForDb, userId, mockLogger);
expect(createFlyerAndItems).toHaveBeenCalled();
expect(AdminRepository).not.toHaveBeenCalled();
expect(mockLogActivity).not.toHaveBeenCalled();
expect(result).toEqual(mockCreatedFlyer);
});
it('should propagate errors from createFlyerAndItems', async () => {
const error = new Error('DB Error');
vi.mocked(createFlyerAndItems).mockRejectedValue(error);
await expect(
service.saveFlyer(mockFlyerData, mockItemsForDb, 'user-1', mockLogger)
).rejects.toThrow(error);
});
});
});