17 lines
3.4 KiB
JavaScript
17 lines
3.4 KiB
JavaScript
import fs from 'node:fs';import path from 'node:path';import net from 'node:net';import assert from 'node:assert/strict';import {spawn} from 'node:child_process';
|
|
const read=p=>JSON.parse(fs.readFileSync(p,'utf8')),state=read('C:/laragon/data/sgf-tempo/run/modular-regression-current.json'),tag=process.argv[2];if(state.port!==55439||!/^[a-f0-9]{12}$/.test(tag??''))throw Error('Owned fixture required');
|
|
const root=path.join(state.root,'private/ledger-'+tag),output=path.join(root,'sales-readcheck.json'),g=read(path.join(root,'sales-fixture.json'));if(fs.existsSync(output)||!read(path.join(root,'sales-final.json')).passed)throw Error('New read proof over completed latest-schema workflow required');
|
|
await new Promise((resolve,reject)=>{const s=net.createServer();s.once('error',reject);s.listen(8047,'127.0.0.1',()=>s.close(resolve));});const log=fs.openSync(path.join(root,'sales-readcheck-server.log'),'a'),server=spawn('C:/laragon/tools/sgf-tempo/php-8.4.27/php.exe',['-S','127.0.0.1:8047',path.resolve('scripts/ledger-sales-http-router.php')],{windowsHide:true,stdio:['ignore',log,log],env:{...process.env,LEDGER_QA_SETTINGS:path.join(root,'settings.json')}});
|
|
let checks=0;const ok=(v,s)=>{checks++;assert(v,s);},jar=new Map();let token='';
|
|
const get=async(url,headers={})=>{const r=await fetch('http://127.0.0.1:8047'+url,{headers:{Accept:'application/json',Cookie:[...jar].map(([k,v])=>k+'='+v).join('; '),'X-SGF-Context':token,...headers},redirect:'manual',signal:AbortSignal.timeout(10000)});for(const c of r.headers.getSetCookie()){const p=c.split(';')[0],i=p.indexOf('=');jar.set(p.slice(0,i),p.slice(i+1));}const text=await r.text();let data;try{data=JSON.parse(text);}catch{}return{status:r.status,text,data};};
|
|
try{
|
|
let ready=false;for(let n=0;n<40&&!ready;n++){try{ready=(await get('/qa/sales-demo')).status===200;}catch{}if(!ready)await new Promise(r=>setTimeout(r,100));}ok(ready,'Read server ready');
|
|
const auth=await get('/qa/sales-enter/prepare');token=auth.data.context;ok(auth.status===200,'Own QA preparer');
|
|
let r=await get('/api/general-ledger/sales?invoice_id='+g.invoice_id,{'X-Sales-QA-Proof':'read'});ok(r.status===200&&r.data.book.journals.length===4&&r.data.book.lines.length===9&&r.data.commercial.position.balance==='400.00','Latest schema completed state remains readable');
|
|
const mode=read(path.join(root,'sales-http-read.json'));ok(mode.transaction.read_only==='on'&&mode.transaction.isolation==='repeatable read'&&mode.writer_locks===0,'Read coherent and no writer locks');
|
|
r=await get('/general-ledger/sales?invoice_id='+g.invoice_id);ok(r.status===200&&!r.text.includes('data-finance=')&&!r.text.includes('data-ledger='),'Closed workspace hides new command forms');
|
|
r=await get('/general-ledger');ok(r.status===200&&r.text.includes('/general-ledger/sales?invoice_id='+g.invoice_id),'Generic diary renders sales proposal origin');
|
|
for(const query of ['invoice_id=999999','invoice_id=0','invoice_id%5Bx%5D=1','invoice_id='+g.invoice_id+'&company_id=9'])ok([403,422].includes((await get('/api/general-ledger/sales?'+query)).status),'Unknown/invalid/cross-context source refused');
|
|
fs.writeFileSync(output,JSON.stringify({passed:true,checks,latest_schema:true,read_only:true,writer_locks:0,journals:4,lines:9,balance_minor:40000,closed_forms_hidden:true,generic_diary_sales_origin:true,no_business_commands:true,visual_review:false},null,2)+'\n');console.log(JSON.stringify({passed:true,checks,no_business_commands:true}));
|
|
}finally{server.kill();fs.closeSync(log);}
|