/** * Object Detection Service Tests */ const { ObjectDetectionService } = require('../src/services/objectDetection'); describe('ObjectDetectionService', () => { let service; beforeEach(() => { service = new ObjectDetectionService(); }); describe('detect', () => { it('should detect components in ATM image', async () => { // Create a valid JPEG buffer const sharp = require('sharp'); const mockImage = await sharp({ create: { width: 640, height: 480, channels: 3, background: { r: 128, g: 128, b: 128 } } }).jpeg().toBuffer(); const result = await service.detect(mockImage, 'atm'); expect(result).toHaveProperty('detections'); expect(result).toHaveProperty('modelVersion'); expect(result).toHaveProperty('inferenceTime'); expect(Array.isArray(result.detections)).toBe(true); }); it('should return detections with required fields', async () => { const sharp = require('sharp'); const mockImage = await sharp({ create: { width: 640, height: 480, channels: 3, background: { r: 128, g: 128, b: 128 } } }).jpeg().toBuffer(); const result = await service.detect(mockImage, 'atm'); if (result.detections.length > 0) { const detection = result.detections[0]; expect(detection).toHaveProperty('componentType'); expect(detection).toHaveProperty('componentName'); expect(detection).toHaveProperty('confidence'); expect(detection).toHaveProperty('boundingBox'); expect(detection.confidence).toBeGreaterThan(0); expect(detection.confidence).toBeLessThanOrEqual(1); } }); it('should handle unknown object type', async () => { const sharp = require('sharp'); const mockImage = await sharp({ create: { width: 640, height: 480, channels: 3, background: { r: 128, g: 128, b: 128 } } }).jpeg().toBuffer(); const result = await service.detect(mockImage, 'unknown_type'); expect(result.detections).toEqual([]); }); }); describe('detectAnomalies', () => { it('should detect new components', async () => { const current = [ { componentType: 'card_reader', confidence: 0.9, boundingBox: { x: 0.1, y: 0.1, width: 0.2, height: 0.2 } }, { componentType: 'skimmer', confidence: 0.8, boundingBox: { x: 0.1, y: 0.1, width: 0.2, height: 0.2 } } ]; const reference = [ { componentType: 'card_reader', confidence: 0.9, boundingBox: { x: 0.1, y: 0.1, width: 0.2, height: 0.2 } } ]; const anomalies = await service.detectAnomalies(current, reference, 'atm'); expect(anomalies.length).toBeGreaterThan(0); expect(anomalies[0].type).toBe('new_object'); }); it('should detect missing components', async () => { const current = [ { componentType: 'card_reader', confidence: 0.9, boundingBox: { x: 0.1, y: 0.1, width: 0.2, height: 0.2 } } ]; const reference = [ { componentType: 'card_reader', confidence: 0.9, boundingBox: { x: 0.1, y: 0.1, width: 0.2, height: 0.2 } }, { componentType: 'camera', confidence: 0.9, boundingBox: { x: 0.5, y: 0.5, width: 0.1, height: 0.1 } } ]; const anomalies = await service.detectAnomalies(current, reference, 'atm'); const missing = anomalies.find(a => a.type === 'missing_component'); expect(missing).toBeDefined(); expect(missing.component).toBe('camera'); }); }); describe('applyNMS', () => { it('should remove overlapping detections', () => { const detections = [ { componentType: 'card_reader', confidence: 0.9, boundingBox: { x: 0.1, y: 0.1, width: 0.2, height: 0.2 } }, { componentType: 'card_reader', confidence: 0.7, boundingBox: { x: 0.12, y: 0.12, width: 0.18, height: 0.18 } }, { componentType: 'pin_pad', confidence: 0.8, boundingBox: { x: 0.5, y: 0.5, width: 0.2, height: 0.2 } } ]; const result = service.applyNMS(detections, 0.5); // Should keep highest confidence card_reader and pin_pad expect(result.length).toBe(2); expect(result[0].componentType).toBe('card_reader'); expect(result[0].confidence).toBe(0.9); }); }); });