test: fijar invariantes transversales F6.1

This commit is contained in:
2026-09-09 14:47:19 -03:00
parent 0959e85487
commit 5a9c4ed5ef
@@ -0,0 +1,71 @@
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import test from 'node:test';
function source(path: string): string {
return readFileSync(resolve(process.cwd(), path), 'utf8');
}
test('F6.1 conserva una jerarquía territorial única y Empresa fuera del árbol físico', () => {
const structure = source('src/asset-master/inventory-structure.service.ts');
const dto = source('src/asset-master/dto/create-inventory-structure.dto.ts');
assert.match(dto, /'EMPRESA',[\s\S]*'DEPARTAMENTO',[\s\S]*'AREA',[\s\S]*'YACIMIENTO',[\s\S]*'INSTALACION',[\s\S]*'SUBINSTALACION'/);
assert.match(structure, /EMPRESA:\s*null/);
assert.match(structure, /DEPARTAMENTO:\s*null/);
assert.match(structure, /AREA:\s*'departamento'/);
assert.match(structure, /YACIMIENTO:\s*'area'/);
assert.match(structure, /INSTALACION:\s*'yacimiento'/);
assert.match(structure, /SUBINSTALACION:\s*'instalacion'/);
assert.match(structure, /Departamento → Área → Yacimiento → Instalación → Subinstalación/);
});
test('F6.1 usa Área + Operadora como contexto de planificación y no mezcla Yacimiento con Área', () => {
const lifecycle = source('src/inspection-visits/inspection-visit-lifecycle.service.ts');
const visits = source('src/inspection-visits/inspection-visits.service.ts');
assert.match(lifecycle, /El contexto operativo de una Inspección es Área \+ Operadora vigente/);
assert.doesNotMatch(lifecycle, /Área\/Yacimiento/);
assert.match(visits, /FROM area_company_relations/);
assert.match(visits, /relation\.relation_role = 'OPERATOR'/);
});
test('F6.1 mantiene múltiples Actas por Inspección pero un solo borrador simultáneo', () => {
const act = source('src/database/entities/inspection-act.entity.ts');
const lifecycle = source('src/inspection-visits/inspection-visit-lifecycle.service.ts');
assert.match(act, /uq_inspection_acts_one_draft_per_visit/);
assert.match(act, /where: "status = 'DRAFT'"/);
assert.match(act, /Una Inspección puede acumular múltiples Actas/);
assert.match(lifecycle, /Todas las Actas deben estar SELLADAS antes de cerrar la Inspección/);
});
test('F6.1 permite Hallazgos directos sólo en Yacimiento, Instalación y Subinstalación y conserva OTROS', () => {
const field = source('src/inspection-visits/field-findings.service.ts');
const resolver = source('src/inspection-findings/f3-finding-catalog-resolver.service.ts');
assert.match(field, /\['yacimiento', 'instalacion', 'subinstalacion'\]\.includes\(assetTypeCode\)/);
assert.match(field, /assetTypeCode !== 'yacimiento' && !row\.inventoryFamilyId/);
assert.match(field, /canAddAnother: true/);
assert.match(resolver, /code: 'OTHER'/);
assert.match(resolver, /label: 'OTROS'/);
});
test('F6.1 abre Inspecciones desde Android usando el lifecycle canónico', () => {
const controller = source('src/inspection-visits/inspection-visits.controller.ts');
assert.match(controller, /@Post\('mobile\/open'\)/);
assert.match(controller, /leadInspectorUserId: principal\.userId/);
assert.match(controller, /this\.lifecycle\.plan\(created\.id/);
assert.match(controller, /this\.lifecycle\.start\(created\.id/);
});
test('F6.1 separa oficialización GEDO de la activación del vencimiento no urgente', () => {
const report = source('src/inspection-reports/inspection-report-workflow.service.ts');
const act = source('src/database/entities/inspection-act.entity.ts');
assert.match(report, /GEDO oficializa el INF, pero no equivale por sí solo a la notificación/);
assert.match(report, /deadlineActivation: 'PENDING_NOTIFICATION_EVENT'/);
assert.match(act, /NOTIFICATION_DATE = 'GEDO_DATE'/);
});