Files
lilishop-ui/manager/tests/wechatOrderSync.test.cjs

75 lines
4.9 KiB
JavaScript

/**
* 小程序订单筛选及异步竞态回归,隔离网络验证旧响应不覆盖新页面。
* @author Bulbasaur
* @since 2026-11-09
*/
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const vm = require('node:vm');
const { parse } = require('@vue/compiler-sfc');
const root = path.resolve(__dirname, '..');
const tick = () => new Promise(resolve => setImmediate(resolve));
/** 从实际 Vue 脚本加载逻辑,替换网络及 Vue 生命周期,不启动业务服务。 */
function script(file) {
return parse(fs.readFileSync(path.join(root,file),'utf8')).descriptor.scriptSetup.content.replace(/^import .*;\r?$/gm,'');
}
/** 为并发请求提供可控完成顺序。 */
function deferred() {
let resolve, reject;
const promise = new Promise((yes,no) => {resolve=yes; reject=no;});
return {promise,resolve,reject};
}
/** 保留表单值及计算属性的最小运行环境。 */
function primitives() {
return { ref:value=>({value}), computed:fn=>({get value(){return fn();}}), defineOptions:()=>{}, defineExpose:()=>{}, onMounted:()=>{} };
}
test('专用列表固定支付范围、重置筛选,且旧列表和数量响应不能覆盖新结果', async()=>{
const requests=[];
const send=kind=>params=>{const wait=deferred();requests.push({kind,params:{...params},...wait});return wait.promise;};
const context={...primitives(),defineProps:()=>({fixedClientType:'WECHAT_MP',fixedPaymentMethod:'WECHAT',wechatSync:true,allowExport:false}),useRoute:()=>({query:{clientType:'PC',paymentMethod:'WALLET'}}),watch:()=>{},wechatSyncOptions:[],API_Order:{getWechatOrderList:send('list'),getWechatOrderNum:send('count')}};
vm.createContext(context);
vm.runInContext(script('src/views/order/order/orderList.vue')+';globalThis.t={init,handleSearch,handleReset,changePage,orderStatusClick,searchForm,data,orderNumData,loading,loadError};',context);
const t=context.t;
t.init();
t.searchForm.value.paymentMethod='WALLET';t.searchForm.value.wechatSyncStatus='FAILED';t.handleSearch();
const newest=requests.filter(r=>r.kind==='list').at(-1);
newest.resolve({success:true,result:{records:[{sn:'new'}],total:1}});
requests.filter(r=>r.kind==='count').at(-1).resolve({success:true,result:{waitPayNum:5}});
await tick();
requests[0].resolve({success:true,result:{records:[{sn:'old'}],total:99}});
requests[1].resolve({success:true,result:{waitPayNum:99}});
await tick();
assert.equal(t.data.value[0].sn,'new');assert.equal(t.orderNumData.value.waitPayNum,5);
t.changePage(2);t.orderStatusClick('DELIVERED');t.handleReset();
for(const r of requests){assert.equal(r.params.clientType,'WECHAT_MP');assert.equal(r.params.paymentMethod,'WECHAT');}
assert.equal(t.searchForm.value.wechatSyncStatus,'');assert.equal(t.searchForm.value.paymentMethod,'WECHAT');
requests.filter(r=>r.kind==='list').at(-1).reject(new Error('network'));
await tick();assert.equal(t.loadError.value,true);assert.equal(t.data.value.length,0);assert.equal(t.loading.value,false);
});
test('普通订单仍使用原接口且允许其他支付方式,不强制附加上报条件', async()=>{
let sent;
const context={...primitives(),defineProps:()=>({fixedClientType:'',fixedPaymentMethod:'',wechatSync:false,allowExport:true}),useRoute:()=>({query:{}}),watch:()=>{},wechatSyncOptions:[],API_Order:{getOrderList:params=>{sent={...params};return Promise.resolve({success:true,result:{records:[],total:0}});},getOrderNum:()=>Promise.resolve({success:true,result:{}})}};
vm.createContext(context);vm.runInContext(script('src/views/order/order/orderList.vue')+';globalThis.t={init,searchForm};',context);
context.t.searchForm.value.paymentMethod='WALLET';context.t.init();await tick();
assert.equal(sent.paymentMethod,'WALLET');assert.equal(sent.clientType,undefined);assert.equal(sent.wechatSyncStatus,undefined);
});
test('日志抽屉切换订单及关闭后,旧请求不会回填另一笔订单', async()=>{
const props={modelValue:true,orderSn:'A'},requests=[];let changed;
const context={...primitives(),defineProps:()=>props,defineEmits:()=>()=>{},watch:(source,callback)=>{changed=callback;callback();},getWechatOrderLogs:(sn,params)=>{const wait=deferred();requests.push({sn,...wait});return wait.promise;}};
vm.createContext(context);vm.runInContext(script('src/views/order/wechat/SyncLogDrawer.vue')+';globalThis.t={records,loading,failed,load};',context);
props.orderSn='B';changed();
requests[1].resolve({success:true,result:{records:[{orderSn:'B'}],total:1}});await tick();
requests[0].resolve({success:true,result:{records:[{orderSn:'A'}],total:1}});await tick();
assert.equal(context.t.records.value[0].orderSn,'B');
context.t.load();props.modelValue=false;changed();requests[2].resolve({success:true,result:{records:[{orderSn:'B'}],total:1}});await tick();
assert.equal(context.t.records.value.length,0);assert.equal(context.t.loading.value,false);
});