Files
dh-inspeccion-v2/api-v3/test/unit/phase-d5-5-web-planning-checklist.test.ts

67 lines
3.7 KiB
TypeScript

import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
import test from 'node:test';
const root = process.cwd();
const read = (relative: string) => fs.readFileSync(path.join(root, relative), 'utf8');
test('D5.5 stores explicit Area and Operator context plus append-only checklist generations', () => {
const migration = read('src/database/migrations/1789063200000-phase-d5-5-web-planning-checklist.ts');
assert.match(migration, /ADD COLUMN operational_area_id uuid/);
assert.match(migration, /ADD COLUMN operator_company_id uuid/);
assert.match(migration, /CREATE TABLE inspection_visit_checklist_items/);
assert.match(migration, /generation_number integer NOT NULL/);
assert.match(migration, /REVOKE UPDATE, DELETE ON TABLE[\s\S]*inspection_visit_checklist_items, inspection_visit_asset_events/);
});
test('D5.5 exposes Area then active OPERATOR choices and a server-generated planning checklist', () => {
const controller = read('src/inspection-visits/inspection-visits.controller.ts');
const service = read('src/inspection-visits/inspection-visits.service.ts');
assert.match(controller, /@Get\('planning-context\/areas'\)/);
assert.match(controller, /@Get\('planning-context\/areas\/:areaId\/operators'\)/);
assert.match(controller, /@Post\(':id\/checklist\/generate'\)/);
assert.match(service, /relation\.relation_role = 'OPERATOR'/);
assert.match(service, /INSPECTION_OPERATOR_NOT_ACTIVE_IN_AREA/);
});
test('D5.5 classifies antecedents overdue items and next controls while adding actionable assets automatically', () => {
const service = read('src/inspection-visits/inspection-visits.service.ts');
assert.match(service, /'COMPANY_OVERDUE'/);
assert.match(service, /'VERIFICATION_OVERDUE'/);
assert.match(service, /'UPCOMING_CONTROL'/);
assert.match(service, /'ANTECEDENT'/);
assert.match(service, /item_kind IN \('COMPANY_OVERDUE','VERIFICATION_OVERDUE','UPCOMING_CONTROL'\)/);
assert.match(service, /'AUTO_INCLUDED'/);
});
test('D5.5 treats manual additions as preventive and requires an auditable reason for exclusions', () => {
const service = read('src/inspection-visits/inspection-visits.service.ts');
const dto = read('src/inspection-visits/dto/exclude-inspection-visit-asset.dto.ts');
assert.match(service, /planning_source[^\n]*[\s\S]*'PREVENTIVE'/);
assert.match(service, /INSPECTION_EXCLUSION_REASON_REQUIRED/);
assert.match(service, /INSPECTION_VISIT_ASSET_EXCLUDED/);
assert.match(service, /INSPECTION_VISIT_ASSET_REINCLUDED/);
assert.match(dto, /@MinLength\(10\)/);
});
test('D5.5/F4 keeps verification visits inside the Area Operator contract and start remains APK-only', () => {
const verification = read('src/inspection-verifications/inspection-verifications.service.ts');
const lifecycle = read('src/inspection-visits/inspection-visit-lifecycle.service.ts');
assert.match(verification, /operationalAreaId: areaId/);
assert.match(verification, /operatorCompanyId: companyId/);
assert.match(verification, /planning_source = 'VERIFICATION'/);
assert.match(lifecycle, /assertMobileInspector\(principal\)/);
assert.match(lifecycle, /INSPECTION_CHECKLIST_REQUIRED/);
});
test('D5.5/F4 requires a current checklist before planning or start and keeps start under mobile policy', () => {
const lifecycle = read('src/inspection-visits/inspection-visit-lifecycle.service.ts');
const policy = read('src/inspection-operations/mobile-inspector-policy.ts');
assert.match(lifecycle, /INSPECTION_CHECKLIST_REQUIRED/);
assert.match(lifecycle, /checklistGeneratedAt/);
assert.match(lifecycle, /assertMobileInspector\(principal\)/);
assert.match(policy, /transport !== 'bearer'/);
assert.match(policy, /includes\('inspector'\)/);
});