47 lines
4.2 KiB
JavaScript
47 lines
4.2 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import { compileFunction } from 'node:vm';
|
|
import { createRequire } from 'node:module';
|
|
import React from 'react';
|
|
import ts from 'typescript';
|
|
import * as finance from '../../resources/js/lib/financial-calculators.ts';
|
|
import * as contract from '../../resources/js/lib/simulation-contract.ts';
|
|
import * as fundingContext from '../../resources/js/lib/planning-finance-context.ts';
|
|
const require = createRequire(import.meta.url);
|
|
const nodes = tree => Array.isArray(tree) ? tree.flatMap(nodes) : tree && typeof tree === 'object' ? [tree, ...nodes(tree.props?.children)] : [];
|
|
const text = tree => Array.isArray(tree) ? tree.map(text).join('') : tree?.props ? text(tree.props.children) : typeof tree === 'string' ? tree : '';
|
|
function harness(snapshot = '') {
|
|
let cursor=0, queue=[], dirty=false, tree;
|
|
const memory=[], deps=[];
|
|
const hooks={...React, useState(initial) {const id=cursor++;if(!(id in memory))memory[id]=typeof initial==='function'?initial():initial;return[memory[id],next=>{const value=typeof next==='function'?next(memory[id]):next;if(!Object.is(value,memory[id])){memory[id]=value;dirty=true;}}];},useEffect(effect, next) {const id=cursor++;if(!deps[id]||next.some((value,i)=>!Object.is(value,deps[id][i]))){queue.push(effect);deps[id]=next;}}};
|
|
const module={exports:{}};
|
|
compileFunction(ts.transpileModule(fs.readFileSync('resources/js/components/simulation-financial-tools.tsx','utf8'),{compilerOptions:{module:ts.ModuleKind.CommonJS,jsx:ts.JsxEmit.ReactJSX}}).outputText,['require','module','exports'])(id=>id==='react'?hooks:id==='@/components/currency-select'?{default:()=>null}:id==='@/lib/financial-calculators'?finance:id==='@/lib/simulation-contract'?contract:id==='@/lib/planning-finance-context'?fundingContext:require(id),module,module.exports);
|
|
const props={currency:'MZN',focus:'funding',loanRelevant:false,snapshot,sourceFunding:{total:'2000000',secured:''},onSnapshotChange(value){props.snapshot=value;dirty=true;},onCurrencyChange(){},onFundingChange(key,value){props.sourceFunding={...props.sourceFunding,[key]:value};dirty=true;}};
|
|
const render=()=>{for(let i=0;i<12;i++){cursor=0;queue=[];dirty=false;tree=module.exports.SimulationFinancialTools(props);for(const effect of queue)effect();if(!dirty)return;}throw new Error('Render did not settle');};
|
|
render();
|
|
return{props,render,text:()=>text(tree),field:label=>nodes(tree).find(node=>node.props?.label===label),button:label=>nodes(tree).find(node=>node.type==='button'&&text(node).startsWith(label))};
|
|
}
|
|
|
|
test('editing canonical mobilised funding updates the attached calculator and snapshot without showing hidden-tool errors',()=>{
|
|
const h=harness();
|
|
h.props.sourceFunding={total:'2000000',secured:'1000000'};h.render();
|
|
assert.equal(h.field('Montante já mobilizado').props.value,'1000000');
|
|
assert.match(h.text(),/1000000.00/);
|
|
assert.equal(finance.restoreFinancialToolsSnapshot(h.props.snapshot).funding.secured,'1000000');
|
|
assert.doesNotMatch(h.text(),/Empréstimo:|Ponto de equilíbrio:|Orçamento:|valores da calculadora diferem/);
|
|
assert.equal(h.button('Exportar resultados'),undefined);
|
|
});
|
|
|
|
test('a known different recovered calculator value is preserved until the user resolves its source',()=>{
|
|
const snapshot=finance.serializeFinancialToolsSnapshot({budgetPeriod:'Mensal',loan:{principal:'',rate:'',months:'',rateType:'nominal',periodMonths:'1',gracePeriods:'',upfrontFee:'',recurringFee:''},breakEven:{fixed:'',price:'',variable:''},funding:{total:'2000000',secured:'250000'},incomes:[{label:'Receitas',amount:''}],expenses:[{label:'Custos',amount:''}]});
|
|
const h=harness(snapshot);h.props.sourceFunding={total:'2000000',secured:'1000000'};h.render();
|
|
assert.equal(h.field('Montante já mobilizado').props.value,'250000');
|
|
assert.match(h.text(),/valores da calculadora diferem/);
|
|
h.button('Usar os valores do investimento').props.onClick();h.render();
|
|
assert.equal(h.field('Montante já mobilizado').props.value,'1000000');
|
|
h.props.sourceFunding={total:'2000000',secured:'1500000'};h.render();
|
|
assert.equal(h.field('Montante já mobilizado').props.value,'1500000');
|
|
assert.match(h.text(),/500000.00/);
|
|
});
|