Files
tilbudgivern/backend/__tests__/projectAiService.test.js
T

35 lines
1.8 KiB
JavaScript

const ProjectAiService = require('../src/services/projectAiService');
const { buildRisk, diffValues } = require('../src/services/projectAiService');
describe('ProjectAiService', () => {
test('computes deterministic risk and a bounded before/after diff', () => {
const risk = buildRisk({
project: { description: '' }, geometry: {}, materials: [], rentals: [], labor: []
});
expect(risk.level).toBe('high');
expect(risk.score).toBeGreaterThanOrEqual(60);
expect(diffValues({ total: 100 }, { total: 120 })).toEqual([{ field: 'total', before: 100, after: 120 }]);
});
test('fact-lock rejects numbers not present in the project', () => {
const service = new ProjectAiService({}, { codexRunner: jest.fn() });
expect(() => service.assertFactLockedText({ customerText: 'Pris 999 kr.', internalText: null }, { price: 100 }))
.toThrow('introducerede nye tal');
});
test('turns fact-locked customer text into a confirmable stored suggestion', async () => {
const execute = jest.fn().mockResolvedValue([{}]);
const service = new ProjectAiService({ pool: { execute } }, {
codexRunner: jest.fn().mockResolvedValue({
feature: 'customer_text', status: 'passed', summary: 'Klar', score: null, level: null,
findings: [], suggestions: [], customerText: 'Arbejdet omfatter 10 m2 tag.', internalText: null
})
});
const context = { snapshot: { project: { id: 7 }, area: 10, stateHash: 'abc' } };
const result = await service.runFeature({ feature: 'customer_text', context }, { id: 'job', projectId: 7, type: 'customer_text' });
expect(result.suggestions[0]).toMatchObject({ action: 'update_customer_text', targetId: '7' });
expect(result.stateHash).toBe('abc');
expect(execute).toHaveBeenCalledWith(expect.stringContaining('INSERT INTO ai_suggestions'), expect.any(Array));
});
});