Files
SGF/scripts/continuity-ui.mjs
2026-11-04 09:37:20 +02:00

21 lines
7.0 KiB
JavaScript

import fs from 'node:fs';import path from 'node:path';import assert from 'node:assert/strict';import {appendProcessLinks} from '../public/purchasing-focus.mjs';
const tag=process.argv[2];assert(/^[a-f0-9]{12}$/.test(tag??''));const run=JSON.parse(fs.readFileSync('C:/laragon/data/sgf-tempo/run/modular-regression-current.json')),root=path.join(run.root,'private/receipt-composition-'+tag),out=path.join(root,'continuity-ui.json');assert(!fs.existsSync(out));const checks=[],ok=(v,name)=>{assert(v,name);checks.push(name);};let enabled=true,allowed=new Set(['receipts','invoices','obligations','dossiers']);
class Element{constructor(tag,text){this.tag=tag;this.textContent=text??'';this.children=[];this.dataset={focusEnabled:'true',continuityEnabled:enabled?'true':'false',context:'qa-context',csrf:'qa-csrf'};this.isConnected=true;}append(...nodes){this.children.push(...nodes);}prepend(...nodes){this.children.unshift(...nodes);}replaceChildren(...nodes){this.children=[...nodes];}setAttribute(k,v){this[k]=v;}dispatchEvent(){} }
globalThis.Option=class extends Element{constructor(text,value){super('option',text);this.value=value;}};globalThis.FormData=class{*[Symbol.iterator](){} };const walk=e=>[e,...e.children.flatMap(walk)],paginator=data=>({data,current_page:1,last_page:1,per_page:25,total:data.length}),rev='a'.repeat(64),calls=[];let elements=new Map,mismatchReceipt=false;
globalThis.document={createElement:tag=>new Element(tag),querySelector:selector=>{if(selector.startsWith('nav[')){const stage=selector.match(/a\[href="\/purchasing\/([a-z]+)"\]/)?.[1];return allowed.has(stage)?new Element('a'):null;}if(!elements.has(selector))elements.set(selector,new Element(selector));return elements.get(selector);}};
const request={id:3,number:'REQ-EXACT',status:'approved',items:[],steps:[],total_minor:10000,process_version:3};const invoice={id:77,number:'INV-EXACT',status:'validated',issued_on:'2026-11-03',total_minor:10000,created_by:1,validated_by:2,items:[],purchase_order_id:41};
const responses={
'/api/purchasing-requests':{new_revision:rev,centres:[],can_prepare:false,requests:paginator([])},'/api/purchasing-requests/3':{request,capabilities:{},history:[],revision:rev},
'/api/purchasing-sourcing/requests/3':{request,capabilities:{},comparison:{policy:{minimum_proposals:3,minimum_evaluators:2},ready:true,rows:[],top_ids:[]},quotes:[],award:{id:2,status:'approved',total_minor:10000,approvals:[]},history:[]},
'/api/purchasing-orders/awards/2':{basis:{award:{id:2,status:'approved',approvals:[],total_minor:10000},quote:{supplier:{name:'QA'},items:[],currency:'MZN'}},existing:{order:{id:41,number:'OC-EXACT',items:[]}},can_issue:false},
'/api/purchasing-receipts/orders/41':{order:{id:41,number:'OC-EXACT'},progress:{state:'complete'},history:{...paginator([]),last_page:2},can_confirm:false},
'/api/purchasing-receipts/history/91':{receipt:{id:91,purchase_order_id:41,number:'REC-EXACT'},documents_enabled:false},
'/api/purchasing-invoices/orders/41':{order:{id:41,number:'OC-EXACT',currency:'MZN',items:[]},invoices:[invoice],can_prepare:false,revision:rev,receipt_progress:{},physical_corrections:[]},
'/api/purchasing-obligations/77':{documents:[{local_id:77,number:'INV-EXACT',supplier_name:'QA',total_minor:10000,status:'validated',order_id:41,missing:[],lines:[]}],obligations:[],permissions:{},proposals:[],events:[],revision:rev,pagination:{proposals:{page:1,last_page:1},events:{page:1,last_page:1}}},
'/api/purchasing-dossiers/3':{request,view_revision:rev,_links:[{href:'/purchasing/requests?request=3',label:'Consultar esta requisição'}],stages:Object.fromEntries(['quotes','awards','orders','receipts','invoices','obligations'].map(k=>[k,{accessible:false}])),events:{accessible:true,data:[],pagination:{page:1,last_page:1}}}
};
globalThis.fetch=async(url,options={})=>{calls.push({url,method:options.method??'GET'});const pathname=url.split('?')[0];let data=responses[pathname];if(!data&&(/\/history$/.test(pathname)||/^\/api\/purchasing-(sourcing|orders|receipts|invoices|obligations|dossiers)$/.test(pathname)))data=paginator([]);if(!data)throw Error('Unexpected mock read '+url);if(mismatchReceipt&&pathname==='/api/purchasing-receipts/history/91')data={receipt:{id:91,purchase_order_id:42,number:'REC-MISMATCH'},documents_enabled:false};return {ok:true,json:async()=>structuredClone(data)};};
const settle=()=>new Promise(resolve=>setTimeout(resolve,10));let sequence=0;async function mount(file,query){elements=new Map;calls.length=0;globalThis.location={search:query};await import('../public/'+file+'.mjs?case='+tag+'-'+sequence++);await settle();await settle();return {calls:[...calls],detail:document.querySelector(file==='order-workspace'?'#award-detail':file==='sourcing-workspace'?'#process-detail':'#detail'),status:document.querySelector(file==='receipt-workspace'?'#message':'#status')};}
responses['/api/purchasing-invoices/orders/41'].order.requisition_id=3;const observed=[],links=d=>walk(d.detail).filter(v=>v.href).map(v=>v.href);let d=await mount('receipt-workspace','?order=41');observed.push(...d.calls);ok(links(d).includes('/purchasing/invoices?order=41'),'receipt carries actual order into invoice consultation');ok(d.calls.every(v=>v.url.startsWith('/api/purchasing-receipts')),'receipt continuation adds no hidden cross-stage request');d=await mount('supplier-invoice-workspace','?order=41&invoice=77');observed.push(...d.calls);ok(['/purchasing/receipts?order=41','/purchasing/dossiers?request=3','/purchasing/obligations?invoice=77'].every(v=>links(d).includes(v)),'invoice links retain exact receipt order dossier request and document responsibility');d=await mount('supplier-obligation-workspace','?invoice=77');observed.push(...d.calls);ok(['/purchasing/invoices?order=41&invoice=77','/purchasing/receipts?order=41'].every(v=>links(d).includes(v)),'obligation returns to exact original invoice and physical order');allowed=new Set(['receipts']);d=await mount('receipt-workspace','?order=41');observed.push(...d.calls);ok(!links(d).length,'physical-only menu does not advertise invoice destination');d=await mount('supplier-invoice-workspace','?order=41&invoice=77');observed.push(...d.calls);ok(links(d).length===1&&links(d)[0]==='/purchasing/receipts?order=41','missing obligation and dossier menu entries suppress only those contextual links');enabled=false;allowed=new Set(['receipts','invoices','obligations','dossiers']);d=await mount('supplier-invoice-workspace','?order=41&invoice=77');observed.push(...d.calls);ok(!links(d).length,'disabled continuity feature leaves previous focused screen without inline links');const node=new Element('div');appendProcessLinks(node,[{href:'/purchasing/orders?award=2',label:'original dossier hint'}]);ok(node.children.length===1,'default dossier link rendering remains independent of optional menu filter');ok(observed.every(v=>v.method==='GET'),'all inline-link startup probes perform reads only');fs.writeFileSync(out,JSON.stringify({passed:true,checks,dom_simulation:true,business_commands:0,visual_review:false},null,2));console.log(JSON.stringify({passed:true,checks:checks.length}));