Files
Investidor-V2/tests/frontend/desk-service-history.test.mjs
T
2026-11-02 20:31:15 +02:00

187 lines
5.9 KiB
JavaScript

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 { renderToStaticMarkup } from 'react-dom/server';
import ts from 'typescript';
const require = createRequire(import.meta.url);
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() {
const values = [],
requests = [];
let cursor = 0,
effect;
const hooks = {
useState(initial) {
const index = cursor++;
if (!(index in values)) values[index] = initial;
return [
values[index],
(value) => {
values[index] =
typeof value === 'function'
? value(values[index])
: value;
},
];
},
useEffect(callback) {
effect = callback;
},
};
const output = ts.transpileModule(
fs.readFileSync(
new URL(
'../../resources/js/components/desk-service-history.tsx',
import.meta.url,
),
'utf8',
),
{
compilerOptions: {
module: ts.ModuleKind.CommonJS,
target: ts.ScriptTarget.ES2022,
jsx: ts.JsxEmit.ReactJSX,
},
},
).outputText;
const module = { exports: {} };
compileFunction(output, ['require', 'module', 'exports'])(
(name) =>
name === 'react'
? hooks
: name === '@/lib/portal-api'
? {
portalRequest: (url, options) =>
new Promise((resolve, reject) =>
requests.push({
url,
options,
resolve,
reject,
}),
),
}
: require(name),
module,
module.exports,
);
return {
requests,
start: () => effect(),
render(code = 'project-change') {
cursor = 0;
return module.exports.default({
code,
formatField: (field) =>
field.label +
(field.required ? ' — Obrigatório' : ' — Opcional'),
});
},
};
}
const version = {
id: 'v1',
version: 1,
status: 'published',
author_id: 21,
published_by: 22,
published_at: null,
reason: 'Synthetic publication reason',
source: { identifier: 'Synthetic source', edition: 'Synthetic edition' },
definition: {
title: 'Old form',
theme: 'Theme',
profile: 'Investor',
entity: 'Internal team',
stage: 'E10',
result: 'Internal preparation',
fields: {
title: { label: 'Original question', type: 'text', required: true },
},
},
payload: 'PRIVATE-ANSWER',
};
const flush = () => new Promise((resolve) => setImmediate(resolve));
await test('history renders immutable definitions and provenance without applicant answers, then paginates using the same authorised endpoint', async () => {
const h = harness();
h.render();
h.start();
assert.equal(
h.requests[0].url,
'/management/balcao/servicos/project-change/versoes?page=1',
);
h.requests[0].resolve({ page: 1, pages: 2, total: 11, data: [version] });
await flush();
const tree = h.render(),
html = renderToStaticMarkup(tree);
assert.match(html, /Original question — Obrigatório/);
assert.match(html, /Synthetic publication reason/);
assert.match(html, /Synthetic source · Synthetic edition/);
assert.doesNotMatch(html, /PRIVATE-ANSWER|<input|<form|<textarea/);
nodes(tree)
.find(
(node) =>
node.type === 'button' && node.props.children === 'Seguinte',
)
.props.onClick();
assert.match(renderToStaticMarkup(h.render()), /A recuperar/);
h.start();
assert.equal(
h.requests[1].url,
'/management/balcao/servicos/project-change/versoes?page=2',
);
h.requests[1].resolve({
page: 2,
pages: 2,
total: 11,
data: [
{
...version,
id: 'older',
version: 0,
definition: { ...version.definition, title: 'Previous page' },
},
],
});
await flush();
assert.match(renderToStaticMarkup(h.render()), /Previous page/);
});
await test('failed history differs from an empty history and stale service responses never replace the selected service', async () => {
const h = harness();
h.render();
const cleanup = h.start();
cleanup();
h.render('project-follow-up');
h.start();
h.requests[0].resolve({ page: 1, pages: 1, total: 1, data: [version] });
await flush();
assert.doesNotMatch(
renderToStaticMarkup(h.render('project-follow-up')),
/Original question/,
);
h.requests[1].reject(new Error('Network unavailable'));
await flush();
const failed = h.render('project-follow-up');
assert.match(renderToStaticMarkup(failed), /Tentar novamente/);
assert.doesNotMatch(renderToStaticMarkup(failed), /Ainda não existem/);
nodes(failed)
.find((node) => node.type === 'button')
.props.onClick();
h.render('project-follow-up');
h.start();
h.requests[2].resolve({ page: 1, pages: 1, total: 0, data: [] });
await flush();
assert.match(
renderToStaticMarkup(h.render('project-follow-up')),
/Ainda não existem/,
);
});