Files
recipe-app/backend/src/flyer-import/flyer-import.service.spec.ts
T
Nils-Johan Gynther 6cd5b80adb
Test Suite / backend-pr-quick (push) Has been skipped
Test Suite / quick-import-pr-quick (push) Has been skipped
Test Suite / backend-full (push) Successful in 2m15s
Test Suite / flutter-quality (push) Failing after 1m25s
feat(flyer-import): add session management and retrieval endpoints
- Add new API endpoints for retrieving flyer import sessions:
  - GET /flyer-import/sessions/latest - Retrieve latest session for user
  - GET /flyer-import/sessions/:sessionId - Retrieve specific session
- Implement session persistence and restoration in Flutter UI
- Add toJson() methods to FlyerImportItem and FlyerImportResult for serialization
- Add new FlyerImportSession domain model for local session management
- Add unit test file for FlyerImportService
- Update FlyerImportController with new endpoints and user ID extraction
- Update FlyerImportService with session retrieval logic and response mapping
- Update API paths in Flutter client
- Add session restoration on widget init in FlyerImportTab
2026-05-19 21:55:55 +02:00

87 lines
2.5 KiB
TypeScript

import { NotFoundException } from '@nestjs/common';
import { FlyerImportService } from './flyer-import.service';
describe('FlyerImportService', () => {
const prismaMock = {
flyerSession: {
findFirst: jest.fn(),
},
};
const createService = () =>
new FlyerImportService(
prismaMock as any,
{} as any,
{} as any,
{} as any,
);
beforeEach(() => {
jest.clearAllMocks();
});
describe('getSession', () => {
it('throws NotFoundException when session is missing', async () => {
prismaMock.flyerSession.findFirst.mockResolvedValue(null);
const service = createService();
await expect(service.getSession(123, 1)).rejects.toBeInstanceOf(NotFoundException);
expect(prismaMock.flyerSession.findFirst).toHaveBeenCalledWith({
where: { id: 123, userId: 1 },
include: { items: { orderBy: { id: 'asc' } } },
});
});
it('returns mapped response for owned session', async () => {
prismaMock.flyerSession.findFirst.mockResolvedValue({
id: 42,
items: [
{
id: 99,
rawName: 'Tomat',
normalizedName: 'tomat',
categoryHint: 'Gronsaker',
price: { toNumber: () => 19.9 },
priceUnit: 'kg',
comparisonPrice: null,
comparisonUnit: null,
offerText: 'Max 2 kop/hushall',
parseConfidence: 0.9,
parseReasons: ['ai_parsed'],
matchedProductId: 5,
matchedProductName: 'Tomat',
matchedVia: 'exact',
matchConfidence: 0.95,
matchReasons: ['normalized_exact'],
},
],
});
const service = createService();
const result = await service.getSession(42, 1);
expect(result.sessionId).toBe(42);
expect(result.items).toHaveLength(1);
expect(result.items[0].flyerItemId).toBe(99);
expect(result.items[0].matchedVia).toBe('exact');
});
});
describe('getLatestSession', () => {
it('returns empty response when no sessions exist', async () => {
prismaMock.flyerSession.findFirst.mockResolvedValue(null);
const service = createService();
const result = await service.getLatestSession(1);
expect(result.sessionId).toBeNull();
expect(result.items).toEqual([]);
expect(prismaMock.flyerSession.findFirst).toHaveBeenCalledWith({
where: { userId: 1 },
orderBy: { createdAt: 'desc' },
include: { items: { orderBy: { id: 'asc' } } },
});
});
});
});