Files
dh-inspeccion-v2/api-v3/test/unit/phase-d5-4-contextual-finding-catalog.test.ts

66 lines
3.8 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
const read = (path: string) => readFileSync(resolve(process.cwd(), path), 'utf8');
const migration = read('src/database/migrations/1788976800000-phase-d5-4-contextual-finding-catalog.ts');
const catalogService = read('src/inspection-findings/finding-catalog.service.ts');
const catalogController = read('src/inspection-findings/finding-catalog.controller.ts');
const findingsService = read('src/inspection-findings/inspection-findings.service.ts');
const createFindingDto = read('src/inspection-findings/dto/create-inspection-finding.dto.ts');
const catalogItemDto = read('src/inspection-findings/dto/create-finding-catalog-item.dto.ts');
const closingService = read('src/inspection-closing/inspection-closing.service.ts');
const wordBuilder = read('src/inspection-reports/inspection-report-word-builder.ts');
test('D5.4 models type applicability and concrete Inventory exceptions separately', () => {
assert.match(migration, /CREATE TABLE finding_catalog_asset_type_profiles/);
assert.match(migration, /CREATE TABLE finding_catalog_item_asset_types/);
assert.match(migration, /CREATE TABLE finding_catalog_asset_overrides/);
assert.match(catalogService, /replaceAssetTypeSelection/);
assert.match(catalogService, /replaceAssetSelection/);
assert.match(catalogService, /typeDefaultEnabled/);
});
test('D5.4 exposes only applicable catalog items and enforces the same rule on field creation', () => {
assert.match(catalogController, /@Get\('applicable\/:assetId'\)/);
assert.match(catalogService, /listApplicableForAsset/);
assert.match(findingsService, /FINDING_CATALOG_ITEM_NOT_APPLICABLE/);
assert.match(findingsService, /finding_catalog_asset_type_profiles profile/);
assert.match(findingsService, /finding_catalog_asset_overrides override/);
assert.match(findingsService, /await this\.requireCatalogItem\(manager, finding\.catalogItemId, dto\.assetId\)/);
});
test('D5.4 stores suggested and actual severity independently on the 1 to 10 scale', () => {
assert.match(migration, /suggested_severity smallint/);
assert.match(migration, /severity smallint/);
assert.match(migration, /BETWEEN 1 AND 10/);
assert.match(catalogItemDto, /@Min\(1\)/);
assert.match(catalogItemDto, /@Max\(10\)/);
assert.match(createFindingDto, /severity\?: number/);
assert.match(findingsService, /suggestedSeverity: catalog\?\.suggestedSeverity/);
assert.match(findingsService, /severity: dto\.severity \?\? catalog\?\.suggestedSeverity/);
assert.match(closingService, /finding\.suggested_severity AS "suggestedSeverity"/);
assert.match(closingService, /finding\.severity/);
assert.match(wordBuilder, /'Gravedad'/);
});
test('D5.4 turns OTHER into an office proposal without rewriting the original finding', () => {
assert.match(migration, /CREATE TABLE finding_catalog_proposals/);
assert.match(findingsService, /INSERT INTO finding_catalog_proposals/);
assert.match(catalogService, /FINDING_CATALOG_PROPOSAL_ALREADY_REVIEWED/);
assert.match(catalogService, /status = 'MATCHED'/);
assert.match(catalogService, /status = 'REJECTED'/);
assert.doesNotMatch(catalogService, /UPDATE inspection_findings SET catalog_item_id/);
});
test('D5.4 keeps contextual catalog administration in office permissions and audited routes', () => {
assert.match(catalogController, /@Put\('asset-types\/:assetTypeId\/selection'\)/);
assert.match(catalogController, /@Put\('assets\/:assetId\/selection'\)/);
assert.match(catalogController, /@Get\('proposals'\)/);
assert.match(catalogController, /finding_catalog\.manage/);
assert.match(catalogService, /FINDING_CATALOG_TYPE_APPLICABILITY_UPDATED/);
assert.match(catalogService, /FINDING_CATALOG_ASSET_SELECTION_UPDATED/);
assert.match(catalogService, /FINDING_CATALOG_PROPOSAL_MATCHED/);
});