From 0442511065b4f4b4fc2ae240949fec6cf47e3287 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Tue, 8 Sep 2026 10:29:42 -0300 Subject: [PATCH] test(f4): guard android lock seal lifecycle contract --- .../test/unit/f4-android-act-contract.test.ts | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 api-v3/test/unit/f4-android-act-contract.test.ts diff --git a/api-v3/test/unit/f4-android-act-contract.test.ts b/api-v3/test/unit/f4-android-act-contract.test.ts new file mode 100644 index 0000000..f50fcd8 --- /dev/null +++ b/api-v3/test/unit/f4-android-act-contract.test.ts @@ -0,0 +1,43 @@ +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 android = (...segments: string[]) => path.join(root, '..', 'android-app', 'app', 'src', 'main', 'java', 'com', 'korexlabs', 'dhinspeccion', ...segments); +const read = (...segments: string[]) => fs.readFileSync(android(...segments), 'utf8'); + +const mobileCore = read('data', 'DhMobile.kt'); +const mobileActs = read('data', 'MobileActs.kt'); +const viewModel = read('MainViewModel.kt'); + +test('F4 Android inspection contract has no title or planned end field', () => { + const summary = mobileCore.slice(mobileCore.indexOf('data class VisitSummary('), mobileCore.indexOf('data class VisitMeta(')); + const detail = mobileCore.slice(mobileCore.indexOf('data class VisitDetail('), mobileCore.indexOf('// ---------- Field inventory ----------')); + + assert.doesNotMatch(summary, /\btitle\s*:/); + assert.doesNotMatch(summary, /\bplannedEndAt\b/); + assert.doesNotMatch(detail, /\btitle\s*:/); + assert.doesNotMatch(detail, /\bplannedEndAt\b/); + assert.match(summary, /plannedStartAt/); + assert.match(detail, /plannedStartAt/); +}); + +test('F4 Android uses only lock and seal endpoints for the active Act lifecycle', () => { + assert.match(mobileActs, /inspection-acts\/\{actId\}\/lock/); + assert.match(mobileActs, /inspection-acts\/\{actId\}\/seal/); + assert.doesNotMatch(mobileActs, /inspection-acts\/\{actId\}\/ready/); + assert.doesNotMatch(mobileActs, /inspection-acts\/\{actId\}\/reopen/); + assert.doesNotMatch(mobileActs, /inspection-acts\/\{actId\}\/close["']/); + assert.doesNotMatch(mobileActs, /suspend fun prepare\(/); + assert.doesNotMatch(mobileActs, /suspend fun reopen\(/); + assert.doesNotMatch(mobileActs, /suspend fun closeAct\(/); +}); + +test('F4 Android ViewModel calls lock and seal directly', () => { + assert.match(viewModel, /actsRepository\.lock\(actId\)/); + assert.match(viewModel, /actsRepository\.seal\(actId\)/); + assert.doesNotMatch(viewModel, /actsRepository\.prepare\(/); + assert.doesNotMatch(viewModel, /actsRepository\.reopen\(/); + assert.doesNotMatch(viewModel, /actsRepository\.closeAct\(/); +});