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 preserves Inventory operator snapshots and changes operator only through Area relations', () => { const relations = source('src/asset-master/asset-operational-relations.service.ts'); const migration = source('src/database/migrations/1790087250000-f5-operational-context-compatibility.ts'); assert.match(migration, /Runtime ownership and search MUST NOT depend on it/); assert.match(migration, /La Empresa se cambia en la relación temporal del Área, no en el Inventario/); assert.match(relations, /operatorSnapshotPreserved:true/); assert.doesNotMatch(relations, /UPDATE assets asset[\s\S]*SET operator_company_id=/); }); test('F6.1 blocks operator mutation through generic Inventory edit DTOs', () => { const updateDto = source('src/asset-master/dto/update-asset.dto.ts'); const contextDto = source('src/asset-master/dto/change-asset-context.dto.ts'); for (const dto of [updateDto, contextDto]) { assert.match(dto, /@IsEmpty/); assert.match(dto, /La Operadora se administra en la relación temporal del Área, no en el Inventario/); } }); test('F6.1 rejects legacy Inventory searches that filter by operator snapshot', () => { const listDto = source('src/asset-master/dto/list-assets-query.dto.ts'); const treeDto = source('src/asset-master/dto/list-asset-tree-query.dto.ts'); for (const dto of [listDto, treeDto]) { assert.match(dto, /operatorCompanyId\?: string/); assert.match(dto, /@IsEmpty/); assert.match(dto, /Filtrá la Operadora mediante la relación temporal del Área/); } }); test('F6.1 resolves temporal Inventory operator from Area relation history', () => { const temporal = source('src/asset-master/asset-temporal.service.ts'); assert.match(temporal, /FROM area_company_relations relation/); assert.match(temporal, /relation\.valid_from <= \$2/); assert.match(temporal, /relation\.valid_until IS NULL OR relation\.valid_until > \$2/); assert.match(temporal, /operator_company\.id=operator_relation\.company_id/); assert.doesNotMatch(temporal, /operator_company\.id=history\.operator_company_id/); }); test('F6.1 verification planning uses Area relation truth instead of Inventory operator snapshot', () => { const verification = source('src/inspection-verifications/inspection-verifications.service.ts'); assert.match(verification, /FROM area_company_relations relation/); assert.match(verification, /relation\.valid_from <= \$2::timestamptz/); assert.match(verification, /VERIFICATION_OPERATOR_NOT_ACTIVE/); assert.match(verification, /operatorSource: 'area_company_relations'/); assert.doesNotMatch(verification, /company\.id = asset\.operator_company_id/); }); test('F6.1 historical operational lists read Company and Area from the parent Inspection', () => { const acts = source('src/inspection-acts/inspection-acts.service.ts'); const findings = source('src/inspection-findings/inspection-finding-worklist.service.ts'); const reports = source('src/inspection-reports/inspection-reports.service.ts'); assert.match(acts, /visit\.operator_company_id/); assert.match(acts, /visit\.operational_area_id/); assert.doesNotMatch(acts, /context_asset\.operator_company_id/); assert.match(findings, /company\.id = visit\.operator_company_id/); assert.match(findings, /area\.id = visit\.operational_area_id/); assert.doesNotMatch(findings, /company\.id = asset\.operator_company_id/); assert.match(reports, /visit\.\$\{column\} = \$\{parameter\}::uuid/); assert.match(reports, /company\.id=context_visit\.operator_company_id/); assert.match(reports, /area\.id=context_visit\.operational_area_id/); assert.doesNotMatch(reports, /context_asset\.operator_company_id/); }); test('F6.1 WEB Inventory searches use physical Area and never the operator snapshot filter', () => { const inspectionEditor = source('../web-v2/src/pages/InspectionVisitEditorF4Page.tsx'); const fieldDiscoveries = source('../web-v2/src/pages/FieldDiscoveriesPage.tsx'); const inventoryMerge = source('../web-v2/src/lib/inventoryMergeApi.ts'); for (const page of [inspectionEditor, fieldDiscoveries, inventoryMerge]) { assert.match(page, /listAssets\(\{[\s\S]{0,300}operationalAreaId:/); assert.doesNotMatch(page, /listAssets\(\{[\s\S]{0,300}operatorCompanyId:/); } assert.doesNotMatch(inventoryMerge, /source\.operatorCompany/); }); test('F6.1 WEB derives the creation snapshot from the active Area operator and removes it from Inventory edits', () => { const editor = source('../web-v2/src/pages/AssetEditorPage.tsx'); const contextPanel = source('../web-v2/src/features/assets/AssetContextHistoryPanel.tsx'); assert.match(editor, /createAsset\(\{[\s\S]*operatorCompanyId: operatorCompanyId \|\| null/); assert.doesNotMatch(editor, /updateAsset\(id, \{[^}]*operatorCompanyId/); assert.doesNotMatch(editor, /parent\.operatorCompany/); assert.match(editor, /listCompaniesForArea\(operationalAreaId\)\.then\(\(loadedCompanies\)/); assert.match(editor, /loadedCompanies\.length === 1 \? \(loadedCompanies\[0\]\?\.id \?\? ''\) : ''/); assert.match(editor, /Snapshot histórico de alta/); assert.match(contextPanel, /Cambiar contexto físico/); assert.doesNotMatch(contextPanel, /operatorCompanyId:/); });