Files
baiyue-logistics-chat/tests/frontend/customer_orders.test.cjs
T

97 lines
5.0 KiB
JavaScript

const {test} = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const vm = require('node:vm');
const flush = async () => { for(let i=0;i<12;i++) await Promise.resolve(); };
function page(){
class Element {
constructor(){ this.children=[]; this.attributes={}; this.hidden=false; this.dataset={}; }
set textContent(value){ this.text=value; this.children=[]; }
get textContent(){ return (this.text || '')+this.children.map(x=>x.textContent).join(''); }
set innerHTML(value){ this.children=[]; this.text=value; }
append(...nodes){ this.children.push(...nodes); }
appendChild(node){ this.append(node); }
setAttribute(key,value){ this.attributes[key]=String(value); }
focus(){ this.focused=true; }
}
const ids={}, requests=[];
const el=id=>ids[id] ||= new Element();
const context=vm.createContext({document:{getElementById:el,createElement:()=>new Element()}, AbortController, setTimeout, clearTimeout});
vm.runInContext(fs.readFileSync('static/js/customer_orders.js','utf8'),context);
const orders=context.CustomerOrders.create({text:key=>key,
fetch:(url,options)=>new Promise((resolve,reject)=>requests.push({url,options,resolve,reject})),
renderCard:(element,card)=>{element.textContent=card.no;},
onUnauthorized:()=>{page.expired=true;}});
return {el,orders,requests,reply:async (i,data,status=200)=>{
requests[i].resolve({ok:status===200,status,json:async()=>data}); await flush();
}};
}
const row=(id=1)=>({id,order_no:'ORDER'+id,inbound_code:'INBOUND'+id,status:'PROCESSING'});
test('login automatically opens list; collapse/reopen and paging keep drafts outside panel untouched',async()=>{
const p=page();p.orders.setUser({id:1});
assert.equal(p.el('customer-orders').hidden,false);
assert.equal(p.el('customer-orders-toggle').attributes['aria-expanded'],'true');
await p.reply(0,{orders:[row()],next_before:1});
assert.match(p.el('customer-orders-list').textContent,/INBOUND1/);
p.el('customer-orders-toggle').onclick();
assert.equal(p.el('customer-orders-body').hidden,true);
p.el('customer-orders-toggle').onclick();
p.el('customer-orders-more').onclick();
assert.equal(p.requests[1].url,'/api/customer/orders?before=1');
await p.reply(1,{orders:[row(2)],next_before:null});
assert.match(p.el('customer-orders-list').textContent,/INBOUND1.*INBOUND2/);
assert.equal(p.el('customer-orders-more').hidden,true);
});
test('logout clears list and ignores delayed list/detail responses from a previous account',async()=>{
const p=page();p.orders.setUser({id:1});p.orders.setUser(null);
await p.reply(0,{orders:[row()],next_before:null});
assert.equal(p.el('customer-orders').hidden,true);
assert.equal(p.el('customer-orders-list').textContent,'');
p.orders.setUser({id:2});await p.reply(1,{orders:[row(2)],next_before:null});
p.el('customer-orders-list').children[0].onclick();
p.orders.setUser(null);p.orders.setUser({id:3});
await p.reply(2,{card:{no:'private-old-account'}});
assert.doesNotMatch(p.el('customer-orders-detail').textContent,/private/);
p.orders.setUser(null);
await p.reply(3,{orders:[],next_before:null});
});
test('exact order detail and back preserve list without a new AI request',async()=>{
const p=page();p.orders.setUser({id:1});
await p.reply(0,{orders:[row(9)],next_before:null});
p.el('customer-orders-list').children[0].onclick();
assert.equal(p.requests[1].url,'/api/customer/orders/9');
await p.reply(1,{card:{no:'ORDER9'}});
assert.equal(p.el('customer-orders-detail').textContent,'ORDER9');
p.el('customer-orders-back').onclick();
assert.equal(p.el('customer-orders-list').hidden,false);
assert.equal(p.requests.length,2);
});
test('failed request offers retry; expired login immediately clears protected data',async()=>{
const p=page();p.orders.setUser({id:1});
p.requests[0].reject(new Error('offline'));await flush();
assert.equal(p.el('customer-orders-retry').hidden,false);
p.el('customer-orders-retry').onclick();
await p.reply(1,{orders:[row()],next_before:null});
p.el('customer-orders-refresh').onclick();
await p.reply(2,{error:'customer_login_required'},401);
assert.equal(p.el('customer-orders').hidden,true);
assert.equal(p.el('customer-orders-list').textContent,'');
});
test('refresh cancels pagination; stale errors cannot replace the refreshed list',async()=>{
const p=page();p.orders.setUser({id:1});
await p.reply(0,{orders:[row()],next_before:1});
p.el('customer-orders-more').onclick();
p.el('customer-orders-refresh').onclick();
await p.reply(2,{orders:[row(3)],next_before:null});
p.requests[1].reject(new Error('late error'));await flush();
assert.equal(p.el('customer-orders-retry').hidden,true);
assert.doesNotMatch(p.el('customer-orders-list').textContent,/INBOUND1/);
assert.match(p.el('customer-orders-list').textContent,/INBOUND3/);
});