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 inspection planning exposes Departamento → Área → Yacimiento explicitly', () => { const hierarchy = source('src/inspection-visits/inspection-planning-hierarchy.service.ts'); const controller = source('src/inspection-visits/inspection-visits.controller.ts'); const createPage = source('../web-v2/src/pages/InspectionVisitCreateF61Page.tsx'); assert.match(hierarchy, /lower\(type\.code\)='departamento'/); assert.match(hierarchy, /area\.parent_id=\$1::uuid/); assert.match(hierarchy, /lower\(type\.code\)='yacimiento'/); assert.match(hierarchy, /yacimiento\.parent_id=\$1::uuid/); assert.match(controller, /planning-context\/departments/); assert.match(controller, /planning-context\/departments\/:departmentId\/areas/); assert.match(controller, /planning-context\/areas\/:areaId\/yacimientos/); assert.match(createPage, /Departamento → Área → Yacimiento/); assert.match(createPage, /Departamento<\/span>/); assert.match(createPage, /Área<\/span>/); assert.match(createPage, /Yacimiento<\/span>/); assert.doesNotMatch(createPage, /Área \/ Yacimiento/); }); test('F6.1 WEB creation freezes Area and uses the selected Yacimiento as physical scope', () => { const dto = source('src/inspection-visits/dto/create-inspection-visit.dto.ts'); const scope = source('src/inspection-visits/inspection-planning-scope.ts'); const create = source('src/inspection-visits/inspection-planning-create.service.ts'); const createPage = source('../web-v2/src/pages/InspectionVisitCreateF61Page.tsx'); assert.match(dto, /scopeAssetId\?: string/); assert.match(scope, /yacimiento\.parent_id=\$2::uuid/); assert.match(scope, /lower\(type\.code\)='yacimiento'/); assert.match(create, /scopeAssetId,/); assert.match(create, /operationalAreaId: dto\.operationalAreaId/); assert.match(create, /relation\.relation_role='OPERATOR'/); assert.match(create, /relation\.valid_from <= \$3::timestamptz/); assert.match(createPage, /scopeAssetId: yacimientoId/); }); test('F6.1 WEB inspection creation does not use Inventory operator snapshots', () => { const create = source('src/inspection-visits/inspection-planning-create.service.ts'); assert.match(create, /area_company_relations relation/); assert.doesNotMatch(create, /inventory\.operator_company_id/); assert.doesNotMatch(create, /asset\.operator_company_id/); }); test('F4 checklist classification is derived on read and never rewrites the persisted generation', () => { const f4 = source('src/inspection-visits/f4-inspection-visits.service.ts'); const d55 = source('src/database/migrations/1789063200000-phase-d5-5-web-planning-checklist.ts'); assert.match(d55, /REVOKE UPDATE, DELETE ON TABLE[\s\S]*inspection_visit_checklist_items/); assert.match(f4, /classifyChecklistView/); assert.match(f4, /FROM inspection_findings finding/); assert.doesNotMatch(f4, /UPDATE inspection_visit_checklist_items/); assert.doesNotMatch(f4, /reclassifyCurrentChecklist/); }); test('Field preparation is an Inspection stage, not a parallel sidebar module', () => { const layout = source('../web-v2/src/layout/AppLayout.tsx'); const briefing = source('../web-v2/src/pages/FieldBriefingsPage.tsx'); const detail = source('../web-v2/src/pages/InspectionVisitDetailF61Page.tsx'); const app = source('../web-v2/src/app/App.tsx'); assert.doesNotMatch(layout, /label: 'Preparación de campo'/); assert.match(briefing, /ETAPA DE LA INSPECCIÓN/); assert.match(briefing, /inspectionId/); assert.match(briefing, /Volver a la inspección/); assert.match(detail, /ETAPA PREVIA AL CAMPO/); assert.match(detail, /preparacion-campo\?inspectionId=/); assert.match(app, /InspectionVisitDetailF61Page/); });