Files
boc/projects/landvex/api/tests/identify.e2e.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

177 lines
5.7 KiB
JavaScript

/**
* E2E-tester för Identify (Skvadron F)
*
* DoD:
* - identify-modell bakom API:t
* - Golden-case-regressionssvit
* - Konfidenskalibrering rapporterad
* - Tills modellen når tröskel: svara med klasskandidat + ärlig konfidens
*/
const request = require('supertest');
const app = require('../src/app');
const Identify = require('../src/models/identify');
describe('Skvadron F · Vision & identify', () => {
describe('POST /v0/identify', () => {
test('Case 1: GE-armatur identifierad med hög konfidens', async () => {
const res = await request(app)
.post('/v0/identify')
.send({
bild: '(gatuvy: cobrahead-armatur)',
position: { lat: 36.16, lon: -115.14, land: 'US' },
ocr_extraherat: ['GE', 'ERS2', '4000K']
});
expect(res.status).toBe(200);
expect(res.body.kandidater).toHaveLength(1);
expect(res.body.kandidater[0].lvx_id).toBe('LVX-P-0000002');
expect(res.body.kandidater[0].konfidens).toBe(0.94);
expect(res.body.kandidater[0].verifieringsniva).toBe('kallbelagd');
expect(res.body.konfidens_rapporterad).toBe(true);
});
test('Case 2: Hydrant åldersbestämd ur gjutgodset', async () => {
const res = await request(app)
.post('/v0/identify')
.send({
bild: '(hydrant, närbild)',
position: { lat: 32.78, lon: -96.80, land: 'US' },
ocr_extraherat: ['AMERICAN-DARLING', 'B-84-B-5', '1998', 'OPEN LEFT']
});
expect(res.status).toBe(200);
expect(res.body.kandidater[0].lvx_id).toBe('LVX-P-0000016');
expect(res.body.kandidater[0].konfidens).toBe(0.97);
expect(res.body.kandidater[0].individdata_ur_ocr).toBeDefined();
});
test('Case 3: Okänd modell — ärligt svar + bounty skapas', async () => {
const res = await request(app)
.post('/v0/identify')
.send({
bild: '(grått gatuskåp utan etikett)',
position: { lat: 51.51, lon: -0.13, land: 'UK' },
ocr_extraherat: [],
kund_ref: 'kund-789'
});
expect(res.status).toBe(200);
expect(res.body.kandidater[0].niva).toBe('objektklass');
expect(res.body.kandidater[0].konfidens).toBe(0.71);
expect(res.body.kandidater[0].sarskiljning_mot).toBeDefined();
expect(res.body.bounty).toBeDefined();
expect(res.body.bounty.skapad).toBe(true);
expect(res.body.bounty.kundnotis).toContain('notifieras');
});
test('konfidens alltid rapporterad — aldrig dold', async () => {
const res = await request(app)
.post('/v0/identify')
.send({
position: { lat: 0, lon: 0 },
ocr_extraherat: ['helt', 'okant', 'ord']
});
expect(res.status).toBe(200);
expect(res.body.konfidens_rapporterad).toBe(true);
expect(res.body.kandidater[0].konfidens).toBeDefined();
});
});
describe('Golden-case regressionssvit', () => {
test('körs och rapporterar resultat', async () => {
const res = await request(app)
.get('/v0/identify/golden-cases');
expect(res.status).toBe(200);
expect(res.body.summary).toBeDefined();
expect(typeof res.body.summary.pass_rate).toBe('number');
});
test('golden cases kan läggas till', () => {
const testCase = Identify.addGoldenCase({
namn: 'GE Cobrahead-test',
beskrivning: 'Identifiera GE Evolve ERS2',
input_ocr: ['GE', 'ERS2'],
forvantat_svar: { lvx_id: 'LVX-P-0000002', konfidens: 0.90 }
});
expect(testCase.id).toBeDefined();
});
});
describe('Konfidenskalibrering', () => {
test('rapporteras via API', async () => {
const res = await request(app)
.get('/v0/identify/calibration');
expect(res.status).toBe(200);
expect(res.body.modell_version).toBeDefined();
expect(res.body.rapport).toBeDefined();
});
test('kan uppdateras med nya resultat', () => {
const result = Identify.updateCalibration('v1-test', '0.9-1.0', 9, 10);
expect(result.accuracy).toBe(0.9);
});
});
describe('Objekt-uppslag', () => {
test('GET /v0/objects/:lvx_id', async () => {
const res = await request(app)
.get('/v0/objects/LVX-TRP-0102');
expect(res.status).toBe(200);
expect(res.body.lvx_id).toBe('LVX-TRP-0102');
expect(res.body.namn.sv).toBeDefined();
});
test('GET /v0/objects/:lvx_id/succession', async () => {
const res = await request(app)
.get('/v0/objects/LVX-P-0000002/succession');
expect(res.status).toBe(200);
expect(res.body.kedja).toBeDefined();
});
test('GET /v0/search', async () => {
const res = await request(app)
.get('/v0/search?q=hydrant');
expect(res.status).toBe(200);
expect(res.body.results.length).toBeGreaterThan(0);
});
});
describe('Ärlig konfidens tills modell når tröskel', () => {
test('svagt svar ger låg konfidens, inte påhittad hög', async () => {
const res = await request(app)
.post('/v0/identify')
.send({
position: { lat: 0, lon: 0 },
ocr_extraherat: []
});
expect(res.status).toBe(200);
// Konfidens ska vara låg när inget OCR finns
expect(res.body.kandidater[0].konfidens).toBeLessThan(0.8);
});
test('klasskandidat ges när modell saknas', async () => {
const res = await request(app)
.post('/v0/identify')
.send({
position: { lat: 51.51, lon: -0.13, land: 'UK' },
ocr_extraherat: []
});
expect(res.status).toBe(200);
expect(res.body.kandidater[0].niva).toBe('objektklass');
expect(res.body.kandidater[0].modell).toBeNull();
expect(res.body.kandidater[0].insikt).toContain('obestämd');
});
});
});