import assert from 'node:assert/strict'; import test from 'node:test'; import fs from 'node:fs'; import { compileFunction } from 'node:vm'; import { createRequire } from 'node:module'; import ts from 'typescript'; import React from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; const require = createRequire(import.meta.url); function source(name) { return fs.readFileSync( new URL('../../resources/js/pages/investment/' + name, import.meta.url), 'utf8', ); } function compile(source) { const output = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022, jsx: ts.JsxEmit.ReactJSX, }, }).outputText; const module = { exports: {} }; compileFunction(output, ['require', 'module', 'exports'])( require, module, module.exports, ); return module.exports; } const shared = ts.createSourceFile( 'shared.tsx', source('shared.tsx'), ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX, ); const apiNode = shared.statements.find( (node) => ts.isFunctionDeclaration(node) && node.name?.text === 'api', ); const { api } = compile(apiNode.getText(shared)); await test('API preserves JSON validation messages and handles empty and non-JSON responses', async () => { const originalFetch = globalThis.fetch; try { globalThis.fetch = async () => new Response(JSON.stringify({ message: 'Campo obrigatorio' }), { status: 422, }); await assert.rejects(api('/synthetic'), /Campo obrigatorio/); globalThis.fetch = async () => new Response('proxy error', { status: 502 }); await assert.rejects(api('/synthetic'), /concluir a opera/); globalThis.fetch = async () => new Response('expired', { status: 419 }); await assert.rejects(api('/synthetic'), /sess.*expirou/); globalThis.fetch = async () => new Response('', { status: 200 }); await assert.rejects(api('/synthetic'), /concluir a opera/); globalThis.fetch = async () => new Response(null, { status: 204 }); assert.equal(await api('/synthetic'), null); } finally { globalThis.fetch = originalFetch; } }); await test('public GET ignores malformed CSRF cookie; writes preserve CSRF and multipart transport', async () => { const originalFetch = globalThis.fetch; const originalDocument = Object.getOwnPropertyDescriptor( globalThis, 'document', ); let request; try { Object.defineProperty(globalThis, 'document', { value: { cookie: 'XSRF-TOKEN=%broken' }, configurable: true, }); globalThis.fetch = async (url, options) => { request = options; return new Response('{"ok":true}'); }; assert.deepEqual(await api('/synthetic'), { ok: true }); await assert.rejects(api('/synthetic', {}), /validada/); globalThis.document.cookie = 'XSRF-TOKEN=synthetic%3D'; const body = new FormData(); body.set('name', 'synthetic'); await api('/synthetic', body); assert.equal(request.method, 'POST'); assert.equal(request.credentials, 'same-origin'); assert.equal(request.headers['X-XSRF-TOKEN'], 'synthetic='); assert.equal(request.headers['Content-Type'], undefined); assert.equal(request.body, body); } finally { globalThis.fetch = originalFetch; if (originalDocument) Object.defineProperty(globalThis, 'document', originalDocument); else delete globalThis.document; } }); await test('catalogue pagination exposes applied links only after a successful search', () => { const file = ts.createSourceFile( 'catalogue.tsx', source('catalogue.tsx'), ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX, ); let nav; function visit(node) { if ( ts.isJsxElement(node) && node.openingElement.tagName.getText(file) === 'nav' && node.getText(file).includes('results.prev_page_url') ) nav = node; ts.forEachChild(node, visit); } visit(file); assert.ok(nav); const { Pagination } = compile( `const Link='a'; export function Pagination({searchLoading,searchError,results,view}) {return (${nav.getText(file)});}`, ); const props = { view: 'list', results: { prev_page_url: '/previous?page=1', next_page_url: '/previous?page=3', }, }; for (const state of [ { searchLoading: true, searchError: '' }, { searchLoading: false, searchError: 'failure' }, ]) { const html = renderToStaticMarkup( React.createElement(Pagination, { ...props, ...state }), ); assert.doesNotMatch(html, /href=/); } const html = renderToStaticMarkup( React.createElement(Pagination, { ...props, searchLoading: false, searchError: '', }), ); assert.match(html, /href="\/previous\?page=1"/); assert.match(html, /href="\/previous\?page=3"/); });