diff --git a/api-v3/test/unit/f6-1-presentation-ready-contract.test.ts b/api-v3/test/unit/f6-1-presentation-ready-contract.test.ts new file mode 100644 index 0000000..0b5689e --- /dev/null +++ b/api-v3/test/unit/f6-1-presentation-ready-contract.test.ts @@ -0,0 +1,66 @@ +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 web = (path: string) => readFileSync(resolve(process.cwd(), '..', 'web-v2', path), 'utf8'); +const android = (path: string) => readFileSync(resolve(process.cwd(), '..', 'android-app', path), 'utf8'); + +test('F6.1 presentation metadata keeps the visible WEB version aligned with package metadata', () => { + const pkg = JSON.parse(web('package.json')) as { version: string }; + const version = web('src/config/version.ts'); + const visibleVersion = version.match(/APP_VERSION\s*=\s*'([^']+)'/)?.[1]; + + assert.equal(visibleVersion, pkg.version); + assert.match(version, /APP_PHASE\s*=\s*'F6\.1 · Contexto operativo Área–Operadora consolidado'/); +}); + +test('F6.1 presentation keeps Relevamientos retired from WEB navigation and routes', () => { + const app = web('src/app/App.tsx'); + const layout = web('src/layout/AppLayout.tsx'); + + assert.doesNotMatch(app, /relevamientos/i); + assert.doesNotMatch(layout, /relevamientos/i); + assert.match(layout, /label: 'Inspecciones'/); + assert.match(layout, /label: 'Inventarios'/); +}); + +test('F6.1 presentation keeps the complete Inspector profile and documentary-copy explanation visible', () => { + const user = web('src/pages/UserDetailPage.tsx'); + const delivery = api('src/inspection-reports/inspection-document-delivery.service.ts'); + + for (const field of ['dni', 'phone', 'jobTitle', 'employeeNumber']) { + assert.match(user, new RegExp(`name="${field}"`)); + } + assert.match(user, /email es obligatorio para un Inspector/i); + assert.match(user, /la documentación se enviará también/i); + assert.match(delivery, /recipientKind:'INSPECTOR'/); + assert.match(delivery, /documentKind:'ACT_PDF'/); + assert.match(delivery, /documentKind:'REPORT_WORD'/); +}); + +test('F6.1 presentation keeps Android start, Otro and chronological merge flows wired to the canonical API', () => { + const mobileApi = android('app/src/main/java/com/korexlabs/dhinspeccion/data/DhMobile.kt'); + const overview = android('app/src/main/java/com/korexlabs/dhinspeccion/ui/F3VisitRoot.kt'); + const viewModel = android('app/src/main/java/com/korexlabs/dhinspeccion/MainViewModel.kt'); + + assert.match(mobileApi, /inspection-visits\/\{id\}\/start/); + assert.match(mobileApi, /field-inventory\/\{assetId\}\/merge/); + assert.match(overview, /Text\("Iniciar inspección"\)/); + assert.match(overview, /Otro \/ no catalogado/); + assert.match(viewModel, /repository\.startVisit\(id\)/); + assert.match(viewModel, /selectedFieldAsset = repository\.selectFieldAsset\(visitId, result\.canonical\.id\)/); + assert.match(viewModel, /la historia de \$\{result\.source\.code\} permanece trazable/); +}); + +test('F6.1 presentation keeps catalog merge append-only for emitted findings', () => { + const merge = api('src/inspection-findings/finding-catalog-merge.service.ts'); + const resolver = api('src/inspection-findings/f3-finding-catalog-resolver.service.ts'); + + assert.match(merge, /los Hallazgos emitidos nunca se reescriben/); + assert.match(merge, /historicalFindingsRewritten: false/); + assert.match(merge, /historyPolicy: 'EMITTED_FINDINGS_PRESERVED'/); + assert.match(resolver, /code: 'OTHER'/); + assert.match(resolver, /label: 'OTROS'/); +});