15 lines
3.5 KiB
JavaScript
15 lines
3.5 KiB
JavaScript
import fs from 'node:fs';import path from 'node:path';import assert from 'node:assert/strict';
|
|
const read=p=>JSON.parse(fs.readFileSync(p,'utf8')),state=read('C:/laragon/data/sgf-tempo/run/modular-regression-current.json'),mode=process.argv[2],tag=process.argv[3],native=mode==='native';if(state.port!==55439||!['native','sgf'].includes(mode)||!/^[a-f0-9]{12}$/.test(tag??''))throw Error('Owned demo required');
|
|
const root=path.join(state.root,'private/ledger-'+(native?'native-':'')+tag),demo=read(path.join(root,'ledger-demo.json')),f=read(path.join(root,'fixture.json')),g=read(path.join(root,'ledger-fixture.json')),output=path.join(root,'ledger-cycle-demo-http.json');if(fs.existsSync(output)||!g.cycle_enabled)throw Error('Unfinished cycle readiness required');const base=new URL(demo.url).origin;let checks=0;const check=(v,s)=>{checks++;assert(v,s);};let r=await fetch(demo.url);check(r.status===200&&(await r.text()).includes('data-ledger-demo="'+tag+'"'),'Persistent cycle landing ready');
|
|
for(const role of ['prepare','validate','read']){
|
|
const jar=new Map();let auth;const req=async(url,body)=>{const r=await fetch(base+url,{method:body?'POST':'GET',headers:{Accept:'application/json',Cookie:[...jar].map(([k,v])=>k+'='+v).join('; '),'X-SGF-Context':auth?.context??'',...(body?{'Content-Type':'application/json','X-CSRF-TOKEN':auth.csrf}:{})},body:body?JSON.stringify(body):undefined,redirect:'manual'});for(const c of r.headers.getSetCookie()){const p=c.split(';')[0],at=p.indexOf('=');jar.set(p.slice(0,at),p.slice(at+1));}const text=await r.text();let data;try{data=JSON.parse(text);}catch{}return{status:r.status,data,text};};
|
|
r=await req('/qa/ledger-enter/'+role);check(r.status===200,'Own synthetic '+role);auth=r.data;check(jar.has(demo.cookie)&&!jar.has('XSRF-TOKEN'),'Isolated cookie');
|
|
r=await req('/api/general-ledger/cycle');check(r.status===200&&r.data.book.journals.length===0&&r.data.book.proposals.length===0&&r.data.allocations.length===0&&r.data.reversals.length===0&&r.data.period_closures.length===0&&r.data.periods.length===1,'Initial cycle has no effects or close');check(r.data.obligations.length===1&&r.data.obligations[0].principal_minor===6000,'Exactly one recognised obligation60');
|
|
r=await req('/general-ledger/cycle');check(r.status===200&&r.text.includes('ciclo contabilístico QA')&&r.text.includes('Conferência e fecho do período QA'),'Common workspace rendered');check(role==='prepare'?r.text.includes('data-action='):!r.text.includes('data-action='),'Role-specific forms');
|
|
if(!native){r=await req('/api/context',{...f.scope,module_id:'purchasing'});check(r.status===200,'Existing explicit financial context selection');auth={csrf:r.data.csrf,context:r.data.context.token};}
|
|
r=await req('/supplier-payments');check(r.status===200&&r.text.includes('ledger_cycle_url'),'Return link from finance to accounting composed');
|
|
r=await req('/api/supplier-payables?'+(native?'invoice=':'source=')+g.local_source_id);check(r.status===200&&r.data.obligations.length===1&&r.data.obligations[0].balance_minor===6000,'Financial principal and balance untouched');
|
|
if(native)check(r.data.documents[0].issued_on==='2026-10-29','Explicit synthetic fixture date belongs to QA period');
|
|
}
|
|
fs.writeFileSync(output,JSON.stringify({passed:true,checks,composition:mode,url:demo.url,tag,three_roles:true,no_business_commands:true,initial_principal_minor:6000,initial_balance_minor:6000,initial_journals:0,initial_payment_effects:0,financial_return_link:true,own_cookie:true,visual_review:false},null,2)+'\n');console.log(JSON.stringify({passed:true,checks,composition:mode,url:demo.url}));
|