209 lines
7.4 KiB
JavaScript
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/);
|
|
});
|