99 lines
5.5 KiB
JavaScript
99 lines
5.5 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {readFile} from 'node:fs/promises';
|
|
const source=await readFile(new URL('../salessupport/todoList/todoList.vue',import.meta.url),'utf8');
|
|
const script=source.match(/<script>([\s\S]*?)<\/script>/)[1]
|
|
.replace(/import[\s\S]*?from\s+['"][^'"]+['"];?[^\n]*/g,'').replace('export default','return');
|
|
const utility=await readFile(new URL('../common/normalizeApiKeys.js',import.meta.url),'utf8');
|
|
const {normalizeApiKeys}=await import('data:text/javascript;base64,'+Buffer.from(utility).toString('base64'));
|
|
function setup({list=async()=>({success:true,data:{records:[]}}),detail=async()=>({success:true,data:{}})}={}) {
|
|
const notices=[];
|
|
const page=new Function('mgmHeader','SimpleWatermark','uni','normalizeApiKeys','getTodoList','getTodoDetail','setTimeout',script)(
|
|
{},{},{showLoading(){},hideLoading(){},showToast:v=>notices.push(v)},normalizeApiKeys,list,detail,fn=>fn());
|
|
const vm={$t:k=>k,currentTask:null,todoListRequestSeq:0,filterType:'IM',currentIndex:0,
|
|
startDate:'2026-09-09',endDate:'2026-09-10',calendarSave:[],listData:[]};
|
|
for(const [k,fn] of Object.entries(page.methods)) vm[k]=fn.bind(vm);
|
|
for(const [k,fn] of Object.entries(page.computed)) Object.defineProperty(vm,k,{get:fn.bind(vm)});
|
|
vm.formatDate=v=>v; vm.checkCalendarSave=()=>{};
|
|
return {vm,page,notices};
|
|
}
|
|
const rows=id=>({success:true,data:{records:[{date:'2026-09-09',dateRecords:[{playerId:id,eta:'13:45'}]}]}});
|
|
test('older success and error cannot overwrite latest Todo response',async()=>{
|
|
for(const rejectOld of [false,true]) {
|
|
const pending=[];
|
|
const {vm}=setup({list:()=>new Promise((resolve,reject)=>pending.push({resolve,reject}))});
|
|
const old=vm.getTodoListByData(); const latest=vm.getTodoListByData();
|
|
pending[1].resolve(rows('new')); await latest;
|
|
if(rejectOld) pending[0].reject(new Error('old failure')); else pending[0].resolve(rows('old'));
|
|
await old;
|
|
assert.equal(vm.listData[0].dateRecords[0].playerId,'new');
|
|
assert.equal(vm.listData[0].dateRecords[0].eta,'13:45');
|
|
assert.equal(vm.showTodoListView,true);
|
|
}
|
|
});
|
|
test('empty success and incomplete error response have distinct messages',async()=>{
|
|
for(const [response,message] of [[{success:true,data:{records:[]}},'common.noRecord'],
|
|
[{success:false},'todo.returnError'],[{success:false,code:'NO RECORD'},'common.noRecord']]) {
|
|
const {vm}=setup({list:async()=>response}); await vm.getTodoListByData();
|
|
assert.equal(vm.dataNull,message); assert.equal(vm.showTodoListView,false);
|
|
}
|
|
});
|
|
test('native Error without errMsg is handled',async()=>{
|
|
const {vm}=setup({list:async()=>{throw new Error('network');}});
|
|
await vm.getTodoListByData(); assert.equal(vm.dataNull,'todo.returnError');
|
|
});
|
|
test('detail normalizes IRC balance and nested Offer fields in both casings',async()=>{
|
|
for(const data of [{IRCProgramFundBalance:'0',Descriptions:[{ItemRecordType:'Offer'}]},
|
|
{iRCProgramFundBalance:'0',descriptions:[{itemRecordType:'Offer'}]}]) {
|
|
const {vm}=setup({detail:async()=>({success:true,data})});
|
|
const record={playerId:'80001',actionDate:'2026-09-09',arrowName:'arrow-down'};
|
|
await vm.fetchTodoDetail(record);
|
|
assert.equal(record.detailData.iRCProgramFundBalance,'0');
|
|
assert.equal(record.showOffer,true); assert.equal(record.showDetail,true);
|
|
assert.equal(record.isProcessing,false);
|
|
}
|
|
});
|
|
test('ETA label still uses Daylight eta field',()=>{
|
|
const {vm,page}=setup();
|
|
assert.equal(page.computed.getETALable.call(vm)({eta:'13:45',eTA:'09:00'}),'13:45');
|
|
});
|
|
test('Todo formatters accept API string amounts, hours and ratios',()=>{
|
|
const {vm}=setup();
|
|
assert.equal(vm.formatNumber('3000000000'),'3,000,000,000');
|
|
assert.equal(vm.formatNumber('12.75'),'12.75');
|
|
assert.equal(vm.formatNumber('0'),'0');assert.equal(vm.formatNumber(null),'0');
|
|
assert.equal(vm.formarHour('1.5'),'1.5 hours');
|
|
assert.equal(vm.formarHour('0'),'0 hour');
|
|
assert.equal(vm.getPercentFormat('0.25'),'25%');
|
|
assert.equal(vm.getPercentFormat('0'),'0%');
|
|
});
|
|
test('Sharer renderer preserves trailing room status and notes and only renders Y icon',()=>{
|
|
const {vm}=setup();
|
|
for(const flag of ['Y','N']) {
|
|
const parts=vm.getRoomDescriptionParts({itemRecordType:'Room',itemRecordDescription:`Conf#123 [Rm Ready] | Suite | Sharer:${flag} | Note`});
|
|
assert.equal(parts.filter(p=>p.type==='sharerIcon').length,flag==='Y'?1:0);
|
|
const text=parts.filter(p=>p.type==='text').map(p=>p.text).join('');
|
|
assert.ok(text.includes('Conf#123 [Rm Ready]'));assert.ok(text.includes('Note'));
|
|
assert.ok(!text.includes('Sharer:'));
|
|
}
|
|
assert.equal(vm.getItemShowSharerIcon('Conf#123 | Sharer:N | Note'),false);
|
|
assert.deepEqual(vm.getDescriptionWithSharerIconParts(null),[]);
|
|
});
|
|
test('summary room markers use row flags only on first line and Limo warning excludes Inhouse',()=>{
|
|
const conditions=[...source.matchAll(/v-show="([^"]+)"/g)].map(m=>m[1]);
|
|
for(const field of ['isQueue','roomReady']) {
|
|
const expression=conditions.find(c=>c.includes(`rowRecord.${field}`));
|
|
assert.ok(expression);
|
|
const evaluate=new Function('index','rowRecord',`return ${expression}`);
|
|
assert.equal(evaluate(0,{[field]:true}),true);
|
|
assert.equal(evaluate(1,{[field]:true}),false);
|
|
assert.equal(evaluate(0,{[field]:false}),false);
|
|
}
|
|
const warning=conditions.find(c=>c.includes("hasLimoRecord =='-1'"));
|
|
const evaluate=new Function('index','currentIndex','rowRecord',`return ${warning}`);
|
|
assert.equal(evaluate(0,0,{hasLimoRecord:-1}),true);
|
|
assert.equal(evaluate(0,2,{hasLimoRecord:-1}),false);
|
|
assert.equal(evaluate(1,0,{hasLimoRecord:-1}),false);
|
|
assert.equal(evaluate(0,0,{hasLimoRecord:1}),false);
|
|
});
|