test(f4): align legacy contracts with lifecycle model
This commit is contained in:
@@ -2,7 +2,7 @@ import { strict as assert } from 'node:assert';
|
||||
import test from 'node:test';
|
||||
import { DashboardService } from '../../src/dashboard/dashboard.service';
|
||||
|
||||
test('DashboardService returns numeric counts and recent activity consistently', async () => {
|
||||
test('DashboardService returns F4 operational counts and recent activity consistently', async () => {
|
||||
const recent = [{
|
||||
id: 'event-id',
|
||||
occurredAt: new Date('2026-08-13T12:00:00.000Z'),
|
||||
@@ -17,9 +17,8 @@ test('DashboardService returns numeric counts and recent activity consistently',
|
||||
return [{
|
||||
activeUsers: '4', inactiveUsers: '2', activeSessions: '3',
|
||||
totalAssets: '12', assetsNeedValidation: '4', assetsWithoutGeometry: '6', plannedInspections: '2',
|
||||
openFindings: '8', awaitingCompanyResponse: '5', overdueCompanyResponses: '2',
|
||||
companyResponsesDueNext7Days: '1', awaitingVerificationSchedule: '4',
|
||||
overdueControls: '2', controlsNext30Days: '3',
|
||||
openFindings: '8', findingsWithoutControlDate: '5', overdueControls: '2', controlsNext30Days: '3',
|
||||
reportsWorking: '1', reportsOfficialized: '2', sealedActsWithoutReport: '4',
|
||||
}];
|
||||
}
|
||||
if (sql.includes('FROM inspection_findings finding')) return [];
|
||||
@@ -32,20 +31,20 @@ test('DashboardService returns numeric counts and recent activity consistently',
|
||||
|
||||
const result = await new DashboardService(dataSource as never).summary();
|
||||
assert.deepEqual(result.counts, {
|
||||
activeUsers: 4,
|
||||
inactiveUsers: 2,
|
||||
activeSessions: 3,
|
||||
totalAssets: 12,
|
||||
assetsNeedValidation: 4,
|
||||
assetsWithoutGeometry: 6,
|
||||
plannedInspections: 2,
|
||||
activeUsers: 4,
|
||||
inactiveUsers: 2,
|
||||
activeSessions: 3,
|
||||
openFindings: 8,
|
||||
awaitingCompanyResponse: 5,
|
||||
overdueCompanyResponses: 2,
|
||||
companyResponsesDueNext7Days: 1,
|
||||
awaitingVerificationSchedule: 4,
|
||||
findingsWithoutControlDate: 5,
|
||||
overdueControls: 2,
|
||||
controlsNext30Days: 3,
|
||||
reportsWorking: 1,
|
||||
reportsOfficialized: 2,
|
||||
sealedActsWithoutReport: 4,
|
||||
});
|
||||
assert.equal(result.recentAudit, recent);
|
||||
assert.deepEqual(result.upcomingControls, []);
|
||||
|
||||
@@ -11,14 +11,15 @@ test('F3.2/F4 mantiene múltiples Actas con un solo borrador simultáneo por ins
|
||||
assert.match(migration, /WHERE status = 'DRAFT'/);
|
||||
});
|
||||
|
||||
test('F3.2 permite seleccionar el Acta explícitamente al trabajar Hallazgos desde la APK', () => {
|
||||
test('F3.2/F4 exige seleccionar el Acta explícitamente al crear Hallazgos desde la APK', () => {
|
||||
const controller = read('src/inspection-visits/field-findings.controller.ts');
|
||||
const service = read('src/inspection-visits/field-findings.service.ts');
|
||||
const dto = read('src/inspection-visits/dto/create-field-finding.dto.ts');
|
||||
assert.match(controller, /FieldFindingActQueryDto/);
|
||||
assert.match(controller, /query\.actId/);
|
||||
assert.match(dto, /actId\?: string/);
|
||||
assert.match(service, /actSelectionMode: actId \? 'EXPLICIT' : 'LEGACY_SINGLE_DRAFT'/);
|
||||
assert.match(dto, /actId!: string/);
|
||||
assert.match(dto, /El Acta es obligatoria/);
|
||||
assert.match(service, /this\.requireDraftAct\(visitId, dto\.actId\)/);
|
||||
assert.match(service, /WHERE id=\$1::uuid AND visit_id=\$2::uuid/);
|
||||
assert.match(service, /FIELD_FINDING_ACT_NOT_DRAFT/);
|
||||
assert.match(service, /FIELD_FINDING_ASSET_NOT_IN_ACT/);
|
||||
|
||||
@@ -5,18 +5,21 @@ import { plainToInstance } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { CancelInspectionActDto } from '../../src/inspection-acts/dto/cancel-inspection-act.dto';
|
||||
import { CreateInspectionActDto } from '../../src/inspection-acts/dto/create-inspection-act.dto';
|
||||
import { InspectionActUrgency } from '../../src/database/entities';
|
||||
|
||||
const ASSET_ID = '16e54e65-60cf-4739-b0d1-ccdd904fbfd5';
|
||||
|
||||
test('inspection act DTO accepts content and selected visit assets', async () => {
|
||||
test('inspection act DTO accepts urgency, content and selected visit assets', async () => {
|
||||
const dto = plainToInstance(CreateInspectionActDto, {
|
||||
occurredAt: '2026-08-14T15:30:00.000Z',
|
||||
urgency: InspectionActUrgency.NON_URGENT,
|
||||
title: ' Verificación de instalación ',
|
||||
summary: ' Se inspeccionó el activo seleccionado. ',
|
||||
observations: ' Sin novedades. ',
|
||||
assetIds: [ASSET_ID],
|
||||
});
|
||||
assert.deepEqual(await validate(dto), []);
|
||||
assert.equal(dto.urgency, InspectionActUrgency.NON_URGENT);
|
||||
assert.equal(dto.title, 'Verificación de instalación');
|
||||
assert.equal(dto.summary, 'Se inspeccionó el activo seleccionado.');
|
||||
assert.equal(dto.observations, 'Sin novedades.');
|
||||
@@ -25,6 +28,7 @@ test('inspection act DTO accepts content and selected visit assets', async () =>
|
||||
test('inspection act DTO rejects duplicate assets', async () => {
|
||||
const dto = plainToInstance(CreateInspectionActDto, {
|
||||
occurredAt: '2026-08-14T15:30:00.000Z',
|
||||
urgency: InspectionActUrgency.NON_URGENT,
|
||||
title: 'Acta',
|
||||
summary: 'Contenido',
|
||||
assetIds: [ASSET_ID, ASSET_ID],
|
||||
|
||||
@@ -12,14 +12,14 @@ function permissionFor(controller: object, method: string): string[] {
|
||||
return Reflect.getMetadata(REQUIRED_PERMISSIONS_KEY, handler) as string[];
|
||||
}
|
||||
|
||||
test('D5 closing endpoints separate read, prepare, sign and close permissions', () => {
|
||||
test('F4 closing endpoints separate read, lock, sign and seal permissions without reopen', () => {
|
||||
assert.deepEqual(permissionFor(InspectionClosingController.prototype, 'get'), ['inspection_closure.read']);
|
||||
assert.deepEqual(permissionFor(InspectionClosingController.prototype, 'responsible'), ['inspection_closure.prepare']);
|
||||
assert.deepEqual(permissionFor(InspectionClosingController.prototype, 'ready'), ['inspection_closure.prepare']);
|
||||
assert.deepEqual(permissionFor(InspectionClosingController.prototype, 'reopen'), ['inspection_closure.prepare']);
|
||||
assert.deepEqual(permissionFor(InspectionClosingController.prototype, 'lock'), ['inspection_closure.prepare']);
|
||||
assert.equal('reopen' in InspectionClosingController.prototype, false);
|
||||
assert.deepEqual(permissionFor(InspectionClosingController.prototype, 'inspectorSignature'), ['inspection_closure.sign']);
|
||||
assert.deepEqual(permissionFor(InspectionClosingController.prototype, 'companySignature'), ['inspection_closure.sign']);
|
||||
assert.deepEqual(permissionFor(InspectionClosingController.prototype, 'companyOutcome'), ['inspection_closure.sign']);
|
||||
assert.deepEqual(permissionFor(InspectionClosingController.prototype, 'close'), ['inspection_closure.close']);
|
||||
assert.deepEqual(permissionFor(InspectionClosingController.prototype, 'seal'), ['inspection_closure.close']);
|
||||
assert.deepEqual(permissionFor(InspectionSignatureContentController.prototype, 'content'), ['inspection_closure.read']);
|
||||
});
|
||||
|
||||
@@ -13,40 +13,16 @@ function permissionFor(controller: object, method: string): string[] {
|
||||
return Reflect.getMetadata(REQUIRED_PERMISSIONS_KEY, handler) as string[];
|
||||
}
|
||||
|
||||
test('finding endpoints separate catalog, content, follow-up and closure permissions', () => {
|
||||
assert.deepEqual(permissionFor(FindingCatalogController.prototype, 'list'), [
|
||||
'finding_catalog.read',
|
||||
]);
|
||||
for (const method of [
|
||||
'adminList',
|
||||
'createCategory',
|
||||
'updateCategory',
|
||||
'createItem',
|
||||
'updateItem',
|
||||
]) {
|
||||
assert.deepEqual(permissionFor(FindingCatalogController.prototype, method), [
|
||||
'finding_catalog.manage',
|
||||
]);
|
||||
test('F4 finding endpoints separate catalog, content and closure while mutable follow-up is retired', () => {
|
||||
assert.deepEqual(permissionFor(FindingCatalogController.prototype, 'list'), ['finding_catalog.read']);
|
||||
for (const method of ['adminList', 'createCategory', 'updateCategory', 'createItem', 'updateItem']) {
|
||||
assert.deepEqual(permissionFor(FindingCatalogController.prototype, method), ['finding_catalog.manage']);
|
||||
}
|
||||
assert.deepEqual(permissionFor(InspectionActFindingsController.prototype, 'list'), [
|
||||
'inspection_findings.read',
|
||||
]);
|
||||
assert.deepEqual(permissionFor(InspectionActFindingsController.prototype, 'create'), [
|
||||
'inspection_findings.create',
|
||||
]);
|
||||
assert.deepEqual(permissionFor(InspectionFindingsController.prototype, 'list'), [
|
||||
'inspection_findings.read',
|
||||
]);
|
||||
assert.deepEqual(permissionFor(InspectionFindingsController.prototype, 'get'), [
|
||||
'inspection_findings.read',
|
||||
]);
|
||||
assert.deepEqual(permissionFor(InspectionFindingsController.prototype, 'update'), [
|
||||
'inspection_findings.update',
|
||||
]);
|
||||
assert.deepEqual(permissionFor(InspectionFindingsController.prototype, 'updateFollowUp'), [
|
||||
'inspection_findings.follow_up',
|
||||
]);
|
||||
assert.deepEqual(permissionFor(InspectionFindingsController.prototype, 'close'), [
|
||||
'inspection_findings.close',
|
||||
]);
|
||||
assert.deepEqual(permissionFor(InspectionActFindingsController.prototype, 'list'), ['inspection_findings.read']);
|
||||
assert.deepEqual(permissionFor(InspectionActFindingsController.prototype, 'create'), ['inspection_findings.create']);
|
||||
assert.deepEqual(permissionFor(InspectionFindingsController.prototype, 'list'), ['inspection_findings.read']);
|
||||
assert.deepEqual(permissionFor(InspectionFindingsController.prototype, 'get'), ['inspection_findings.read']);
|
||||
assert.deepEqual(permissionFor(InspectionFindingsController.prototype, 'update'), ['inspection_findings.update']);
|
||||
assert.equal('updateFollowUp' in InspectionFindingsController.prototype, false);
|
||||
assert.deepEqual(permissionFor(InspectionFindingsController.prototype, 'close'), ['inspection_findings.close']);
|
||||
});
|
||||
|
||||
@@ -13,9 +13,9 @@ test('D5.3.13 separates company response due dates from verification due dates',
|
||||
assert.match(source, /verificationOverdue/);
|
||||
});
|
||||
|
||||
test('D5.3.13 exposes a global office queue and controlled finding closure', () => {
|
||||
test('D5.3.13/F4 exposes the global worklist and controlled finding closure', () => {
|
||||
assert.match(controller, /@Get\(\)/);
|
||||
assert.match(controller, /this\.findings\.listGlobal\(query\)/);
|
||||
assert.match(controller, /this\.worklist\.list\(query\)/);
|
||||
assert.match(controller, /@Patch\(':id\/close'\)/);
|
||||
assert.match(source, /finding\.status = InspectionFindingStatus\.CLOSED/);
|
||||
assert.match(source, /finding\.closureNotes = dto\.closureNotes/);
|
||||
|
||||
@@ -10,7 +10,7 @@ function permissionFor(method: string): string[] {
|
||||
return Reflect.getMetadata(REQUIRED_PERMISSIONS_KEY, handler) as string[];
|
||||
}
|
||||
|
||||
test('inspection visit endpoints separate reading, planning, assignment and execution', () => {
|
||||
test('F4 inspection endpoints separate reading, planning, assignment and execution', () => {
|
||||
assert.deepEqual(permissionFor('list'), ['inspections.read']);
|
||||
assert.deepEqual(permissionFor('get'), ['inspections.read']);
|
||||
assert.deepEqual(permissionFor('assignees'), ['inspections.assign']);
|
||||
@@ -18,7 +18,9 @@ test('inspection visit endpoints separate reading, planning, assignment and exec
|
||||
assert.deepEqual(permissionFor('update'), ['inspections.manage']);
|
||||
assert.deepEqual(permissionFor('replaceAssets'), ['inspections.manage']);
|
||||
assert.deepEqual(permissionFor('replaceTeam'), ['inspections.assign']);
|
||||
assert.deepEqual(permissionFor('changeStatus'), ['inspections.manage']);
|
||||
assert.deepEqual(permissionFor('plan'), ['inspections.manage']);
|
||||
assert.deepEqual(permissionFor('unplan'), ['inspections.manage']);
|
||||
assert.deepEqual(permissionFor('start'), ['inspections.execute']);
|
||||
assert.deepEqual(permissionFor('close'), ['inspections.execute']);
|
||||
assert.deepEqual(permissionFor('cancel'), ['inspections.manage']);
|
||||
});
|
||||
|
||||
@@ -11,15 +11,15 @@ function policyCalls(value: string): number {
|
||||
return value.match(/assertMobileInspector\(principal\);/g)?.length ?? 0;
|
||||
}
|
||||
|
||||
test('D5.1 applies the mobile-inspector policy to every field operation', async () => {
|
||||
const [visits, acts, findings, evidence, closing] = await Promise.all([
|
||||
source('inspection-visits/inspection-visits.service.ts'),
|
||||
test('D5.1/F4 applies the mobile-inspector policy to every field operation', async () => {
|
||||
const [lifecycle, acts, findings, evidence, closing] = await Promise.all([
|
||||
source('inspection-visits/inspection-visit-lifecycle.service.ts'),
|
||||
source('inspection-acts/inspection-acts.service.ts'),
|
||||
source('inspection-findings/inspection-findings.service.ts'),
|
||||
source('inspection-findings/inspection-evidence.service.ts'),
|
||||
source('inspection-closing/inspection-closing.service.ts'),
|
||||
]);
|
||||
assert.equal(policyCalls(visits), 2);
|
||||
assert.equal(policyCalls(lifecycle), 2);
|
||||
assert.equal(policyCalls(acts), 3);
|
||||
assert.equal(policyCalls(findings), 2);
|
||||
assert.equal(policyCalls(evidence), 1);
|
||||
@@ -34,9 +34,7 @@ test('D5.1 leaves company follow-up outside the field-operation gate', async ()
|
||||
});
|
||||
|
||||
test('D5.1 migration grants operational permissions only to inspector', async () => {
|
||||
const migration = await source(
|
||||
'database/migrations/1787331600000-phase-d5-1-mobile-inspection-policy.ts',
|
||||
);
|
||||
const migration = await source('database/migrations/1787331600000-phase-d5-1-mobile-inspection-policy.ts');
|
||||
assert.match(migration, /role\.code <> 'inspector'/);
|
||||
assert.match(migration, /role\.code = 'inspector'/);
|
||||
assert.doesNotMatch(migration, /inspection_findings\.follow_up/);
|
||||
|
||||
@@ -19,7 +19,8 @@ test('D5.3.15/F4 exposes global acts and report emission after an Act is SEALED'
|
||||
test('D5.3.15/F4 freezes the immutable sealed Act snapshot as the INF source', () => {
|
||||
assert.match(reportService, /assertMobileInspector\(principal\)/);
|
||||
assert.match(reportService, /final_snapshot AS "finalSnapshot"/);
|
||||
assert.match(reportService, /DocumentSequenceType\.REPORT/);
|
||||
assert.match(reportService, /const reportNumber = act\.actNumber/);
|
||||
assert.match(reportService, /act\.code\.replace\(\/\^ACT-\/, 'INF-'\)/);
|
||||
assert.match(reportService, /sha256CanonicalJson\(frozenSnapshot\)/);
|
||||
assert.match(reportService, /InspectionReportStatus\.WORKING/);
|
||||
assert.match(reportService, /INSPECTION_REPORT_GENERATED/);
|
||||
|
||||
@@ -7,10 +7,11 @@ const service = readFileSync(resolve(process.cwd(), 'src/inspection-verification
|
||||
const migration = readFileSync(resolve(process.cwd(), 'src/database/migrations/1788112800000-phase-d5-3-16-verification-planning.ts'), 'utf8');
|
||||
const visitService = readFileSync(resolve(process.cwd(), 'src/inspection-visits/inspection-visits.service.ts'), 'utf8');
|
||||
|
||||
test('D5.3.16 builds the verification queue from the second finding deadline', () => {
|
||||
assert.match(service, /company_response_received_on IS NOT NULL/);
|
||||
test('D5.3.16/F4 builds the verification queue from the next control date and unresolved latest result', () => {
|
||||
assert.doesNotMatch(service, /company_response_received_on IS NOT NULL/);
|
||||
assert.match(service, /finding\.next_control_on IS NOT NULL/);
|
||||
assert.match(service, /verification_visit\.id IS NULL/);
|
||||
assert.match(service, /latest_verification\.outcome/);
|
||||
assert.match(service, /<> 'RESOLVED'/);
|
||||
assert.match(service, /overdueUnplanned/);
|
||||
});
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ test('D5.3.20 stores an integrity-checked Word artifact without changing the fro
|
||||
assert.match(migration, /word_sha256 char\(64\)/);
|
||||
assert.match(migration, /word_generated_at timestamptz/);
|
||||
assert.match(wordService, /createHash\('sha256'\)/);
|
||||
assert.match(wordService, /word_status = 'READY'/);
|
||||
assert.match(wordService, /word_status\s*=\s*'READY'/);
|
||||
assert.match(controller, /@Get\(':id\/word'\)/);
|
||||
});
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ test('D5.4 stores suggested and actual severity independently on the 1 to 10 sca
|
||||
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'/);
|
||||
});
|
||||
|
||||
@@ -45,22 +45,22 @@ test('D5.5 treats manual additions as preventive and requires an auditable reaso
|
||||
assert.match(dto, /@MinLength\(10\)/);
|
||||
});
|
||||
|
||||
test('D5.5 keeps verification visits inside the same Area Operator planning contract and start remains APK-only', () => {
|
||||
test('D5.5/F4 keeps verification visits inside the Area Operator contract and start remains APK-only', () => {
|
||||
const verification = read('src/inspection-verifications/inspection-verifications.service.ts');
|
||||
const visits = read('src/inspection-visits/inspection-visits.service.ts');
|
||||
const lifecycle = read('src/inspection-visits/inspection-visit-lifecycle.service.ts');
|
||||
assert.match(verification, /operationalAreaId: areaId/);
|
||||
assert.match(verification, /operatorCompanyId: companyId/);
|
||||
assert.match(verification, /planning_source = 'VERIFICATION'/);
|
||||
assert.match(visits, /assertMobileInspector\(principal\)/);
|
||||
assert.match(visits, /INSPECTION_CHECKLIST_REQUIRED/);
|
||||
assert.match(lifecycle, /assertMobileInspector\(principal\)/);
|
||||
assert.match(lifecycle, /INSPECTION_CHECKLIST_REQUIRED/);
|
||||
});
|
||||
|
||||
test('D5.5 confirmation requires a reviewed current checklist and keeps visit start under mobile inspector policy', () => {
|
||||
const visits = read('src/inspection-visits/inspection-visits.service.ts');
|
||||
test('D5.5/F4 requires a current checklist before planning or start and keeps start under mobile policy', () => {
|
||||
const lifecycle = read('src/inspection-visits/inspection-visit-lifecycle.service.ts');
|
||||
const policy = read('src/inspection-operations/mobile-inspector-policy.ts');
|
||||
assert.match(visits, /INSPECTION_CHECKLIST_REQUIRED/);
|
||||
assert.match(visits, /checklistGeneratedAt/);
|
||||
assert.match(visits, /assertMobileInspector\(principal\)/);
|
||||
assert.match(lifecycle, /INSPECTION_CHECKLIST_REQUIRED/);
|
||||
assert.match(lifecycle, /checklistGeneratedAt/);
|
||||
assert.match(lifecycle, /assertMobileInspector\(principal\)/);
|
||||
assert.match(policy, /transport !== 'bearer'/);
|
||||
assert.match(policy, /includes\('inspector'\)/);
|
||||
});
|
||||
|
||||
@@ -6,14 +6,18 @@ import test from 'node:test';
|
||||
const root = process.cwd();
|
||||
const read = (relative: string) => fs.readFileSync(path.join(root, relative), 'utf8');
|
||||
|
||||
test('D5.6.4 generates inspection codes server-side with an annual transactional sequence', () => {
|
||||
test('D5.6.4/F4 generates inspection codes server-side with an annual transactional sequence', () => {
|
||||
const generator = read('src/inspection-visits/inspection-visit-code.ts');
|
||||
assert.match(generator, /INS-\$\{year\}-\$\{String\(sequence\)\.padStart\(6, '0'\)\}/);
|
||||
assert.match(generator, /pg_advisory_xact_lock/);
|
||||
assert.match(generator, /America\/Argentina\/Mendoza/);
|
||||
assert.match(generator, /padStart\(5, '0'\)/);
|
||||
assert.match(generator, /return `INSP-/);
|
||||
assert.match(generator, /dateRow\.day/);
|
||||
assert.match(generator, /dateRow\.month/);
|
||||
assert.match(generator, /dateRow\.short_year/);
|
||||
});
|
||||
|
||||
test('D5.6.4 creates one inspection from Area Operator start and lead inspector without manual title or end date', () => {
|
||||
test('D5.6.4/F4 creates one inspection from Area Operator, start and lead inspector without legacy title or end date', () => {
|
||||
const dto = read('src/inspection-visits/dto/create-inspection-visit.dto.ts');
|
||||
const service = read('src/inspection-visits/inspection-visits.service.ts');
|
||||
assert.doesNotMatch(dto, /code!/);
|
||||
@@ -23,8 +27,9 @@ test('D5.6.4 creates one inspection from Area Operator start and lead inspector
|
||||
assert.match(dto, /operatorCompanyId!/);
|
||||
assert.match(dto, /plannedStartAt!/);
|
||||
assert.match(dto, /leadInspectorUserId!/);
|
||||
assert.match(service, /title: code/);
|
||||
assert.match(service, /plannedEndAt: null/);
|
||||
assert.match(service, /const code = await nextInspectionVisitCode\(manager, plannedStartAt\)/);
|
||||
assert.doesNotMatch(service, /title: code/);
|
||||
assert.doesNotMatch(service, /plannedEndAt/);
|
||||
});
|
||||
|
||||
test('D5.6.4 assigns the lead inspector and generates the checklist in the same creation transaction', () => {
|
||||
@@ -34,10 +39,10 @@ test('D5.6.4 assigns the lead inspector and generates the checklist in the same
|
||||
assert.match(service, /await this\.generateChecklistInternal\(manager, visit, principal\.userId\)/);
|
||||
});
|
||||
|
||||
test('D5.6.4 uses the same inspection numbering and start-only planning for verification visits', () => {
|
||||
test('D5.6.4/F4 uses the same inspection numbering and start-only planning for verification visits', () => {
|
||||
const dto = read('src/inspection-verifications/dto/plan-verification-visit.dto.ts');
|
||||
const service = read('src/inspection-verifications/inspection-verifications.service.ts');
|
||||
assert.doesNotMatch(dto, /plannedEndAt/);
|
||||
assert.match(service, /nextInspectionVisitCode\(manager, plannedStartAt\)/);
|
||||
assert.match(service, /plannedEndAt: null/);
|
||||
assert.doesNotMatch(service, /plannedEndAt/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user