import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import test from 'node:test'; import { isApiErrorV1, isApiQuestionnaireReadResponseV1, isApiSimulationJobsReadResponseV1, isApiSimulationReportReadResponseV1, isApiSimulationDraftAttachResponseV1, isApiSimulationDraftReadResponseV1, isApiSimulationDraftWriteResponseV1, isApiSimulationHistoryResponseV1, fiscalComponentCodes, indeterminateFiscalComponent, isApiSimulationCreateResponseV1, isApiSimulationReadResponseV1, isApiSimulationResultSnapshotV1, isSimulationCurrency, simulationCurrencyFractionDigits, simulationCurrencyOptions, validateSimulationResult, } from '../../resources/js/lib/simulation-contract.ts'; const apiSnapshot = { contract_version: 1, context: { reference_date: '2026-10-03', currency: null, currency_fraction_digits: null, scenario_id: '87654321-aaaa-bbbb-cccc-123456789abc', scenario_version: 1, engine_version: 'portal-arithmetic-v1', ruleset_version: null, }, result: { status: 'calculated', value: '0.000000', unit: null, explanation: 'Arithmetic indicative.', missing_inputs: [], source_ids: [], }, indicative_total: '0.000000', legal_interpretation: false, formula_version: 'portal-arithmetic-v1', }; const apiExecution = { id: '87654321-aaaa-bbbb-cccc-123456789abc', status: 'queued', version_no: 1, result_snapshot: null, }; const apiDraft = { id: '87654321-aaaa-bbbb-cccc-123456789abc', version_no: 2, snapshot_sha256: 'a'.repeat(64), personal_snapshot: [], economic_snapshot: { purpose: 'simulate_only' }, simulation_sources: [], updated_at: '2026-10-03T12:30:00.000000Z', }; const apiHistory = { data: [ { id: apiExecution.id, scope: 'personal', organization_name: null, status: 'completed', version_no: 1, created_at: '2026-10-03T12:00:00.000000Z', updated_at: '2026-10-03T12:00:01.000000Z', has_ready_report: true, }, ], meta: { current_page: 1, last_page: 1, per_page: 10, total: 1 }, }; const apiJob = { id: '87654321-aaaa-bbbb-cccc-123456789abc', simulation_id: '87654321-aaaa-bbbb-cccc-123456789abc', job_type: 'execute', status: 'succeeded', attempts: 1, available_at: '2026-10-03T12:00:00.000000Z', started_at: '2026-10-03T12:00:01.000000Z', finished_at: '2026-10-03T12:00:02.000000Z', error_code: null, }; void test('OpenAPI matches decimal-string inputs and execution response guards', async () => { const openapi = JSON.parse( await readFile( new URL( '../../docs/investmoz/simulations/openapi.json', import.meta.url, ), 'utf8', ), ); const schemas = openapi.components.schemas; assert.ok(schemas.DecimalInputString.pattern.includes(String.raw`\.`)); assert.equal( schemas.SimulationInput.properties.base.allOf[0].$ref, '#/components/schemas/DecimalInputString', ); assert.equal( schemas.SimulationInput.properties.rate.allOf[0].$ref, '#/components/schemas/PercentageInputString', ); assert.equal( schemas.UpdateScenarioInput.properties.base.allOf[0].$ref, '#/components/schemas/DecimalInputString', ); assert.deepEqual(schemas.SimulationExecutionV1.properties.status.enum, [ 'queued', 'running', 'completed', 'failed', 'cancelled', ]); assert.equal( openapi.paths['/simulations'].post.responses['202'].content[ 'application/json' ].schema.$ref, '#/components/schemas/SimulationCreateResponseV1', ); assert.equal( openapi.paths['/simulations/{id}'].get.responses['200'].content[ 'application/json' ].schema.$ref, '#/components/schemas/SimulationReadResponseV1', ); assert.equal( openapi.paths['/simulations/history'].get.responses['200'].content[ 'application/json' ].schema.$ref, '#/components/schemas/SimulationHistoryResponseV1', ); assert.equal( openapi.paths['/simulation-drafts/current'].get.responses['200'] .content['application/json'].schema.$ref, '#/components/schemas/SimulationDraftReadResponseV1', ); assert.equal( openapi.paths['/questionnaires/{code}'].get.responses['200'].content[ 'application/json' ].schema.$ref, '#/components/schemas/QuestionnaireReadResponseV1', ); assert.equal( openapi.paths['/simulations/{id}/jobs'].get.responses['200'].content[ 'application/json' ].schema.$ref, '#/components/schemas/SimulationJobsReadResponseV1', ); assert.equal( openapi.paths['/simulations/{id}/scenarios/{scenarioId}'].patch .responses['202'].content['application/json'].schema.$ref, '#/components/schemas/SimulationReadResponseV1', ); assert.equal( openapi.paths['/simulations/{id}/scenarios/{scenarioId}'].patch .responses['422'].content['application/json'].schema.$ref, '#/components/schemas/ApiErrorV1', ); assert.equal( schemas.SimulationHistoryResponseV1.properties.meta.properties.per_page .maximum, 50, ); for (const pathItem of Object.values(openapi.paths)) { for (const operation of Object.values(pathItem)) { for (const [status, response] of Object.entries( operation.responses ?? {}, )) { if (!/^4\d\d$/.test(status)) continue; assert.equal( response.content?.['application/json']?.schema?.$ref, '#/components/schemas/ApiErrorV1', `HTTP ${status} must use the shared API error contract`, ); } } } }); void test('currency codes are explicit and must be present in the supported currency catalog', () => { assert.equal(isSimulationCurrency('MZN'), true); assert.equal(isSimulationCurrency('USD'), true); assert.equal(isSimulationCurrency('mzn'), false); assert.equal(isSimulationCurrency('XYZ'), false); assert.equal(simulationCurrencyFractionDigits('JPY'), 0); assert.equal(simulationCurrencyFractionDigits('KWD'), 3); assert.equal(simulationCurrencyOptions.includes('JPY'), false); assert.equal(simulationCurrencyOptions.includes('KWD'), false); }); void test('calculated values preserve exact decimal strings, including zero', () => { assert.deepEqual( validateSimulationResult({ status: 'calculated', value: '0.00', unit: 'MZN', explanation: 'Cenário aritmético.', missingInputs: [], sourceIds: [], }), [], ); }); void test('API v1 wire envelope preserves exact zero and validates indeterminate states', () => { assert.equal(isApiSimulationResultSnapshotV1(apiSnapshot), true); assert.equal( isApiSimulationResultSnapshotV1({ ...apiSnapshot, context: { ...apiSnapshot.context, reference_date: '2026-02-31' }, }), false, ); assert.equal( isApiSimulationResultSnapshotV1({ ...apiSnapshot, context: { ...apiSnapshot.context, reference_date: '2024-02-29' }, }), true, ); assert.equal( isApiSimulationResultSnapshotV1({ ...apiSnapshot, indicative_total: null, result: { ...apiSnapshot.result, status: 'indeterminate', value: null, missing_inputs: ['approved_rule'], }, }), true, ); assert.equal( isApiSimulationResultSnapshotV1({ ...apiSnapshot, indicative_total: '0.000001', }), false, ); assert.equal( isApiSimulationResultSnapshotV1({ ...apiSnapshot, result: { ...apiSnapshot.result, value: '0' }, }), false, ); assert.equal( isApiSimulationResultSnapshotV1({ ...apiSnapshot, result: { ...apiSnapshot.result, status: 'indeterminate', missing_inputs: [], }, }), false, ); }); void test('simulation creation and polling responses require a valid execution view', () => { const queuedExecution = { ...apiExecution }; delete queuedExecution.result_snapshot; assert.equal( isApiSimulationCreateResponseV1({ data: queuedExecution, replayed: false, }), true, ); assert.equal(isApiSimulationReadResponseV1({ data: apiExecution }), true); const completedExecution = { ...apiExecution, status: 'completed', version_no: 2, result_snapshot: apiSnapshot, }; assert.equal( isApiSimulationReadResponseV1({ data: completedExecution }), true, ); assert.equal( isApiSimulationReadResponseV1({ data: { ...completedExecution, result_snapshot: { broken: true } }, }), false, ); assert.equal( isApiSimulationReadResponseV1({ data: { ...completedExecution, result_snapshot: null }, }), false, ); assert.equal( isApiSimulationReadResponseV1({ data: { ...apiExecution, result_snapshot: { contract_version: 1, indicative_total: '12', }, }, }), false, ); assert.equal( isApiSimulationReadResponseV1({ data: { ...completedExecution, result_snapshot: { indicative_total: '12.50' }, }, }), true, ); assert.equal( isApiSimulationCreateResponseV1({ data: apiExecution, replayed: false, }), true, ); assert.equal( isApiSimulationCreateResponseV1({ data: apiExecution, replayed: true, access_token: 'x'.repeat(48), }), true, ); assert.equal( isApiSimulationReadResponseV1({ data: { ...apiExecution, status: 'unknown' }, }), false, ); assert.equal( isApiSimulationReadResponseV1({ data: { id: apiExecution.id, status: 'completed', version_no: 2 }, }), false, ); assert.equal( isApiSimulationCreateResponseV1({ data: apiExecution, replayed: 'false', }), false, ); }); void test('history and encrypted-draft endpoints reject malformed envelopes', () => { assert.equal(isApiSimulationHistoryResponseV1(apiHistory), true); assert.equal( isApiSimulationHistoryResponseV1({ ...apiHistory, data: [{ ...apiHistory.data[0], status: 'unrecognized' }], }), false, ); assert.equal( isApiSimulationHistoryResponseV1({ ...apiHistory, meta: {} }), false, ); assert.equal(isApiSimulationDraftReadResponseV1({ data: apiDraft }), true); assert.equal(isApiSimulationDraftReadResponseV1({ data: null }), true); assert.equal( isApiSimulationDraftReadResponseV1({ data: { ...apiDraft, personal_snapshot: ['private'] }, }), false, ); assert.equal( isApiSimulationDraftWriteResponseV1({ data: { id: apiDraft.id, version_no: 3 }, }), true, ); assert.equal( isApiSimulationDraftWriteResponseV1({ data: { id: 'bad', version_no: 0 }, }), false, ); assert.equal( isApiSimulationDraftAttachResponseV1({ data: apiDraft, replayed: false, }), true, ); assert.equal( isApiSimulationDraftAttachResponseV1({ data: apiDraft, replayed: 'false', }), false, ); }); void test('questionnaire, report, job and error envelopes match their server contracts', () => { assert.equal( isApiQuestionnaireReadResponseV1({ data: { id: apiExecution.id, code: 'user-entered-arithmetic', version_no: 1, locale: 'pt-MZ', schema_snapshot: { inputs: {} }, status: 'published', valid_from: '2026-10-01', valid_to: null, }, }), true, ); assert.equal( isApiQuestionnaireReadResponseV1({ data: { id: apiExecution.id, code: 'user-entered-arithmetic', version_no: 1, locale: 'pt-MZ', schema_snapshot: { inputs: {} }, status: 'published', valid_from: '2026-02-31', valid_to: null, }, }), false, ); assert.equal( isApiQuestionnaireReadResponseV1({ data: { locale: 'en' } }), false, ); assert.equal( isApiSimulationReportReadResponseV1({ data: { id: apiExecution.id, simulation_id: apiExecution.id, version_no: 1, status: 'ready', report_snapshot: apiSnapshot, report_sha256: 'b'.repeat(64), }, }), true, ); assert.equal( isApiSimulationReportReadResponseV1({ data: { id: apiExecution.id, simulation_id: apiExecution.id, version_no: 1, status: 'ready', report_snapshot: [], report_sha256: 'invalid', }, }), false, ); assert.equal( isApiSimulationReportReadResponseV1({ data: { id: apiExecution.id, simulation_id: apiExecution.id, version_no: 1, status: 'queued', report_snapshot: apiSnapshot, report_sha256: 'b'.repeat(64), }, }), false, ); assert.equal( isApiSimulationReportReadResponseV1({ data: { id: apiExecution.id, simulation_id: apiExecution.id, version_no: 1, status: 'ready', report_snapshot: null, report_sha256: null, }, }), false, ); assert.equal(isApiSimulationJobsReadResponseV1({ data: [apiJob] }), true); assert.equal( isApiSimulationJobsReadResponseV1({ data: [{ ...apiJob, attempts: 4 }], }), false, ); assert.equal( isApiErrorV1({ message: 'Validation failed', errors: { base: ['Invalid'] }, }), true, ); assert.equal(isApiErrorV1({ message: 42 }), false); assert.equal(isApiErrorV1({ errors: { base: 'Invalid' } }), false); }); void test('wire contract guards survive a real JSON encode/decode round trip', () => { const wirePayloads = [ [isApiSimulationReadResponseV1, { data: apiExecution }], [ isApiSimulationCreateResponseV1, { data: apiExecution, replayed: false, access_token: 'x'.repeat(48), }, ], [isApiSimulationHistoryResponseV1, apiHistory], [isApiSimulationDraftReadResponseV1, { data: apiDraft }], [ isApiSimulationDraftAttachResponseV1, { data: apiDraft, replayed: false }, ], [isApiSimulationJobsReadResponseV1, { data: [apiJob] }], [ isApiSimulationResultSnapshotV1, { ...apiSnapshot, result: { ...apiSnapshot.result } }, ], ]; for (const [guard, payload] of wirePayloads) { const decoded = JSON.parse(JSON.stringify(payload)); assert.equal(guard(decoded), true); } }); void test('indeterminate results require missing inputs and cannot carry a numeric value', () => { assert.deepEqual( validateSimulationResult({ status: 'indeterminate', value: null, unit: null, explanation: 'Falta a classificação.', missingInputs: ['tariff_code'], sourceIds: [], }), [], ); assert.deepEqual( validateSimulationResult({ status: 'indeterminate', value: '0', unit: 'MZN', explanation: 'Sem dados.', missingInputs: [], sourceIds: [], }), ['indeterminate_inputs'], ); }); void test('estimated and not-applicable states must be explicit', () => { assert.deepEqual( validateSimulationResult({ status: 'estimated', value: '12.30', unit: 'MZN', explanation: 'Estimativa incompleta.', missingInputs: ['tariff_code'], sourceIds: [], }), [], ); assert.deepEqual( validateSimulationResult({ status: 'not_applicable', value: null, unit: null, explanation: 'Fora do cenário.', missingInputs: [], sourceIds: [], }), [], ); assert.deepEqual( validateSimulationResult({ status: 'not_applicable', value: '0', unit: 'MZN', explanation: 'Fora do cenário.', missingInputs: [], sourceIds: [], }), ['not_applicable_value'], ); }); void test('every tax component remains indeterminate until an approved effective rule exists', () => { assert.deepEqual(fiscalComponentCodes, [ 'IRPS', 'INSS', 'IVA', 'IRPC', 'ISPC', 'RETENCOES', ]); for (const code of fiscalComponentCodes) { const result = indeterminateFiscalComponent(code, '2026-10-02'); assert.deepEqual(validateSimulationResult(result), []); assert.equal(result.value, null); assert.ok(result.missingInputs.includes('approved_rule')); assert.deepEqual(result.sourceIds, []); } });