import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; import { createRequire } from 'node:module'; import { compileFunction } from 'node:vm'; import React from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; import ts from 'typescript'; const require = createRequire(import.meta.url); const root = path.resolve('resources/js'); function load(file, mocks = {}) { const absolute = path.resolve(root, file); const module = { exports: {} }; const code = ts.transpileModule(fs.readFileSync(absolute, 'utf8'), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022, jsx: ts.JsxEmit.ReactJSX, }, }).outputText; compileFunction(code, ['require', 'module', 'exports'])( (id) => { if (id in mocks) return mocks[id]; if (id === '@inertiajs/react') return { Link: ({ children, ...props }) => React.createElement('a', props, children), usePage: () => ({ url: '/sectores/test' }), }; if (id.startsWith('.') || id.startsWith('@/')) { const base = id.startsWith('@/') ? path.resolve(root, id.slice(2)) : path.resolve(path.dirname(absolute), id); const found = [base, base + '.tsx', base + '.ts'].find( (p) => fs.existsSync(p) && fs.statSync(p).isFile(), ); if (found) return load(path.relative(root, found), mocks); } return require(id); }, module, module.exports, ); return module.exports; } const render = (file, props) => renderToStaticMarkup(React.createElement(load(file).default, props)); test('demographic comparison retains four saved places and requires a province before searching districts', () => { const Page = load('pages/investment/demography.tsx', { './shared': { Frame: ({ children }) => React.createElement('main', null, children), button: '', }, '@/components/demographic-evidence': { default: () => null }, }).default; const territories = [ { id: 'p1', name: 'Província A', location_type: 'province', parent_id: null, }, { id: 'p2', name: 'Província B', location_type: 'province', parent_id: null, }, { id: 'd1', name: 'Distrito A', location_type: 'district', parent_id: 'p1', }, { id: 'd2', name: 'Distrito B', location_type: 'district', parent_id: 'p2', }, ]; const html = renderToStaticMarkup( React.createElement(Page, { evidence: { territories: [] }, filters: { territories: territories.map((t) => t.id), start_year: 2026, end_year: 2027, }, territories, sectors: { general: 'Geral' }, }), ); assert.match(html, /aria-label="Pesquisar Província da comparação"/); assert.match( html, /aria-label="Pesquisar Distrito da comparação \(opcional\)"[^>]*disabled/, ); assert.doesNotMatch(html, /]*multiple/); for (const t of territories) assert.ok(html.includes(`Retirar ${t.name} —`)); assert.match(html, /disabled=""[^>]*>Acrescentar à comparação/); assert.match(html, /value="2026"/); assert.match(html, /value="2027"/); }); test('the real preparation editor opens an own idea with its budget and no mandatory advert or duplicate reference selector', () => { const Empty = () => null; const Editor = load('pages/investor-path/context.tsx', { '@/pages/investment/shared': { Frame: ({ children }) => React.createElement('main', null, children), card: '', button: '', input: '', }, '@/components/navigation-context': { useNavigationContext: () => ({}) }, '@/components/investment-territory': { TerritoryFields: Empty }, '@/components/private-investment-preparation': { PreparationEditor: Empty, PreparationImpact: Empty, }, '@/components/investment-complements': { default: Empty, SelectedComplements: Empty, complementInput: (value) => value, }, '@/components/context-documents': { default: Empty }, '@/components/investment-opportunity-choices': { default: Empty }, '@/components/investment-requirements': { default: Empty }, '@/lib/operation-key': { createOperationKey: () => 'synthetic-key' }, }).default; const html = renderToStaticMarkup( React.createElement(Editor, { initial: { case: { id: 'synthetic-hotel', title: 'Criar Hotel', version: 1, }, context: { revision: 0, fields: { project_title: 'Criar Hotel' }, selection: {}, provenance: {}, opportunity_choices: [], }, private_investment: null, can_write: true, results: [], requests: [], preparation_documents: [], }, source: null, options: { countries: [ { code: 'MZ', name: 'Moçambique', name_en: 'Mozambique' }, ], sectors: [{ id: 7, name: 'Turismo QA' }], parks: [], search_limited: false, opportunities: [ { key: 'opportunity:2', title: 'Açúcar sem pertinência', kind: 'opportunity', }, ], }, entryIdea: { sector_id: '7', currency: 'MZN', investment_budget_min: '1000000', investment_budget_max: '5000000', }, }), ); assert.match(html, /Criar Hotel/); assert.match(html, /value="1000000"/); assert.match(html, /value="5000000"/); assert.match(html, /value="sector:7" selected=""/); assert.match(html, /Oportunidades relacionadas \(opcional\)/); assert.doesNotMatch(html, /Referência individual|Açúcar sem pertinência/); if (process.env.INVESTMOZ_INTENT_PREVIEW === '1') { const manifest = JSON.parse( fs.readFileSync( 'public/build-qa-opportunities/manifest.json', 'utf8', ), ); const css = fs.readFileSync( 'public/build-qa-opportunities/' + manifest['resources/css/app.css'].file, 'utf8', ); fs.writeFileSync( 'outputs/investor-intent-20261115/editor-preview.html', `InvesteMoz — prévia sintética de preparação

QA sintético: editor renderizado, sem autenticação, gravação ou consultas. A cartografia foi substituída no ensaio. Esta prévia não demonstra o percurso autenticado.

${html}
`, 'utf8', ); } }); test('changing the consulted territory remounts its evidence and aborts a late response', async () => { const state = [], refs = []; let cursor = 0, refCursor = 0, cleanup; const hooks = { useState(initial) { const index = cursor++; if (!(index in state)) state[index] = initial; return [ state[index], (next) => { state[index] = next; }, ]; }, useRef(initial) { const index = refCursor++; refs[index] ??= { current: initial }; return refs[index]; }, useEffect(callback) { cleanup = callback(); }, }; const Component = load('components/demographic-context.tsx', { react: hooks, }).default; const a = Component({ territoryId: 'synthetic-A' }); const b = Component({ territoryId: 'synthetic-B' }); assert.notEqual(a.key, b.key); assert.equal(Component({ territoryId: null }), null); const tree = a.type(a.props); const nodes = (n) => !n || typeof n !== 'object' ? [] : Array.isArray(n) ? n.flatMap(nodes) : [n, ...nodes(n.props?.children)]; const button = nodes(tree).find((n) => n.type === 'button'); const originalFetch = globalThis.fetch; let resolve, signal; globalThis.fetch = (url, options) => { assert.match(url, /synthetic-A/); signal = options.signal; return new Promise((done) => { resolve = done; }); }; try { const pending = button.props.onClick(); cleanup(); assert.equal(signal.aborted, true); resolve({ ok: true, json: async () => ({ territories: ['old A'] }) }); await pending; assert.equal( state[0], null, 'late evidence must not be attached to another territory', ); } finally { globalThis.fetch = originalFetch; } }); test('shared evidence is closed by default, preserves content and wraps long references', () => { const html = render('components/evidence-details.tsx', { children: 'source-version-hash', title: 'Fonte', }); assert.match(html, /]*>/); assert.doesNotMatch(html, /]*\bopen/); assert.match(html, /source-version-hash/); assert.match(html, /overflow-wrap:anywhere/); }); test('public document keeps applicability, usage limitations and actions visible, with source metadata in detail', () => { const { PublicDocumentContent } = load( 'components/public-document-content.tsx', ); const resource = { id: 1, title: 'Diploma QA', description: 'Objecto documentado', issuer: null, document_number: null, document_date: null, applicable_from: '2025-01-01', applicable_until: null, source_url: null, source_confirmation: 'unknown', usage_notice: 'Confirmar o âmbito aplicável', view_url: null, download_url: '/documents/1', context_actions: [], }; const html = renderToStaticMarkup( React.createElement(PublicDocumentContent, { resource }), ); assert.match(html, /2025-01-01/); assert.match(html, /Confirmar o âmbito aplicável/); assert.match(html, /href="\/documents\/1"/); assert.doesNotMatch(html, /Entidade emissora|Consultar ficha/); assert.ok(html.indexOf('Período indicado') > html.indexOf('')); }); test('territorial references retain exact citation and provenance without a primary internal-process block', () => { const source = { association: 'Corredor QA', role: 'Ligação', source_reference: 'Diploma QA §2', source_quote: 'Relação documentada', supports: '', traceability: 'original hash/version', official_source_accepted: true, existing_validation: 'validated', }; const html = render('components/territorial-source-evidence.tsx', { sources: [source], }); assert.match(html, /Diploma QA §2/); assert.match(html, /original hash\/version/); assert.doesNotMatch( html, /não retira a aceitação existente|campo específico/, ); assert.equal( render('components/territorial-source-evidence.tsx', { sources: [] }), '', ); }); test('empty published catalogue does not claim absent companies, resources or economic potential', () => { const html = render('components/published-opportunities-empty.tsx', { href: '/oportunidades?sector=qa', }); assert.match(html, /Sem anúncios publicados/); assert.match( html, /não indica ausência de empresas, recursos ou potencial/, ); assert.match(html, /sector=qa/); }); const value = ( year, age_group = 'all', data_kind = 'projected', unit = 'pessoas', ) => ({ year, indicator: 'population', age_group, residence: 'all', value: '1234', original_value: '1 234', unit, data_kind, sheet: 'sheet', cell: 'B' + year, validation_status: 'valid', }); test('demographic highlights never sum dimensions, mix units or silently replace a source/version', () => { const { demographicHighlights } = load( 'components/demographic-evidence.tsx', ); const values = [ value(2024), value(2025), value(2026, '0-4'), value(2024, 'all', 'observed'), value(2023, 'all', 'projected', 'unspecified'), ]; assert.deepEqual(demographicHighlights(values), [ values[1], values[3], values[4], ]); assert.deepEqual(demographicHighlights([value(2025, '0-4')]), []); }); test('demography shows original latest total, period, projection and decision warning; technical cells remain closed', () => { const evidence = { state: 'available', start_year: 2024, end_year: 2025, limitations: ['Não prova procura'], comparisons: [], differences: [], territories: [ { id: 'qa', name: 'Território QA', level: 'province', factors_to_assess: [], series: [ { import_id: 'qa', source: 'Fonte QA', version: 'Edição QA', sha256: '123abc', file_name: 'QA.xlsx', missing_years: [], issue_counts: {}, values: [value(2024), value(2025)], }, ], }, ], }; const html = render('components/demographic-evidence.tsx', { evidence }); assert.match(html, /1 234/); assert.match(html, /não demonstram procura ou rentabilidade/); assert.match(html, /Projecção/); assert.match(html, /SHA256/); assert.ok(html.indexOf('SHA256') > html.indexOf(']*\bopen/); }); test('cluster analysis omits empty field blocks but keeps documented evidence and uncertainty', () => { const { forces } = load('lib/cluster-competitiveness.ts'); const rows = Object.fromEntries( forces.map((f) => [ f, { pressure: '', evidence: 'Facto QA', source: '', period: '', rationale: '', limitations: 'Por confirmar', opportunity: '', }, ]), ); const html = render('components/cluster-competitiveness-public.tsx', { analysis: { version: 1, at: '2026-11-15', draft: { sector: 'QA', region: 'Local QA', forces: rows }, }, }); assert.match(html, /Facto QA/); assert.match(html, /Por confirmar/); assert.doesNotMatch(html, /]*>Fonte e referência/); }); test('simulator keeps original calculation correspondence and source behind explicit details', () => { const { SimulationModeloA } = load('components/simulation-modelo-a.tsx'); const html = renderToStaticMarkup( React.createElement(SimulationModeloA, { draft: {} }), ); assert.match(html, /Modelo A/); assert.match(html, /SHA256/); assert.ok( html.indexOf('SHA256') > html.indexOf('Exemplar e integridade da fonte'), ); assert.match(html, /não é imposto final/); }); // Optional visual fixture: the real components with explicit synthetic data, // not an authenticated application or an operational publication. if (process.env.INVESTMOZ_RECONCILIATION_PREVIEW === '1') { const population = (year, age, amount, residence = 'all') => ({ ...value(year, age, 'projected', 'pessoas'), residence, value: String(amount), original_value: String(amount), cell: `${year}-${age}-${residence}`, }); const values = [ population(2026, 'all', 1000), population(2028, 'all', 1200), population(2028, 'all', 480, 'urban'), population(2028, 'all', 720, 'rural'), ]; for (const age of ['0-4', '5-9', '10-14']) values.push(population(2028, age, 120)); for (const age of [ '15-19', '20-24', '25-29', '30-34', '35-39', '40-44', '45-49', '50-54', '55-59', '60-64', ]) values.push(population(2028, age, 60)); const evidence = { state: 'available', start_year: 2026, end_year: 2028, sector: 'general', limitations: [ 'Exclusivamente dados sintéticos. Não representam população real.', ], comparisons: [], differences: [], territories: [ { id: 'synthetic-qa', name: 'Território sintético QA', level: 'district', factors_to_assess: [], series: [ { import_id: 'qa', source: 'Fonte sintética de ensaio', version: 'QA 2026', sha256: 'a'.repeat(64), file_name: 'exemplo-sintetico.xlsx', missing_years: [2027], issue_counts: {}, values, }, ], }, ], }; const demographicHtml = render('components/demographic-evidence.tsx', { evidence, }); const emptyHtml = render('components/published-opportunities-empty.tsx', { href: '#demografia', label: 'Estudar a localização', }); const { PublicDocumentContent } = load( 'components/public-document-content.tsx', ); const documentHtml = renderToStaticMarkup( React.createElement(PublicDocumentContent, { resource: { id: 1, title: 'Guia sintético QA', description: 'Documento de ensaio para conferir a apresentação.', issuer: 'Entidade sintética', document_number: 'QA-1', document_date: '2026-11-15', applicable_from: '2026-11-15', applicable_until: null, source_url: null, source_confirmation: 'unknown', usage_notice: 'Exemplo de limitação relevante, conservada junto do documento.', view_url: null, download_url: '#documento', context_actions: [], }, }), ); const sourceHtml = render('components/territorial-source-evidence.tsx', { sources: [ { association: 'Relação territorial sintética', role: 'Contexto', source_reference: 'Fonte sintética §1', source_quote: 'Relação apenas para ensaio.', supports: '', traceability: 'Versão QA e original conservados', official_source_accepted: false, existing_validation: null, }, ], }); const { SimulationModeloA } = load('components/simulation-modelo-a.tsx'); const simulatorHtml = renderToStaticMarkup( React.createElement(SimulationModeloA, { draft: {} }), ); const manifest = JSON.parse( fs.readFileSync('public/build-qa-opportunities/manifest.json', 'utf8'), ); const css = fs.readFileSync( 'public/build-qa-opportunities/' + manifest['resources/css/app.css'].file, 'utf8', ); fs.writeFileSync( 'outputs/demography-reconciliation-20261115/visual-components.html', `InvesteMoz QA — conferência de componentes

InvesteMoz — prévia QA

Componentes reais com dados sintéticos. Não é uma sessão autenticada nem publicação no portal.

${demographicHtml}

Contexto territorial

${sourceHtml}
${documentHtml}
${simulatorHtml}
`, 'utf8', ); }