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/); 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); });