Files
Investidor-V2/tests/frontend/desk-request-conditions.test.mjs
T

209 lines
7.4 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 { createElement } from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import ts from 'typescript';
const require = createRequire(import.meta.url);
function load(file, overrides = {}) {
const output = 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(output, ['require', 'module', 'exports'])(
(name) => overrides[name] ?? require(name),
module,
module.exports,
);
return module.exports;
}
function render(payload, extra = {}) {
const empty = () => null;
const page = load('../../resources/js/pages/desk/request.tsx', {
'@inertiajs/react': {
Link: ({ href, children }) =>
createElement('a', { href }, children),
useForm: (data) => ({ data, errors: {}, processing: false }),
},
'@/lib/operation-key': { createOperationKey: () => 'synthetic-key' },
'@/lib/desk-field-visibility': load(
'../../resources/js/lib/desk-field-visibility.ts',
),
'@/lib/desk-field-values': load(
'../../resources/js/lib/desk-field-values.ts',
),
'@/components/desk-typed-choice': load(
'../../resources/js/components/desk-typed-choice.tsx',
{
'@/lib/desk-field-values': load(
'../../resources/js/lib/desk-field-values.ts',
),
},
),
'@/components/dossier-prefill': { DossierPrefill: empty },
'@/components/desk-draft-recovery': {
__esModule: true,
default: empty,
},
'@/components/country-select': { __esModule: true, default: empty },
'@/components/desk-attachment-field': {
__esModule: true,
default: empty,
},
'@/components/investment-territory': { TerritoryFields: empty },
'@/components/desk-internal-operations': {
DocumentReview: empty,
RequestOperations: ({ owner, reviewer, payments }) =>
createElement(
'section',
{
'data-test': 'manual-operations',
'data-writable': owner || reviewer ? 'yes' : 'no',
},
payments.map((payment) => payment.reference).join(', '),
),
},
'@/pages/investment/shared': {
Frame: ({ children }) => createElement('main', null, children),
card: '',
input: '',
button: '',
},
}).default;
return renderToStaticMarkup(
createElement(page, {
request: {
id: 'synthetic-request',
version: 1,
status: 'draft',
payload,
protocol: null,
editable_fields: [],
analyst_id: null,
due_at: null,
},
case: { id: 'synthetic-case', title: 'Synthetic dossier' },
definition: {
title: 'Synthetic form',
result: 'Synthetic result',
fields: {
detail: {
label: 'Deep detail',
type: 'text',
required: true,
when: { field: 'branch', equals: '1' },
},
branch: {
label: 'Branch question',
type: 'select',
required: true,
options: { 0: 'No', 1: 'Yes' },
when: { field: 'root', equals: '1' },
},
root: {
label: 'Root question',
type: 'select',
required: true,
options: { 0: 'No', 1: 'Yes' },
},
},
},
owner: true,
manager: false,
analyst: false,
fieldsEditable: true,
states: { draft: 'Draft' },
transitions: [],
findings: [],
messages: [],
analysts: [],
territoryPaths: {},
events: [],
documents: [],
payments: [],
caseVersion: 1,
countries: [],
toolPrefill: null,
...extra,
}),
);
}
await test('manual payment history remains visible with operations disabled and legacy draft props still render', () => {
const readonly = render(
{},
{
operationsEditable: false,
payments: [{ reference: 'SYNTHETIC historical payment' }],
},
);
assert.match(readonly, /SYNTHETIC historical payment/);
assert.match(readonly, /data-writable="no"/);
const legacy = render(
{},
{ payments: [{ reference: 'SYNTHETIC legacy draft' }] },
);
assert.match(legacy, /SYNTHETIC legacy draft/);
assert.match(legacy, /data-writable="yes"/);
});
await test('hidden parent answers never reveal nested questions, while reopening the branch restores their answers', () => {
const payload = { root: '0', branch: '1', detail: 'Preserved detail' };
const hidden = render(payload);
assert.ok(hidden.includes('Root question'));
assert.ok(!hidden.includes('Branch question'));
assert.ok(!hidden.includes('Deep detail'));
assert.ok(!hidden.includes('Preserved detail'));
const visible = render({ ...payload, root: '1' });
assert.ok(visible.includes('Branch question'));
assert.ok(visible.includes('Deep detail'));
assert.ok(visible.includes('Preserved detail'));
assert.deepEqual(payload, {
root: '0',
branch: '1',
detail: 'Preserved detail',
});
});
await test('return category is optional and comes from the server, while historical labels retain their snapshot', () => {
const props = {
owner: false,
manager: true,
fieldsEditable: false,
transitions: ['returned'],
returnReasons: {
unspecified: 'SYNTHETIC unclassified',
missing_documents: 'SYNTHETIC configured category',
},
events: [
{
id: 'event',
action: 'request_returned',
name: 'SYNTHETIC actor',
created_at: '2026-11-02T10:00:00Z',
payload: { return_reason_label: 'SYNTHETIC historical label' },
},
],
};
const returned = render({}, props);
assert.match(
returned,
/Categoria do motivo \(opcional, para indicadores\)/,
);
assert.match(returned, /SYNTHETIC configured category/);
assert.match(returned, /Categoria:.*SYNTHETIC historical label/);
assert.doesNotMatch(returned, /<select[^>]*required/);
const other = render({}, { ...props, transitions: ['reviewing'] });
assert.doesNotMatch(other, /SYNTHETIC configured category/);
assert.match(other, /SYNTHETIC historical label/);
});