feat: add tests for QuickImportService and ReceiptImportService parse flow
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
import { ReceiptImportService } from './receipt-import.service';
|
||||
import { FlatCategory } from '../categories/categories.service';
|
||||
|
||||
function cat(id: number, name: string, path: string): FlatCategory {
|
||||
return { id, name, path };
|
||||
}
|
||||
|
||||
describe('ReceiptImportService parseReceipt flow', () => {
|
||||
const categories: FlatCategory[] = [
|
||||
cat(30, 'Mejeri, ost & ägg', 'Mejeri, ost & ägg'),
|
||||
cat(53, 'Choklad', 'Glass, godis & snacks > Choklad'),
|
||||
cat(51, 'Godis', 'Glass, godis & snacks > Godis'),
|
||||
];
|
||||
|
||||
const prismaMock = {
|
||||
receiptAlias: { findMany: jest.fn() },
|
||||
product: { findMany: jest.fn() },
|
||||
unitMapping: { findMany: jest.fn() },
|
||||
user: { findUnique: jest.fn() },
|
||||
};
|
||||
|
||||
const aiServiceMock = {
|
||||
suggestCategory: jest.fn(),
|
||||
};
|
||||
|
||||
const categoriesServiceMock = {
|
||||
findFlattened: jest.fn(),
|
||||
};
|
||||
|
||||
const service = new ReceiptImportService(
|
||||
prismaMock as any,
|
||||
aiServiceMock as any,
|
||||
categoriesServiceMock as any,
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
categoriesServiceMock.findFlattened.mockResolvedValue(categories);
|
||||
prismaMock.unitMapping.findMany.mockResolvedValue([]);
|
||||
prismaMock.user.findUnique.mockResolvedValue({ aiEngineEnabled: true });
|
||||
});
|
||||
|
||||
it('kör prioriteringskedjan i parseReceipt: user alias -> global alias -> wordmatch -> AI', async () => {
|
||||
prismaMock.receiptAlias.findMany.mockResolvedValue([
|
||||
{
|
||||
receiptName: 'mixad vara',
|
||||
product: {
|
||||
id: 901,
|
||||
name: 'User Produkt',
|
||||
canonicalName: 'User Produkt',
|
||||
categoryRef: { id: 30, name: 'Mejeri, ost & ägg' },
|
||||
},
|
||||
},
|
||||
{
|
||||
receiptName: 'global choklad',
|
||||
product: {
|
||||
id: 900,
|
||||
name: 'Global Produkt',
|
||||
canonicalName: 'Global Produkt',
|
||||
categoryRef: { id: 53, name: 'Choklad' },
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
prismaMock.product.findMany.mockResolvedValue([
|
||||
{
|
||||
id: 777,
|
||||
name: 'Specialprodukt',
|
||||
canonicalName: 'Specialprodukt',
|
||||
categoryRef: { id: 30, name: 'Mejeri, ost & ägg' },
|
||||
},
|
||||
]);
|
||||
|
||||
aiServiceMock.suggestCategory.mockResolvedValue({
|
||||
categoryId: 51,
|
||||
categoryName: 'Godis',
|
||||
path: 'Glass, godis & snacks > Godis',
|
||||
confidence: 'low',
|
||||
});
|
||||
|
||||
jest
|
||||
.spyOn(service as any, 'parseReceiptViaImporter')
|
||||
.mockResolvedValue([
|
||||
{ rawName: 'MIXAD VARA', quantity: 1, unit: 'st' },
|
||||
{ rawName: 'GLOBAL CHOKLAD', quantity: 1, unit: 'st' },
|
||||
{ rawName: 'SPECIALPRODUKT 1st', quantity: 1, unit: 'st' },
|
||||
{ rawName: 'helt okänd vara', quantity: 1, unit: 'st' },
|
||||
]);
|
||||
|
||||
const file = {
|
||||
buffer: Buffer.from('dummy'),
|
||||
mimetype: 'image/jpeg',
|
||||
originalname: 'receipt.jpg',
|
||||
} as any;
|
||||
|
||||
const result = await service.parseReceipt(file, false, 10);
|
||||
|
||||
expect(result).toHaveLength(4);
|
||||
|
||||
expect(result[0].matchedVia).toBe('alias');
|
||||
expect(result[0].matchedProductId).toBe(901);
|
||||
|
||||
expect(result[1].matchedVia).toBe('alias');
|
||||
expect(result[1].matchedProductId).toBe(900);
|
||||
|
||||
expect(result[2].matchedVia).toBe('wordmatch');
|
||||
expect(result[2].suggestedProductId).toBe(777);
|
||||
expect(result[2].categorySuggestion?.categoryId).toBe(30);
|
||||
|
||||
expect(result[3].matchedVia).toBe('none');
|
||||
expect(result[3].categorySuggestion?.categoryId).toBe(51);
|
||||
|
||||
expect(aiServiceMock.suggestCategory).toHaveBeenCalledTimes(1);
|
||||
expect(aiServiceMock.suggestCategory).toHaveBeenCalledWith('helt okänd vara', categories);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user