import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { createRequire } from 'node:module'; import { compileFunction } from 'node:vm'; import React from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; import ts from 'typescript'; import pathModule from 'node:path'; const require = createRequire(import.meta.url); function load(path, overrides = {}) { const source = fs.readFileSync( new URL('../../resources/js/' + path, import.meta.url), 'utf8', ); const module = { exports: {} }; const code = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022, jsx: ts.JsxEmit.ReactJSX, }, }).outputText; compileFunction(code, ['require', 'module', 'exports'])( (n) => { if (n in overrides) return overrides[n]; const relative = n.startsWith('@/') ? n.slice(2) : n.startsWith('.') ? pathModule.posix.join(pathModule.posix.dirname(path), n) : null; if (relative) { for (const candidate of [relative, relative + '.tsx', relative + '.ts']) { if (fs.existsSync(new URL('../../resources/js/' + candidate, import.meta.url))) return load(candidate, overrides); } } return require(n); }, module, module.exports, ); return module.exports; } const helpers = load('lib/demographic-reading.ts'); const Summary = load('components/demographic-reading-summary.tsx', { '@/lib/demographic-reading': helpers, }).default; const Details = load('components/evidence-details.tsx').default; const Component = load('components/demographic-evidence.tsx', { './demographic-reading-summary': { default: Summary }, './evidence-details': { default: Details }, }).default; const row = (age, value, residence = 'all', year = 2026, extra = {}) => ({ year, indicator: 'population', age_group: age, residence, value, original_value: value, unit: 'pessoas', data_kind: 'projected', sheet: String(year), cell: `${age}-${residence}`, validation_status: 'valid', ...extra, }); const series = (values) => ({ import_id: 'source-one', source: 'INE', version: 'SYNTHETIC test edition', sha256: 'a'.repeat(64), file_name: 'source.xlsx', missing_years: [], issue_counts: {}, values, }); const ages = [ '15-19', '20-24', '25-29', '30-34', '35-39', '40-44', '45-49', '50-54', '55-59', '60-64', ]; const base = () => series([ row('all', '1000.1234567890123'), row('all', '400', 'urban'), row('all', '600.1234567890123', 'rural'), row('0-4', '100'), row('5-9', '100'), row('10-14', '100'), ...ages.map((a) => row(a, '50')), ]); const evidence = (s) => ({ state: 'available', start_year: 2026, end_year: 2026, sector: 'general', limitations: ['Population is not demand.'], comparisons: [], differences: [], territories: [ { id: 'district-one', name: 'Báruè', level: 'district', factors_to_assess: [], series: s, }, ], }); test('summarises compatible age/residence groups without changing original decimals', () => { const s = base(), before = JSON.stringify(s), r = helpers.demographicReading(s, 2026, 2026); assert.equal(r.last.under15, 300); assert.equal(r.last.age15to64, 500); assert.ok(Math.abs(r.last.ruralShare - 60.00493766) < 0.00001); assert.equal(JSON.stringify(s), before); assert.equal(r.growth, null); }); test('missing age bands remain unknown; zeros are preserved', () => { const s = base(); s.values = s.values.filter((r) => r.age_group !== '5-9'); assert.equal(helpers.demographicReading(s, 2026, 2026).last.under15, null); const r = helpers.demographicReading( series([ row('all', '0'), row('all', '0', 'urban'), row('all', '0', 'rural'), ]), 2026, 2026, ); assert.equal(r.last.total, 0); assert.equal(r.last.ruralShare, null); }); test('duplicate dimensions and incompatible kinds cannot supply invented shares', () => { const s = base(); s.values.push(row('0-4', '200')); s.values.find((r) => r.residence === 'rural').data_kind = 'observed'; const r = helpers.demographicReading(s, 2026, 2026).last; assert.equal(r.under15, null); assert.equal(r.rural, null); assert.equal(r.ruralShare, null); }); test('inconsistent residence components do not produce percentages', () => { const s = series([ row('all', '100'), row('all', '80', 'urban'), row('all', '80', 'rural'), ]); const r = helpers.demographicReading(s, 2026, 2026).last; assert.equal(r.urban, 80); assert.equal(r.urbanShare, null); assert.equal(r.ruralShare, null); }); test('growth uses explicit comparable endpoints and does not fill missing intermediate years', () => { const s = series([ row('all', '100', 'all', 2026), row('all', '120', 'all', 2028), ]); const r = helpers.demographicReading(s, 2026, 2028); assert.equal(r.growth, 20); assert.equal(r.years[1].total, null); assert.equal(helpers.demographicReading(s, 2026, 2030).growth, null); s.values[1].data_kind = 'observed'; assert.equal(helpers.demographicReading(s, 2026, 2028).growth, null); }); test('technical source and full decimals remain available in closed details after a readable summary', () => { const html = renderToStaticMarkup( React.createElement(Component, { evidence: evidence([base()]) }), ); assert.ok( html.indexOf('Retrato da população') < html.indexOf('Valores originais por ano'), ); assert.match(html, /1000.1234567890123/); assert.match(html, /Valores por dimensão, fonte e advertências/); assert.doesNotMatch(html, /]*\bopen\b/); assert.match(html, /um único ano/); assert.match(html, /capacidade instalada/); assert.match(html, /qualificações/); }); test('multiple editions receive separate summaries rather than a summed population', () => { const a = series([row('all', '100')]), b = { ...series([row('all', '900')]), import_id: 'source-two' }; const html = renderToStaticMarkup( React.createElement(Component, { evidence: evidence([a, b]) }), ); assert.equal((html.match(/Retrato da população/g) || []).length, 2); assert.match(html, />100<\/dd>/); assert.match(html, />900<\/dd>/); }); test('demographic page offers territory-only preparation independent of old commercial filters', () => { const Page = load('pages/investment/demography.tsx', { '@inertiajs/react': { router: {} }, '@/components/demographic-evidence': { default: Component }, './shared': { Frame: ({ children }) => React.createElement('main', null, children), button: '', }, }).default; const html = renderToStaticMarkup( React.createElement(Page, { evidence: evidence([base()]), filters: { territories: ['district-one'], sector: 'general' }, territories: [], sectors: { general: 'Contexto geral' }, }), ); assert.match(html, /source=territory%3Adistrict-one/); assert.doesNotMatch(html, /compra de propriedade|sector=turismo|modality=/); assert.match(html, /Não é necessário haver uma oportunidade publicada/); }); test('Barue 2026 provided evidence produces the readable proportions without changing originals', () => { const fixture = JSON.parse( fs.readFileSync( new URL('../Fixtures/demography/barue-2026.json', import.meta.url), 'utf8', ), ); const s = series(fixture.values), before = JSON.stringify(s); const r = helpers.demographicReading(s, 2026, 2026).last; assert.equal(Math.round(r.total), 248518); assert.equal(Number(r.ruralShare.toFixed(1)), 65.1); assert.equal(Number(r.under15Share.toFixed(1)), 45.6); assert.equal(Number(r.age15to64Share.toFixed(1)), 51.3); assert.equal(JSON.stringify(s), before); });