Android CI / RC / Android · lint, tests, debug APK, release compile (push) Successful in 3m24s
DH V2 CI / API · typecheck, tests, build (push) Successful in 40s
DH V2 CI / WEB · typecheck, build (push) Successful in 18s
Production dependency audit / API · production dependencies (push) Successful in 8s
Production dependency audit / WEB · production dependencies (push) Successful in 9s
DH V2 CI / Docker / scripts contract (push) Successful in 1m22s
84 lines
4.7 KiB
TypeScript
84 lines
4.7 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { resolve } from 'node:path';
|
|
import test from 'node:test';
|
|
|
|
const api = (path: string) => readFileSync(resolve(process.cwd(), path), 'utf8');
|
|
const android = (path: string) => readFileSync(resolve(process.cwd(), '..', 'android-app', path), 'utf8');
|
|
const web = (path: string) => readFileSync(resolve(process.cwd(), '..', 'web-v2', path), 'utf8');
|
|
|
|
test('F6.8 persists field mutations locally and retries only when network is available', () => {
|
|
const queue = android('app/src/main/java/com/korexlabs/dhinspeccion/data/offline/OfflineQueue.kt');
|
|
assert.match(queue, /@Database\(entities = \[PendingMobileOperation::class, OfflineCacheEntry::class\]/);
|
|
assert.match(queue, /NetworkType\.CONNECTED/);
|
|
assert.match(queue, /OneTimeWorkRequestBuilder<OfflineSyncWorker>/);
|
|
for (const operation of [
|
|
'VISIT_START', 'VISIT_CLOSE', 'FIELD_ASSET_CREATE', 'FIELD_ASSET_PHOTO',
|
|
'ACT_CREATE', 'ACT_ASSET_ENSURE', 'FINDING_CREATE', 'FINDING_PHOTO',
|
|
'ACT_RESPONSIBLE', 'ACT_LOCK', 'COMPANY_OUTCOME', 'COMPANY_SIGNATURE', 'ACT_SEAL',
|
|
]) assert.match(queue, new RegExp(`"${operation}"`));
|
|
});
|
|
|
|
test('F6.8 isolates offline work and cached inspection data by authenticated user', () => {
|
|
const queue = android('app/src/main/java/com/korexlabs/dhinspeccion/data/offline/OfflineQueue.kt');
|
|
const mobile = android('app/src/main/java/com/korexlabs/dhinspeccion/data/DhMobile.kt');
|
|
const acts = android('app/src/main/java/com/korexlabs/dhinspeccion/data/MobileActs.kt');
|
|
const findings = android('app/src/main/java/com/korexlabs/dhinspeccion/data/FieldFindingsMobile.kt');
|
|
assert.match(queue, /val ownerUserId: String/);
|
|
assert.match(queue, /ownerUserId=:ownerUserId/);
|
|
assert.match(queue, /SecureSessionStore/);
|
|
assert.match(mobile, /userCacheKey/);
|
|
assert.match(acts, /userCacheKey/);
|
|
assert.match(findings, /userCacheKey/);
|
|
});
|
|
|
|
test('F6.8 gives offline-created objects idempotent client identities', () => {
|
|
const actDto = api('src/inspection-acts/dto/create-inspection-act.dto.ts');
|
|
const findingDto = api('src/inspection-findings/dto/create-inspection-finding.dto.ts');
|
|
const inventoryDto = api('src/inspection-visits/dto/create-field-inventory.dto.ts');
|
|
const migration = api('src/database/migrations/1790128200000-f6-8-offline-evidence-idempotency.ts');
|
|
assert.match(actDto, /clientGeneratedId/);
|
|
assert.match(findingDto, /clientGeneratedId/);
|
|
assert.match(inventoryDto, /clientGeneratedId/);
|
|
assert.match(migration, /inspection_finding_evidence/);
|
|
assert.match(migration, /asset_field_capture_events/);
|
|
assert.equal((migration.match(/client_operation_id/g) ?? []).length >= 6, true);
|
|
});
|
|
|
|
test('F6.8 reviews photos before queueing and never sends the retired ONLINE upload mode', () => {
|
|
const photo = android('app/src/main/java/com/korexlabs/dhinspeccion/ui/FieldFindingScreen.kt');
|
|
const acts = android('app/src/main/java/com/korexlabs/dhinspeccion/data/MobileActs.kt');
|
|
assert.match(photo, /Revisar fotografía/);
|
|
assert.match(photo, /Usar esta foto/);
|
|
assert.match(photo, /Volver a tomar/);
|
|
assert.match(photo, /Eliminar foto/);
|
|
assert.doesNotMatch(acts, /uploadMode: String = "ONLINE"/);
|
|
assert.match(acts, /uploadMode: String = "IMMEDIATE"/);
|
|
});
|
|
|
|
test('F6.8 makes the real Acta PDF and photographic record first-class in Dashboard', () => {
|
|
const controller = api('src/inspection-reports/inspection-reports.controller.ts');
|
|
const page = web('src/pages/InspectionActEditorPage.tsx');
|
|
const media = web('src/features/inspections/InspectionActMediaPanel.tsx');
|
|
assert.match(controller, /inspection-acts\/:actId\/pdf/);
|
|
assert.match(api('src/inspection-acts/inspection-acts.controller.ts'), /:id\/field-media/);
|
|
assert.match(api('src/inspection-acts/inspection-acts.service.ts'), /capture\.visit_id=act\.visit_id/);
|
|
assert.match(page, /Abrir PDF del Acta/);
|
|
assert.match(page, /Descargar PDF/);
|
|
assert.match(media, /Hallazgos del Acta/);
|
|
assert.match(media, /act-finding-photos/);
|
|
assert.match(media, /listInspectionFindingEvidence/);
|
|
});
|
|
|
|
test('F6.8 presents technical families to users as installation and subinstallation types', () => {
|
|
const config = web('src/pages/AssetTypesPage.tsx');
|
|
const detail = web('src/pages/SimpleInventoryDetailPage.tsx');
|
|
const field = api('src/inspection-visits/f3-field-inventory-structure.service.ts');
|
|
assert.match(config, /Tipos de Instalación/);
|
|
assert.match(config, /Tipos de Subinstalación/);
|
|
assert.match(detail, /Tipo de instalación \/ subinstalación/);
|
|
assert.match(field, /Tipo de instalación\/subinstalación/);
|
|
assert.doesNotMatch(config, /clasificación técnica/i);
|
|
assert.doesNotMatch(detail, /clasificación técnica/i);
|
|
});
|