316 lines
13 KiB
JavaScript
316 lines
13 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
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, errors: {}, 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")
|
|
: resolveLocal(name, file),
|
|
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);
|
|
});
|
|
|
|
function resolveLocal(name, parent) {
|
|
if (name === "./territory-geometry-preview") return { default: () => null };
|
|
const relative = name.startsWith("@/")
|
|
? name.slice(2)
|
|
: name.startsWith(".")
|
|
? path.posix.join(path.posix.dirname(parent), name)
|
|
: 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);
|
|
}
|
|
return require(name);
|
|
}
|
|
|
|
test("physical presence matches descendants, not a broader province or unknown locations", () => {
|
|
const points = [
|
|
{
|
|
territory_id: "district-a",
|
|
territory_path: [
|
|
{ id: "province", name: "Province" },
|
|
{ id: "district-a", name: "A" },
|
|
],
|
|
evidence_status: "reported",
|
|
},
|
|
{
|
|
territory_id: "province",
|
|
territory_path: [{ id: "province", name: "Province" }],
|
|
evidence_status: "reported",
|
|
},
|
|
{ territory_id: "district-a", evidence_status: "to_confirm" },
|
|
{ territory_id: "district-a", evidence_status: "historical" },
|
|
{ territory_id: "" },
|
|
];
|
|
assert.deepEqual(presentation.matchingInstitutionLocations(points, "district-a"), [points[0]]);
|
|
assert.deepEqual(
|
|
presentation.matchingInstitutionLocations(points, "province"),
|
|
points.slice(0, 2),
|
|
);
|
|
assert.deepEqual(presentation.matchingInstitutionLocations(points, "elsewhere"), []);
|
|
});
|
|
test("compact institutions show local address and explicitly identify unconfirmed physical presence", () => {
|
|
const { InstitutionView } = load("components/funding-institution.tsx");
|
|
const value = {
|
|
...records[0],
|
|
locations: [
|
|
{
|
|
role: "branch",
|
|
address: "Balcão de Tete",
|
|
territory_id: "tete",
|
|
territory_path: [{ id: "tete", name: "Tete" }],
|
|
},
|
|
{ role: "headquarters", address: "Sede Maputo", territory_id: "maputo" },
|
|
],
|
|
};
|
|
const render = (territory, compact = true) =>
|
|
renderToStaticMarkup(
|
|
React.createElement(InstitutionView, { value, compact, physicalTerritory: territory }),
|
|
);
|
|
assert.match(render("tete"), /Balcão de Tete/);
|
|
assert.doesNotMatch(render("tete"), /Sede Maputo|Presença física por confirmar/);
|
|
assert.match(render("niassa"), /Presença física por confirmar no local escolhido/);
|
|
assert.doesNotMatch(render("niassa"), /Balcão de Tete|Sede Maputo/);
|
|
assert.match(render("tete", false), /Sede Maputo/);
|
|
assert.match(render("tete", false), /Balcão de Tete/);
|
|
});
|