Files
Investidor-V2/tests/frontend/funding-public-presentation.test.mjs
T

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/);
});