Files
boc/vims-backend/tests/riskClassifier.test.js
T
Bernt 6de2455917 v1.2.0: Add Global Markets footer, translated to 9 languages
- Added GLOBAL_MARKETS_TITLE to all translation files
- Updated footer with 12 markets (4 active + 8 upcoming)
- Translated market section to: zh-cn, zh-tw, ja, ko, th, vi, id, ms, hi
- Built and deployed to production
- CloudFront invalidation: I3RTMXVFDJXWLG3SYX208OP1CC
2026-07-08 19:56:03 +00:00

228 lines
5.8 KiB
JavaScript

/**
* Risk Classifier Service Tests
*/
const { RiskClassifierService } = require('../src/services/riskClassifier');
describe('RiskClassifierService', () => {
let service;
beforeEach(() => {
service = new RiskClassifierService();
});
describe('classify', () => {
it('should classify skimmer as red', () => {
const detection = {
anomalyType: 'skimmer',
confidence: 0.95
};
const result = service.classify(detection, 'atm');
expect(result.level).toBe('red');
expect(result.action).toBe('immediate_alert');
});
it('should classify camera blocked as orange', () => {
const detection = {
anomalyType: 'camera_blocked',
confidence: 0.8
};
const result = service.classify(detection, 'atm');
expect(result.level).toBe('orange');
});
it('should escalate high confidence anomalies', () => {
const detection = {
anomalyType: 'display_changed',
confidence: 0.95
};
const result = service.classify(detection, 'atm');
// display_changed is yellow but high confidence should escalate
expect(result.level).toBe('orange');
});
it('should de-escalate low confidence anomalies', () => {
const detection = {
anomalyType: 'pin_pad_modified',
confidence: 0.3
};
const result = service.classify(detection, 'atm');
// pin_pad_modified is red but low confidence should de-escalate
expect(result.level).toBe('orange');
});
});
describe('aggregate', () => {
it('should return green for no classifications', () => {
const result = service.aggregate([]);
expect(result.level).toBe('green');
});
it('should return highest risk level', () => {
const classifications = [
{ level: 'green', reason: 'Normal' },
{ level: 'yellow', reason: 'Minor' },
{ level: 'red', reason: 'Critical' }
];
const result = service.aggregate(classifications);
expect(result.level).toBe('red');
});
it('should count by level', () => {
const classifications = [
{ level: 'yellow', reason: 'Minor 1' },
{ level: 'yellow', reason: 'Minor 2' },
{ level: 'orange', reason: 'Major' }
];
const result = service.aggregate(classifications);
expect(result.counts.yellow).toBe(2);
expect(result.counts.orange).toBe(1);
});
it('should determine action based on highest risk', () => {
const classifications = [
{ level: 'yellow', reason: 'Minor' }
];
const result = service.aggregate(classifications);
expect(result.action).toBe('verify_maintenance');
});
it('should escalate action for multiple yellow', () => {
const classifications = [
{ level: 'yellow', reason: 'Minor 1' },
{ level: 'yellow', reason: 'Minor 2' },
{ level: 'yellow', reason: 'Minor 3' }
];
const result = service.aggregate(classifications);
expect(result.action).toBe('scheduled_inspection');
});
});
describe('processObservation', () => {
it('should process observation with no anomalies', () => {
const observation = { id: 'obs-1' };
const detections = [
{ componentType: 'card_reader', confidence: 0.9, isAnomaly: false }
];
const result = service.processObservation(observation, detections, 'atm');
expect(result.level).toBe('green');
});
it('should process observation with anomalies', () => {
const observation = { id: 'obs-1' };
const detections = [
{ componentType: 'skimmer', confidence: 0.9, isAnomaly: true }
];
const result = service.processObservation(observation, detections, 'atm');
expect(result.level).toBe('red');
expect(result.observationId).toBe('obs-1');
});
});
describe('calculateTrend', () => {
it('should detect increasing trend', () => {
const history = [
{ level: 'green' },
{ level: 'yellow' },
{ level: 'orange' }
];
const result = service.calculateTrend(history);
expect(result.trend).toBe('increasing');
});
it('should detect decreasing trend', () => {
const history = [
{ level: 'red' },
{ level: 'orange' },
{ level: 'yellow' }
];
const result = service.calculateTrend(history);
expect(result.trend).toBe('decreasing');
});
it('should detect stable trend', () => {
const history = [
{ level: 'green' },
{ level: 'green' },
{ level: 'green' }
];
const result = service.calculateTrend(history);
expect(result.trend).toBe('stable');
});
it('should return stable for insufficient data', () => {
const result = service.calculateTrend([]);
expect(result.trend).toBe('stable');
expect(result.confidence).toBe(0);
});
});
describe('validateRules', () => {
it('should validate correct rules', () => {
const rules = {
atm: {
skimmer: { level: 'red', action: 'immediate_alert' }
}
};
const result = service.validateRules(rules);
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
it('should detect invalid level', () => {
const rules = {
atm: {
skimmer: { level: 'invalid', action: 'immediate_alert' }
}
};
const result = service.validateRules(rules);
expect(result.valid).toBe(false);
expect(result.errors.length).toBeGreaterThan(0);
});
it('should detect invalid action', () => {
const rules = {
atm: {
skimmer: { level: 'red', action: 'invalid_action' }
}
};
const result = service.validateRules(rules);
expect(result.valid).toBe(false);
});
});
});