From 6895edce20e7bd5047c274da862a72b4b6b59ea6 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Mon, 7 Sep 2026 08:39:59 -0300 Subject: [PATCH] F2.3: probar contrato de Hallazgos desde Inventario --- api-v3/test/unit/field-findings-f2-3.test.ts | 67 ++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 api-v3/test/unit/field-findings-f2-3.test.ts diff --git a/api-v3/test/unit/field-findings-f2-3.test.ts b/api-v3/test/unit/field-findings-f2-3.test.ts new file mode 100644 index 0000000..e3b061b --- /dev/null +++ b/api-v3/test/unit/field-findings-f2-3.test.ts @@ -0,0 +1,67 @@ +import 'reflect-metadata'; +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { readFileSync } from 'node:fs'; +import { plainToInstance } from 'class-transformer'; +import { validate } from 'class-validator'; +import { REQUIRED_PERMISSIONS_KEY } from '../../src/authorization/decorators/require-permissions.decorator'; +import { CreateFieldFindingDto } from '../../src/inspection-visits/dto/create-field-finding.dto'; +import { FieldFindingsController } from '../../src/inspection-visits/field-findings.controller'; + +function permissions(method: string): string[] { + const controller = FieldFindingsController.prototype; + const handler = controller[method as keyof typeof controller]; + return Reflect.getMetadata(REQUIRED_PERMISSIONS_KEY, handler) as string[]; +} + +test('F2.3 mantiene los Hallazgos de campo bajo ejecución móvil y permisos explícitos', () => { + assert.deepEqual(permissions('options'), ['inspection_findings.create', 'inspections.execute']); + assert.deepEqual(permissions('list'), ['inspection_findings.read', 'inspections.execute']); + assert.deepEqual(permissions('create'), ['inspection_findings.create', 'inspections.execute']); +}); + +test('F2.3 exige descripción y título cuando el inspector usa OTROS', async () => { + const dto = plainToInstance(CreateFieldFindingDto, { + description: '', + catalogItemId: null, + customTitle: '', + }); + const errors = await validate(dto); + const properties = new Set(errors.map((error) => error.property)); + assert.equal(properties.has('description'), true); + assert.equal(properties.has('customTitle'), true); +}); + +test('F2.3 vuelve a validar contexto, selección y GPS+foto en servidor antes del Hallazgo', () => { + const source = readFileSync('src/inspection-visits/field-findings.service.ts', 'utf8'); + assert.match(source, /assertMobileInspector\(principal\)/); + assert.match(source, /row\.visitStatus !== 'IN_PROGRESS'/); + assert.match(source, /FIELD_FINDING_INSPECTOR_NOT_ASSIGNED/); + assert.match(source, /FIELD_FINDING_INVENTORY_OUTSIDE_CONTEXT/); + assert.match(source, /FIELD_FINDING_INVENTORY_NOT_SELECTED/); + assert.match(source, /hasGeometry && creationGpsCaptured && fieldPhotoCount > 0/); + assert.match(source, /FIELD_FINDING_CAPTURE_REQUIRED/); +}); + +test('F2.3 resuelve exactamente el Acta DRAFT actual y no vuelve a la regla de un Acta por inspección', () => { + const source = readFileSync('src/inspection-visits/field-findings.service.ts', 'utf8'); + assert.match(source, /FROM inspection_acts/); + assert.match(source, /status = 'DRAFT'/); + assert.match(source, /LIMIT 2/); + assert.match(source, /FIELD_FINDING_DRAFT_ACT_REQUIRED/); + assert.match(source, /FIELD_FINDING_MULTIPLE_DRAFT_ACTS/); +}); + +test('F2.3 reutiliza catálogo contextual y creación canónica, conserva OTROS y permite varios Hallazgos', () => { + const fieldSource = readFileSync('src/inspection-visits/field-findings.service.ts', 'utf8'); + const catalogSource = readFileSync('src/inspection-findings/finding-catalog.service.ts', 'utf8'); + const findingSource = readFileSync('src/inspection-findings/inspection-findings.service.ts', 'utf8'); + + assert.match(fieldSource, /this\.catalog\.listApplicableForAsset\(assetId, \{\}\)/); + assert.match(fieldSource, /this\.findings\.create\(act\.id, payload, principal, request\)/); + assert.match(fieldSource, /canAddAnother: true/); + assert.match(catalogSource, /code: 'OTHER'/); + assert.match(catalogSource, /label: 'OTROS'/); + assert.match(findingSource, /finding_catalog_proposals/); + assert.match(findingSource, /PENDING/); +});