66 lines
3.6 KiB
TypeScript
66 lines
3.6 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import test from 'node:test';
|
|
|
|
const root = process.cwd();
|
|
const read = (relative: string) => fs.readFileSync(path.join(root, relative), 'utf8');
|
|
|
|
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/);
|
|
assert.match(migration, /WHERE status = 'DRAFT'/);
|
|
assert.match(migration, /DROP CONSTRAINT IF EXISTS uq_inspection_reports_visit/);
|
|
assert.match(migration, /CREATE INDEX idx_inspection_reports_visit_id/);
|
|
});
|
|
|
|
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 \}\)/);
|
|
assert.match(reportEntity, /@Index\('idx_inspection_reports_visit_id', \['visitId'\]\)/);
|
|
assert.doesNotMatch(reportEntity, /visitId'\], \{ unique: true \}/);
|
|
assert.match(reports, /WHERE act_id = \$1/);
|
|
});
|
|
|
|
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, /inspectionRemainsIndependent: true/);
|
|
assert.match(closeBody, /ensureFrozenReport\(manager, actId, principal, request\)/);
|
|
});
|
|
|
|
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('F4 requires a final company manifestation before an act can be sealed', () => {
|
|
const closing = read('src/inspection-closing/inspection-closing.service.ts');
|
|
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(closing, /InspectionActSignatureStatus\.REFUSED/);
|
|
});
|
|
|
|
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\)/);
|
|
assert.match(link, /inspection_visit_assets/);
|
|
assert.match(link, /inspection_act_assets/);
|
|
assert.match(link, /return \{ actId: act\?\.id \?\? null \}/);
|
|
assert.doesNotMatch(link, /status <> 'CANCELLED'/);
|
|
});
|