68 lines
3.5 KiB
TypeScript
68 lines
3.5 KiB
TypeScript
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/);
|
|
});
|