From 232614ccf0cb2c0dc9af5f9f529cb673899e2344 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Tue, 8 Sep 2026 09:08:23 -0300 Subject: [PATCH] test: align multi-act contract with F4 lifecycle --- ...ase-f1-1-multi-act-operating-model.test.ts | 44 ++++++++----------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/api-v3/test/unit/phase-f1-1-multi-act-operating-model.test.ts b/api-v3/test/unit/phase-f1-1-multi-act-operating-model.test.ts index f563b06..99beaa5 100644 --- a/api-v3/test/unit/phase-f1-1-multi-act-operating-model.test.ts +++ b/api-v3/test/unit/phase-f1-1-multi-act-operating-model.test.ts @@ -6,7 +6,7 @@ import test from 'node:test'; const root = process.cwd(); const read = (relative: string) => fs.readFileSync(path.join(root, relative), 'utf8'); -test('F1.1 migration allows many acts per inspection while keeping only one draft at a time', () => { +test('F1.1/F4 allows many acts per inspection while keeping only one draft at a time', () => { const migration = read('src/database/migrations/1789495200000-phase-f1-1-multi-act-inspections.ts'); assert.match(migration, /DROP CONSTRAINT IF EXISTS uq_inspection_acts_visit/); assert.match(migration, /CREATE UNIQUE INDEX uq_inspection_acts_one_draft_per_visit/); @@ -15,7 +15,7 @@ test('F1.1 migration allows many acts per inspection while keeping only one draf assert.match(migration, /CREATE INDEX idx_inspection_reports_visit_id/); }); -test('F1.1 preserves exactly one frozen report per act instead of per inspection', () => { +test('F1.1/F4 preserves exactly one frozen report per act instead of per inspection', () => { const reportEntity = read('src/database/entities/inspection-report.entity.ts'); const reports = read('src/inspection-reports/inspection-reports.service.ts'); assert.match(reportEntity, /@Index\('uq_inspection_reports_act', \['actId'\], \{ unique: true \}\)/); @@ -24,43 +24,37 @@ test('F1.1 preserves exactly one frozen report per act instead of per inspection assert.match(reports, /WHERE act_id = \$1/); }); -test('F1.1 closes an act without closing its parent inspection', () => { +test('F4 seals one act without closing its parent inspection', () => { const closing = read('src/inspection-closing/inspection-closing.service.ts'); const closeBody = closing.slice(closing.indexOf(' async close('), closing.indexOf(' async signatureContent(')); assert.match(closeBody, /UPDATE inspection_acts/); + assert.match(closeBody, /status='SEALED'/); assert.doesNotMatch(closeBody, /UPDATE inspection_visits/); - assert.match(closeBody, /visitRemainsIndependent: true/); + assert.match(closeBody, /inspectionRemainsIndependent: true/); assert.match(closeBody, /ensureFrozenReport\(manager, actId, principal, request\)/); }); -test('F1.1 exposes an APK-only explicit inspection close and permits pending company signature', () => { - const controller = read('src/inspection-visits/inspection-visits.controller.ts'); - const visits = read('src/inspection-visits/inspection-visits.service.ts'); - assert.match(controller, /@Post\(':id\/close'\)/); - assert.match(controller, /@RequirePermissions\('inspections\.execute'\)/); - assert.match(visits, /async close\(/); - assert.match(visits, /assertMobileInspector\(principal\)/); - assert.match(visits, /INSPECTION_VISIT_DRAFT_ACTS_PENDING/); - assert.match(visits, /INSPECTION_VISIT_INSPECTOR_SIGNATURE_PENDING/); - assert.match(visits, /pendingCompanySignatures/); - assert.match(visits, /actsMayCompleteCompanySignatureLater: true/); +test('F4 closes an inspection only after every non-cancelled act is sealed', () => { + const lifecycle = read('src/inspection-visits/inspection-visit-lifecycle.service.ts'); + const closeBody = lifecycle.slice(lifecycle.indexOf(' async close('), lifecycle.indexOf(' async cancel(')); + assert.match(closeBody, /status<>'CANCELLED'/); + assert.match(closeBody, /acts\.filter\(\(act\) => act\.status !== 'SEALED'\)/); + assert.match(closeBody, /INSPECTION_REQUIRES_ACT/); + assert.match(closeBody, /INSPECTION_ACTS_NOT_SEALED/); + assert.match(closeBody, /assertVerificationResultsComplete\(manager, id\)/); + assert.match(closeBody, /visit\.status = InspectionVisitStatus\.CLOSED/); }); -test('F1.1 lets the company sign after the inspection closes and records conformity or dissent', () => { +test('F4 requires a final company manifestation before an act can be sealed', () => { const closing = read('src/inspection-closing/inspection-closing.service.ts'); - const dto = read('src/inspection-closing/dto/create-company-signature.dto.ts'); - const signatureEntity = read('src/database/entities/inspection-act-signature.entity.ts'); - assert.match(closing, /InspectionVisitStatus\.IN_PROGRESS, InspectionVisitStatus\.CLOSED/); + assert.match(closing, /INSPECTION_ACT_COMPANY_OUTCOME_REQUIRED/); + assert.match(closing, /INSPECTION_ACT_COMPANY_MANIFESTATION_PENDING/); assert.match(closing, /InspectionCompanySignatureManifestation\.CONFORMITY/); assert.match(closing, /InspectionCompanySignatureManifestation\.DISSENT/); - assert.match(dto, /@ValidateIf/); - assert.match(dto, /@MinLength\(10\)/); - assert.match(signatureEntity, /CONFORMITY = 'CONFORMITY'/); - assert.match(signatureEntity, /DISSENT = 'DISSENT'/); - assert.match(signatureEntity, /companyStatement/); + assert.match(closing, /InspectionActSignatureStatus\.REFUSED/); }); -test('F1.1 keeps field-created Inventory linked only to the current draft act', () => { +test('F1.1/F4 keeps field-created Inventory linked only to the current draft act', () => { const link = read('src/inspection-operations/field-discovery-inspection-link.service.ts'); assert.match(link, /AND status = 'DRAFT'/); assert.match(link, /if \(act\)/);