import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { execFileSync } from 'node:child_process'; import { compileFunction } from 'node:vm'; import { createRequire } from 'node:module'; import { renderToStaticMarkup } from 'react-dom/server'; import ts from 'typescript'; const require = createRequire(import.meta.url); function load(file, mocks = {}) { const code = ts.transpileModule( fs.readFileSync(new URL(file, import.meta.url), 'utf8'), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022, jsx: ts.JsxEmit.ReactJSX, }, }, ).outputText; const module = { exports: {} }; compileFunction(code, ['require', 'module', 'exports'])( (key) => mocks[key] ?? require(key), module, module.exports, ); return module.exports; } // Pure config export: no application bootstrap, connection or active database access. const guide = JSON.parse( execFileSync( 'php', [ '-r', "echo json_encode(require 'config/bvm-admission-guide.php', JSON_THROW_ON_ERROR);", ], { cwd: new URL('../..', import.meta.url), encoding: 'utf8' }, ), ); guide.sha256 = 'b'.repeat(64); const lib = load('../../resources/js/lib/investment-guides.ts'); const props = { guide, instruments: [], note: '', case: null, saved: null, canWrite: false, historical: false, olderEdition: false, currentAvailable: true, workingCopy: false, contextChanged: false, unavailableInstruments: [], history: [], historyNext: null, }; function nodes(tree) { if (!tree || typeof tree !== 'object') return []; if (Array.isArray(tree)) return tree.flatMap(nodes); return [tree, ...nodes(tree.props?.children)]; } function harness() { let cursor = 0; const values = [], requests = []; class ValidationError extends Error {} const component = load('../../resources/js/pages/investment/guide.tsx', { react: { useState(initial) { const i = cursor++; if (!(i in values)) values[i] = structuredClone(initial); return [ values[i], (value) => { values[i] = typeof value === 'function' ? value(values[i]) : value; }, ]; }, useRef(initial) { const i = cursor++; if (!(i in values)) values[i] = { current: initial }; return values[i]; }, }, '@inertiajs/react': { Link: 'a', router: { visit() {} } }, './shared': { Frame: 'main', card: '', input: '', button: '' }, '@/lib/investment-guides': lib, '@/lib/operation-key': { createOperationKey: () => 'SYNTHETIC-operation', }, '@/lib/profile-json': { ProfileValidationError: ValidationError, profileJson: async (...args) => { requests.push(args); return { saved: true }; }, }, }); return { render(extra = {}) { cursor = 0; const outer = component.default({ ...props, ...extra }); return outer.type(outer.props); }, requests, }; } function headingCount(tree, label) { return nodes(tree).filter( (n) => ['h2', 'h3', 'h4'].includes(n.type) && n.props.children === label, ).length; } await test('actual source guide renders five paths, scoped gaps and article/page links with explicit historical minimums', () => { const tree = harness().render(), html = renderToStaticMarkup(tree); assert.equal( nodes(tree).filter( (n) => n.type === 'input' && n.props.name === 'instruments[]', ).length, 5, ); assert.match(html, /Que segmento e tipo de valor pretende preparar/); assert.match(html, /Requisitos por segmento e tipo de valor/); assert.match(html, /Período indicado até 2025-03-31/); assert.match(html, /fonte histórica, sem aplicação como mínimo actual/); assert.match(html, /Por esclarecer/); assert.match(html, /Regra com dispensa ou condição específica/); assert.match(html, /Regulamento 04\/2021/); assert.ok( nodes(tree).some( (n) => n.type === 'a' && n.props.href === 'https://www.bvm.co.mz/documentos/regulamentos/RegulamentoTerceiroMercado.pdf#page=2', ), ); assert.match(html, /Art. 2\(1\)\(c\) e art. 8/); assert.equal(headingCount(tree, 'Preparar para discussão'), 0); assert.doesNotMatch(html, /name="(note|nuit|email|amount|capital)"/); }); await test('third-market selection hides the entry audit document while keeping OCAM, declaration and conditional waiver explanations', () => { const h = harness(); nodes(h.render()) .find((n) => n.props?.value === 'third_shares') .props.onChange({ target: { checked: true } }); const tree = h.render(), html = renderToStaticMarkup(tree); assert.equal(headingCount(tree, 'Auditoria ou certificação aplicável'), 0); assert.equal( headingCount( tree, 'Demonstrações financeiras assinadas por contabilista certificado', ), 1, ); assert.equal( headingCount(tree, 'Declaração de actualidade das informações'), 1, ); assert.equal( headingCount(tree, 'Detentores do capital e participações'), 1, ); assert.match(html, /sem extensão automática/); assert.match(html, /demonstrações e relatório de evolução semestrais/); assert.doesNotMatch(html, /Existência jurídica de um ano, não derrogável/); assert.doesNotMatch( html, /Relatórios de gestão e contas anuais dos dois exercícios anteriores/, ); }); await test('multiple paths share common documents once while retaining their different accounts and prospectus conditions', () => { const h = harness(); for (const code of ['official_shares', 'second_shares']) nodes(h.render()) .find((n) => n.props?.value === code) .props.onChange({ target: { checked: true } }); const tree = h.render(), html = renderToStaticMarkup(tree); for (const title of [ 'Deliberações, estatutos e certidão', 'Relatórios, contas, fiscalização e publicações', 'Auditoria ou certificação aplicável', 'Projecto de prospecto conforme o segmento', ]) assert.equal(headingCount(tree, title), 1); assert.equal( headingCount( tree, 'Demonstrações financeiras assinadas por contabilista certificado', ), 0, ); assert.match(html, /dois exercícios anteriores/); assert.match(html, /pelo menos nove meses/); assert.match(html, /Anexo A do Regulamento do Segundo Mercado/); assert.doesNotMatch( html, /Documentos específicos do empréstimo obrigacionista/, ); }); await test('bonds use their own document path and external handoffs never receive private note or dossier parameters', () => { const dossier = { id: 'SYNTHETIC-private-dossier', title: 'SYNTHETIC private context', version: 1, }; const tree = harness().render({ case: dossier, canWrite: true, instruments: ['second_bonds'], note: 'SYNTHETIC PRIVATE NOTE', }); assert.equal( headingCount( tree, 'Documentos específicos do empréstimo obrigacionista', ), 1, ); assert.equal( headingCount(tree, 'Detentores do capital e participações'), 0, ); assert.ok( nodes(tree).some( (n) => n.props?.href === '/balcao-virtual/dossiers/SYNTHETIC-private-dossier', ), ); const external = nodes(tree).filter( (n) => n.type === 'a' && n.props.href?.startsWith('https://'), ); assert.ok(external.length > 10); for (const link of external) { assert.doesNotMatch( link.props.href, /SYNTHETIC|note=|context=|dossier=/, ); assert.equal(new URL(link.props.href).search, ''); assert.equal(link.props.rel, 'noopener noreferrer'); } assert.ok( external.some( (n) => n.props.href === 'https://www.bvm.co.mz/empresas/0/0', ), ); }); await test('historical BVM references render frozen sources and conditions without reopening a write or mixing guide history', async () => { const h = harness(); const oldGuide = { ...guide, version: 'SYNTHETIC-old-BVM-edition' }; const tree = h.render({ guide: oldGuide, instruments: ['third_shares'], case: { id: 'SYNTHETIC-case', title: 'SYNTHETIC', version: 3 }, saved: { revision: 1, at: 'SYNTHETIC-date', context: { revision: 0 } }, canWrite: true, historical: true, history: [ { id: 'SYNTHETIC-event', revision: 1, edition: 'SYNTHETIC-old-BVM-edition', at: 'SYNTHETIC-date', }, ], }); assert.equal( nodes(tree).find((n) => n.type === 'fieldset').props.disabled, true, ); nodes(tree) .find((n) => n.type === 'form') .props.onSubmit({ preventDefault() {} }); await new Promise((resolve) => setImmediate(resolve)); assert.equal(h.requests.length, 0); assert.match(renderToStaticMarkup(tree), /SYNTHETIC-old-BVM-edition/); assert.ok( nodes(tree).some( (n) => n.props?.href === '/investimentos/SYNTHETIC-case/guias/bolsa?revision=SYNTHETIC-event', ), ); });