Files
SGF/scripts/purchasing-completion-read.mjs
2026-11-04 09:37:20 +02:00

25 lines
5.7 KiB
JavaScript

import fs from 'node:fs';import path from 'node:path';import assert from 'node:assert/strict';
import {parsePage,installDom,walk} from './purchasing-workspace-dom.mjs';
const run=JSON.parse(fs.readFileSync('C:/laragon/data/sgf-tempo/run/modular-regression-current.json')),root=path.join(run.root,'private/receipt-composition-cc50a276c10c'),source=JSON.parse(fs.readFileSync(path.join(root,'completion-flow-result.json'))),ids=source.source_ids,base='http://127.0.0.1:8085',out=path.join(root,'completion-read-result.json');assert(source.passed&&!fs.existsSync(out));
const originalFetch=globalThis.fetch,cookies=new Map,checks=[],calls=[];let pending=0,document;const ok=(v,name)=>{assert(v,name);checks.push(name);};
async function raw(url,options={}){const h=new Headers(options.headers);h.set('Cookie',[...cookies].map(([k,v])=>k+'='+v).join('; '));const r=await originalFetch(base+url,{...options,headers:h,redirect:'manual'});for(const cookie of r.headers.getSetCookie()){const p=cookie.split(';')[0],i=p.indexOf('=');cookies.set(p.slice(0,i),p.slice(i+1));}return r;}
globalThis.fetch=async(url,options={})=>{assert((options.method??'GET')==='GET','This verification never repeats a business command');pending++;try{const r=await raw(url,options);calls.push({url,status:r.status,data:await r.clone().json()});return r;}finally{pending--;}};
const delay=ms=>new Promise(resolve=>setTimeout(resolve,ms));async function settle(){for(let i=0;i<2000;i++){if(pending===0){await delay(30);if(!pending)return;}await delay(20);}throw Error('Read did not settle');}
async function login(role,stage,query=''){
const entry=await raw('/compras'),html=await entry.text(),token=/name="_token" value="([^"]+)"/.exec(html)?.[1];assert(token);const r=await raw('/compras/entrar',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:new URLSearchParams({_token:token,role,stage,...(query?{return_to:'/purchasing/'+stage+query}:{})})});assert.equal(r.status,302);return {location:r.headers.get('location'),token};
}
try{
const cases=[['actor','suppliers','supplier-workspace','suppliers','?supplier='+ids.supplier],['requester','requests','request-workspace','requests','?request='+ids.request],['actor','sourcing','sourcing-workspace','sourcing','?request='+ids.request],['actor','orders','order-workspace','orders-workspace','?award='+ids.award],['validator','receipts','receipt-workspace','receipts','?order='+ids.order+'&receipt='+ids.receipt],['issuer','invoices','supplier-invoice-workspace','supplier-invoices','?order='+ids.order+'&invoice='+ids.invoice],['reviewer','obligations','supplier-obligation-workspace','supplier-obligations','?invoice='+ids.invoice]];
for(const [role,stage,file,id,query]of cases){await settle();if(document)for(const e of walk(document.root))e.isConnected=false;await login(role,stage,query);const r=await raw('/purchasing/'+stage+query),html=await r.text();assert.equal(r.status,200);document=parsePage(html);installDom(document);globalThis.location={search:query};globalThis.history={replaceState:(_,__,href)=>{globalThis.location.search=href.slice(href.indexOf('?'));}};const before=calls.length;await import('../public/'+file+'.mjs?completed-read='+stage);await settle();const entry=document.querySelector('[data-purchasing-entry]');ok(entry&&new URL('http://qa'+entry.href).searchParams.get('return_to')==='/purchasing/'+stage+query,'C09 '+stage+' conserva o documento exacto para trocar de função');ok(calls.slice(before).every(c=>c.status===200),'C09 '+stage+' abre o documento real da mesma compra');}
const final=calls.filter(c=>c.url.startsWith('/api/purchasing-obligations/'+ids.invoice+'?')).at(-1).data,position=final.obligations[0];ok(position.principal_minor===10000&&position.balance_minor===10000&&position.due_on===null&&!position.source_conflict,'C08 principal e saldo100MZN com origem coerente e vencimento desconhecido');
const entry=await raw('/compras'),html=await entry.text(),token=/name="_token" value="([^"]+)"/.exec(html)[1];
for(const [body,status,name]of [
[{role:'missing',stage:'requests'},403,'função inexistente'],[{role:'validator',stage:'obligations'},403,'etapa sem direito'],[{role:'actor',stage:'orders',return_to:'https://example.com/purchasing/orders?award=1'},422,'destino externo'],[{role:'actor',stage:'orders',return_to:'/purchasing/orders?award=1&award=2'},422,'origem ambígua'],[{role:'issuer',stage:'receipts',return_to:'/purchasing/receipts?order=1&movement=1'},422,'origens misturadas']]){
const response=await raw('/compras/entrar',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded',Accept:'application/json'},body:new URLSearchParams({_token:token,...body})});ok(response.status===status,'C01 entrada recusa '+name);
}
const csrf=await raw('/compras/entrar',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded',Accept:'application/json'},body:new URLSearchParams({role:'actor',stage:'suppliers'})});ok(csrf.status===419,'C01 escolha de função exige CSRF');
// One read-only board navigation through the real module used by the installation.
await login('issuer','obligations');const hub=await raw('/purchasing/workspace'),hubHtml=await hub.text();document=parsePage(hubHtml);installDom(document);await import('../public/purchasing-board.mjs?complete=1');await settle();ok(document.querySelector('#board-records').textContent.length>0,'C09 painel único consulta documentos autorizados existentes');
fs.writeFileSync(out,JSON.stringify({passed:true,checks,principal_minor:position.principal_minor,balance_minor:position.balance_minor,source_conflict:position.source_conflict,new_business_commands:0,role_selection_posts:true,real_http:true,dom_simulation:true,visual_review:false},null,2));console.log(JSON.stringify({passed:true,checks:checks.length}));
}finally{globalThis.fetch=originalFetch;}