11 lines
7.6 KiB
JavaScript
11 lines
7.6 KiB
JavaScript
import fs from 'node:fs';import assert from 'node:assert/strict';import {pathToFileURL} from 'node:url';import {transformWithOxc} from 'vite';import {checkedObligations,obligationsPageCsv} from '../resources/js/fiscal-obligations-view.js';
|
|
const base=JSON.parse(fs.readFileSync('C:/laragon/data/sgf-tempo/run/modular-regression-current.json')).root+'/private',root=base+'/receipt-composition-cc50a276c10c',sample=JSON.parse(fs.readFileSync(base+'/receipt-composition-b4093c6f6707/fiscal-obligations-sample-private.json')),checks=[],ok=(v,n)=>{assert(v,n);checks.push(n);};
|
|
let slots=[],cursor=0,effects=[],tree,props,calls=[],next=structuredClone(sample),uncertain=true;const same=(a,b)=>a&&b&&a.length===b.length&&a.every((v,i)=>v===b[i]);const R={createElement:(type,props,...children)=>({type,props:props??{},children}),Fragment:Symbol('fragment'),useRef(value){const i=cursor++;slots[i]??={current:value};return slots[i];},useState(initial){const i=cursor++;slots[i]??={value:initial};return[slots[i].value,v=>{slots[i].value=typeof v==='function'?v(slots[i].value):v;}];},useMemo(fn,deps){const i=cursor++;if(!same(slots[i]?.deps,deps))slots[i]={value:fn(),deps};return slots[i].value;},useEffect(fn,deps){const i=cursor++;if(!same(slots[i]?.deps,deps)){slots[i]?.cleanup?.();slots[i]={deps};effects.push(()=>slots[i].cleanup=fn());}}};globalThis.__foHooks=R;const stub='const r=globalThis.__foHooks;export default r;export const useState=r.useState,useMemo=r.useMemo,useEffect=r.useEffect,useRef=r.useRef;',stubUrl='data:text/javascript;base64,'+Buffer.from(stub).toString('base64');let source=fs.readFileSync('resources/js/FiscalObligationsWorkspace.jsx','utf8').replace("from 'react'",'from '+JSON.stringify(stubUrl));for(const f of ['statement-download.js','workshop-stock-operation.js','fiscal-obligations-view.js'])source=source.replace("from './"+f+"'",'from '+JSON.stringify(pathToFileURL(process.cwd()+'/resources/js/'+f).href));const c=await transformWithOxc(source,'FiscalObligationsWorkspace.jsx',{jsx:{runtime:'classic'}}),{default:Workspace,FiscalObligationRows}=await import('data:text/javascript;base64,'+Buffer.from(c.code).toString('base64'));
|
|
const api=async(path,method='GET',body,token,key)=>{calls.push({path,method,body:structuredClone(body),key});if(path.endsWith('/preview'))return{preview:'encrypted-qa-cut',impact:{before:{version:0,effective:null},after:{version:1,state:'prepared',proposal:body.data,effective:null},tax_payable:null,payments:0,journals:0}};if(path.endsWith('/confirm')){if(uncertain){uncertain=false;const e=Error('QA response lost');e.status=503;throw e;}return{id:123,version:1,state:'prepared',replayed:true};}return structuredClone(next);};props={context:{token:'fo-qa-generation'},api};const render=()=>{cursor=0;tree=Workspace(props);const jobs=effects;effects=[];jobs.forEach(f=>f());return tree;},tick=async()=>{await new Promise(r=>setTimeout(r,0));render();};const descend=n=>Array.isArray(n)?n.flatMap(descend):n&&typeof n==='object'?[n,...descend(n.children)]:[],nodes=(n=tree)=>descend(n),text=n=>Array.isArray(n)?n.map(text).join(''):n&&typeof n==='object'?text(typeof n.type==='function'?n.type(n.props):n.children):String(n??''),find=(tag,label)=>nodes().find(n=>n.type===tag&&text(n).includes(label)),click=label=>{const b=find('button',label);assert(b,label);assert(!b.props.disabled,label+' disabled');b.props.onClick();render();};
|
|
render();ok(calls.length===0,'no implicit reference query');ok(nodes().some(n=>n.type==='input'&&n.props.type==='date'&&n.props.required&&n.props.value===''),'reference explicitly required');nodes().find(n=>n.type==='input'&&n.props.type==='date').props.onChange({target:{value:'2026-12-15'}});render();find('form','Consultar').props.onSubmit({preventDefault(){}});render();await tick();ok(calls[0].path.includes('reference_on=2026-12-15'),'chosen reference sent');ok(text(tree).includes('Sem prazo legal')&&text(tree).includes('entrega apenas simulada'),'no legal or delivery claim');
|
|
// Select an existing cancelled record, then choose NEW: it must not reuse that identity.
|
|
const existing=sample.records.data[0];const rows=FiscalObligationRows({data:sample,onSelect:r=>{const component=nodes().find(n=>n.type===FiscalObligationRows);component.props.onSelect(r);},disabled:false});const button=nodes(rows).find(n=>n.type==='button');button.props.onClick();render();ok(text(tree).includes('Impacto registado nesta versão'),'selected history shows recorded before after');click('Nova obrigação deste mapa');const operationForm=find('form','Conferir impacto');ok(operationForm&&find('fieldset','Conferir impacto'),'new form opens');ok(nodes().some(n=>n.type==='select'&&n.props.required&&n.props.value===''),'responsible never automatically chosen');ok(!text(operationForm).includes(existing.record_key),'new operation does not reuse selected record key');ok(find('fieldset','Referência para atraso').props.disabled,'editing locks filters');ok(nodes().filter(n=>n.type==='textarea').every(n=>n.props.value===''),'evidence and reason not copied');
|
|
const responsible=nodes().find(n=>n.type==='select'&&n.props.required);responsible.props.onChange({target:{value:'13'}});render();nodes().find(n=>n.type==='input'&&n.props.type==='checkbox').props.onChange({target:{checked:true}});render();let areas=nodes().filter(n=>n.type==='textarea');areas[0].props.onChange({target:{value:'QA artificial individual evidence.'}});render();areas=nodes().filter(n=>n.type==='textarea');areas[1].props.onChange({target:{value:'QA individual reason, not prior reason.'}});render();await find('form','Conferir impacto').props.onSubmit({preventDefault(){}});render();const prepared=calls.find(x=>x.path.endsWith('/preview'));ok(prepared.body.data.due_on===null&&prepared.body.data.responsible_id===13,'explicit unknown and selected responsible sent');ok(prepared.body.record_key!==existing.record_key&&prepared.body.version===0,'new key and zero version after old selection');ok(text(tree).includes('Impacto antes da confirmação')&&text(tree).includes('Zero dívida/pagamentos/lançamentos'),'impact before confirmation visible');click('Confirmar esta decisão individual');await tick();ok(text(tree).includes('Resultado incerto'),'uncertain result preserved');ok(find('button','Descartar formulário').props.disabled,'uncertain decision cannot be discarded');click('Recuperar a mesma confirmação');await tick();const sent=calls.filter(x=>x.path.endsWith('/confirm'));ok(sent.length===2&&JSON.stringify(sent[0])===JSON.stringify(sent[1]),'retry retains identical body and key');ok(text(tree).includes('recibo recuperado'),'recovery acknowledged');
|
|
const query={reference_on:sample.reference_on,page:1,per_page:25};ok(checkedObligations(sample,query)===sample,'actual regression sample contract');const changed={...sample,reference_on:'2026-12-16'};assert.throws(()=>checkedObligations(changed,query));ok(true,'late reference rejected');const csv=obligationsPageCsv(sample,query);ok(csv.includes('APENAS ESTA PAGINA')&&csv.includes('SEM PRAZO LEGAL OU SUBMISSAO'),'CSV page and synthetic scope');const dangerous=structuredClone(sample);dangerous.records.data[0].reason=' =FORMULA()';ok(obligationsPageCsv(dangerous,query).includes("' =FORMULA()"),'CSV reason formula escaped');const unknown=structuredClone(sample);unknown.records.data[0].days_overdue=null;unknown.records.data[0].effective=null;ok(text(FiscalObligationRows({data:unknown})).includes('Atraso indeterminado'),'unknown delay not zero');
|
|
const file=root+'/fiscal-obligations-ui-20261110.json';fs.writeFileSync(file,JSON.stringify({passed:true,checks,actual_component_handlers:true,api_mocked:true,browser_visual_review:false,business_commands:0},null,2));console.log(JSON.stringify({passed:true,checks:checks.length,proof:file}));
|