Files
dh-inspeccion-v2/api-v3/test/unit/asset-imports-d5-3-6.test.ts
T

50 lines
2.8 KiB
TypeScript

import 'reflect-metadata';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { join, resolve } from 'node:path';
import test from 'node:test';
import { REQUIRED_PERMISSIONS_KEY } from '../../src/authorization/decorators/require-permissions.decorator';
import { AssetImportsController } from '../../src/asset-imports/asset-imports.controller';
import { analyzeImportWorkbook } from '../../src/asset-imports/asset-import-profiles';
import type { ParsedWorkbook } from '../../src/asset-imports/asset-import-parser';
function source(relative: string): string { return readFileSync(resolve(process.cwd(), relative), 'utf8'); }
function permissionFor(method: string): string[] {
const controller = AssetImportsController.prototype;
return Reflect.getMetadata(REQUIRED_PERMISSIONS_KEY, controller[method as keyof typeof controller]) as string[];
}
function workbook(rows: string[][]): ParsedWorkbook { return { kind: 'XLSX', sheets: [{ name: 'Inventario', rows }] }; }
test('D5.3.6 protects reconciliation as an import-management operation', () => {
assert.deepEqual(permissionFor('reconcile'), ['asset_imports.manage']);
});
test('D5.3.6 normalizes technical family and subtype while preserving source classification', () => {
const analysis = analyzeImportWorkbook(workbook([
['Item','Area/ Yacimiento','Instalacion','Sub instalacion','Equipo','Denominación del equipo','Ubicación del equipo o instalación','N° ID/ Inventario','Cantidad','Especificaciones técnicas','Estado'],
['1','REFUGIO TUPUNGATO','TUP-PIAS','ZONA BOMBAS','Bomba Centrífuga','Clase: BBA; Tipo: CEN','N/A','BBA-050','1','Fabricante; GOULD; Modelo: 3196','NO'],
]));
assert.equal(analysis.rows[0]?.normalized.sourceClass, 'BBA');
assert.equal(analysis.rows[0]?.normalized.sourceSubtype, 'CEN');
assert.equal(analysis.rows[0]?.normalized.normalizedFamily, 'bomba');
assert.equal(analysis.rows[0]?.normalized.normalizedSubtype, 'centrifuga');
assert.equal(analysis.rows[0]?.normalized.sourceStatus, 'NO');
});
test('D5.3.6 reconciliation is conservative and does not write Maestro assets', () => {
const service = source('src/asset-imports/asset-imports.service.ts');
const reconcile = service.slice(service.indexOf('async reconcile'), service.indexOf('async cancel'));
assert.match(reconcile, /INVENTORY_ID_OR_CODE_EXACT/);
assert.match(reconcile, /AREA_FIELD_EXACT/);
assert.match(reconcile, /MATCH_MULTIPLE_ASSETS/);
assert.match(reconcile, /masterModified: false/);
assert.doesNotMatch(reconcile, /INSERT INTO assets\s*\(/);
assert.doesNotMatch(reconcile, /UPDATE assets\s+SET/);
});
test('D5.3.6.3 audit summary is exposed as a plain record', () => {
const source = readFileSync(join(process.cwd(), 'src/asset-imports/asset-imports.service.ts'), 'utf8');
assert.match(source, /afterData:\s*\{\s*\.\.\.summary\s*\}/);
});