299 lines
11 KiB
JavaScript
299 lines
11 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import { compileFunction } from 'node:vm';
|
|
import { createRequire } from 'node:module';
|
|
import React from 'react';
|
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
import ts from 'typescript';
|
|
import * as presentation from '../../resources/js/lib/funding-public-presentation.ts';
|
|
const require = createRequire(import.meta.url),
|
|
records = Object.values(
|
|
JSON.parse(
|
|
fs.readFileSync(
|
|
new URL(
|
|
'../../database/data/funding-institutions-nov2026.json',
|
|
import.meta.url,
|
|
),
|
|
'utf8',
|
|
),
|
|
).references,
|
|
).map((x) => x.draft);
|
|
function load(file) {
|
|
const module = { exports: {} };
|
|
const output = ts.transpileModule(
|
|
fs.readFileSync(
|
|
new URL('../../resources/js/' + file, import.meta.url),
|
|
'utf8',
|
|
),
|
|
{
|
|
compilerOptions: {
|
|
module: ts.ModuleKind.CommonJS,
|
|
target: ts.ScriptTarget.ES2022,
|
|
jsx: ts.JsxEmit.ReactJSX,
|
|
},
|
|
},
|
|
).outputText;
|
|
compileFunction(output, ['require', 'module', 'exports'])(
|
|
(name) =>
|
|
name === '@/lib/funding-public-presentation'
|
|
? presentation
|
|
: name === '@/pages/investment/shared'
|
|
? {
|
|
Frame: ({ title, children }) =>
|
|
React.createElement(
|
|
'main',
|
|
null,
|
|
React.createElement('h1', null, title),
|
|
children,
|
|
),
|
|
card: 'card',
|
|
button: 'button',
|
|
input: 'input',
|
|
}
|
|
: name === '@inertiajs/react'
|
|
? {
|
|
Link: ({ children, href }) =>
|
|
React.createElement('a', { href }, children),
|
|
router: {},
|
|
useForm: (data) => ({ data, setData() {}, get() {} }),
|
|
}
|
|
: name === './shared'
|
|
? { windowLabels: {} }
|
|
: name === '@/lib/portal-api'
|
|
? {
|
|
portalRequest: () => {
|
|
throw Error(
|
|
'Read-only rendering must not send requests',
|
|
);
|
|
},
|
|
}
|
|
: name === '@/components/funding-classification'
|
|
? load('components/funding-classification.tsx')
|
|
: name === '@/components/funding-institution'
|
|
? load('components/funding-institution.tsx')
|
|
: name === '@/components/funding-dossier-choice'
|
|
? { FundingDossierChoice: () => null }
|
|
: name ===
|
|
'@/components/funding-criteria-assessment'
|
|
? load(
|
|
'components/funding-criteria-assessment.tsx',
|
|
)
|
|
: require(name),
|
|
module,
|
|
module.exports,
|
|
);
|
|
return module.exports;
|
|
}
|
|
test('all270 imported institutions get readable descriptions and evidenced services without changing the published payload', () => {
|
|
assert.equal(records.length, 270);
|
|
for (const p of records) {
|
|
const original = JSON.stringify(p),
|
|
m = presentation.fundingPublicPresentation(p);
|
|
assert.ok(m.description);
|
|
assert.doesNotMatch(
|
|
m.description,
|
|
/documento fornecido|ficha|SHA-256|Público\/finalidade/,
|
|
);
|
|
assert.equal(JSON.stringify(p), original);
|
|
assert.equal(
|
|
m.products.length,
|
|
(p.products ?? []).filter((x) => x.availability !== 'closed')
|
|
.length,
|
|
);
|
|
}
|
|
});
|
|
test('deliberate editorial descriptions survive and missing products are never fabricated', () => {
|
|
const m = presentation.fundingPublicPresentation({
|
|
title: 'Example',
|
|
kind: 'institution',
|
|
summary: 'Apoio especializado ao investimento rural.',
|
|
products: [],
|
|
institution_types: ['insurer'],
|
|
});
|
|
assert.equal(m.description, 'Apoio especializado ao investimento rural.');
|
|
assert.deepEqual(m.products, []);
|
|
assert.deepEqual(m.services, []);
|
|
});
|
|
test('actual public cards and detail lead with description/products and keep import metadata out of the visitor text', () => {
|
|
const Index = load('pages/funding/index.tsx').default,
|
|
Show = load('pages/funding/show.tsx').default;
|
|
for (const raw of [
|
|
records[0],
|
|
records.find((p) => p.institution_types.includes('investment_manager')),
|
|
]) {
|
|
const p = { ...raw, windows: [], documents: [] },
|
|
item = {
|
|
id: 'synthetic',
|
|
version_id: 'synthetic-version',
|
|
version: 1,
|
|
payload: p,
|
|
};
|
|
const index = renderToStaticMarkup(
|
|
React.createElement(Index, {
|
|
items: { data: [item], links: [] },
|
|
filters: {},
|
|
kinds: {},
|
|
options: { territories: [], sectors: [] },
|
|
management: false,
|
|
}),
|
|
);
|
|
const detail = renderToStaticMarkup(
|
|
React.createElement(Show, {
|
|
record: item,
|
|
authenticated: false,
|
|
saved: null,
|
|
}),
|
|
);
|
|
for (const html of [index, detail]) {
|
|
assert.doesNotMatch(
|
|
html,
|
|
/ficha|documento fornecido|SHA-256|linha de origem|Instituições financeiras em Moçambique\.docx/i,
|
|
);
|
|
assert.match(html, /Produtos e serviços/);
|
|
assert.match(
|
|
html,
|
|
new RegExp(raw.title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')),
|
|
);
|
|
}
|
|
const out = new URL(
|
|
'../../outputs/funding-public-editorial-20261111/',
|
|
import.meta.url,
|
|
);
|
|
fs.mkdirSync(out, { recursive: true });
|
|
const name = p.products.length
|
|
? 'bank-with-products'
|
|
: 'investment-manager';
|
|
fs.writeFileSync(new URL(name + '-index.html', out), index);
|
|
fs.writeFileSync(new URL(name + '-detail.html', out), detail);
|
|
fs.writeFileSync(
|
|
new URL('verification.json', out),
|
|
JSON.stringify(
|
|
{
|
|
publishedSourceRecords: 270,
|
|
descriptionsPreserved: true,
|
|
productsNotFabricated: true,
|
|
actualPublicComponents: true,
|
|
metadataRemovedFromPresentation: true,
|
|
privateEditorialFieldsUnchanged: true,
|
|
activeDataWrites: 0,
|
|
visualBrowserReview: false,
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
);
|
|
assert.match(detail, /Descrição/);
|
|
if (p.products.length) assert.match(detail, /Soluções PME/);
|
|
}
|
|
});
|
|
|
|
test('Quorus and Moza use one shared clean profile in both list and detail', () => {
|
|
const Index = load('pages/funding/index.tsx').default,
|
|
Show = load('pages/funding/show.tsx').default;
|
|
const out = new URL(
|
|
'../../outputs/funding-uniform-menu-20261111/',
|
|
import.meta.url,
|
|
);
|
|
fs.mkdirSync(out, { recursive: true });
|
|
for (const title of ['Quorus', 'Moza Banco']) {
|
|
const raw = records.find((p) => p.title === title);
|
|
assert.ok(raw, title);
|
|
const p = { ...raw, windows: [], documents: [] },
|
|
item = {
|
|
id: 'synthetic',
|
|
version_id: 'synthetic-version',
|
|
version: 1,
|
|
payload: p,
|
|
};
|
|
const index = renderToStaticMarkup(
|
|
React.createElement(Index, {
|
|
items: { data: [item], links: [] },
|
|
filters: {},
|
|
kinds: {},
|
|
options: { territories: [], sectors: [] },
|
|
management: false,
|
|
}),
|
|
);
|
|
const detail = renderToStaticMarkup(
|
|
React.createElement(Show, {
|
|
record: item,
|
|
authenticated: false,
|
|
saved: null,
|
|
}),
|
|
);
|
|
for (const html of [
|
|
index.match(/<article class="card">([\s\S]*?)<\/article>/)?.[0] ??
|
|
index,
|
|
detail,
|
|
]) {
|
|
assert.doesNotMatch(
|
|
html,
|
|
/Por confirmar|por confirmar|correspondência confirmada|Instituição identificada|Entidade responsável|Sectores:|Cobertura|garantia de financiamento|Não encontrado|ficha|Sede ou contacto indicado|Informação institucional/,
|
|
);
|
|
assert.equal((html.match(/Produtos e serviços/g) || []).length, 1);
|
|
assert.equal((html.match(/Descrição/g) || []).length, 1);
|
|
}
|
|
if (title === 'Quorus') {
|
|
assert.equal(
|
|
(detail.match(/Entidade de corretagem de seguros/g) || [])
|
|
.length,
|
|
1,
|
|
);
|
|
assert.doesNotMatch(
|
|
detail,
|
|
/<h3[^>]*>Contactos|<h3[^>]*>Localização/,
|
|
);
|
|
} else {
|
|
assert.equal((detail.match(/21 342 000/g) || []).length, 1);
|
|
assert.equal(
|
|
(detail.match(/Rua dos Desportistas/g) || []).length,
|
|
1,
|
|
);
|
|
assert.equal(
|
|
(
|
|
detail.match(
|
|
/Tesouraria, investimento, construção e equipamento/g,
|
|
) || []
|
|
).length,
|
|
1,
|
|
);
|
|
assert.doesNotMatch(detail, /500\.000|30\.000\.000|Prime|spread/);
|
|
}
|
|
fs.writeFileSync(
|
|
new URL(title.replaceAll(' ', '-') + '-index.html', out),
|
|
index,
|
|
);
|
|
fs.writeFileSync(
|
|
new URL(title.replaceAll(' ', '-') + '-detail.html', out),
|
|
detail,
|
|
);
|
|
}
|
|
});
|
|
test('contact and location deduplication preserves different branches and original records', () => {
|
|
const moza = records.find((p) => p.title === 'Moza Banco'),
|
|
original = JSON.stringify(moza);
|
|
assert.equal(
|
|
presentation
|
|
.publicInstitutionContacts(moza.contacts)
|
|
.filter((c) => c.kind === 'phone').length,
|
|
1,
|
|
);
|
|
assert.equal(
|
|
presentation.publicInstitutionLocations(moza.locations).length,
|
|
1,
|
|
);
|
|
assert.equal(
|
|
presentation.publicInstitutionLocations([
|
|
...moza.locations,
|
|
{
|
|
...moza.locations[0],
|
|
role: 'branch',
|
|
address: 'Rua dos Desportistas, número 714',
|
|
},
|
|
]).length,
|
|
2,
|
|
);
|
|
assert.equal(JSON.stringify(moza), original);
|
|
});
|