86 lines
6.5 KiB
JavaScript
86 lines
6.5 KiB
JavaScript
const test=require('node:test'),assert=require('node:assert/strict'),fs=require('node:fs'),vm=require('node:vm'),ts=require('typescript');
|
|
const read=file=>fs.readFileSync(file,'utf8');
|
|
function load(file,require,globals={},replace=s=>s){
|
|
const context={exports:{},require,...globals};
|
|
vm.runInNewContext(ts.transpileModule(replace(read(file)),{compilerOptions:{module:ts.ModuleKind.CommonJS,target:ts.ScriptTarget.ES2017,experimentalDecorators:true}}).outputText,context);
|
|
return context.exports;
|
|
}
|
|
const probability=load('assets/pyramid/scripts/PyramidProbability.ts',()=>{});
|
|
const Debug=load('assets/pyramid/scripts/PyramidAnimationDebug.ts',()=>probability).default;
|
|
function snapshot(){return {periodId:'test',revision:1,currentLevel:1,completed:false,canPay:true,pendingGrants:[],levels:Array.from({length:6},(_,i)=>({level:i+1,rewards:[
|
|
{rewardId:`${i+1}-low`,weight:1,up:false,gain:false,deliveryStatus:'not_eligible',goods:[{id:1001,count:10}]},
|
|
{rewardId:`${i+1}-high`,weight:3,up:true,gain:false,deliveryStatus:'not_eligible',goods:[{id:2001,count:2}]}
|
|
]}))};}
|
|
test('debug uses remaining weights, marks gains and never mutates the server snapshot',()=>{
|
|
const source=snapshot(),before=JSON.stringify(source),session=new Debug(source,'u:test');
|
|
const first=session.draw(()=>0.24);assert.equal(first.rewardId,'1-low');assert.equal(session.state.currentLevel,1);
|
|
assert.deepEqual(Array.from(probability.remainingProbabilities(1,session.state.levels[0].rewards)),[0,1]);
|
|
const second=session.draw(()=>0);assert.equal(second.rewardId,'1-high');assert.equal(session.state.currentLevel,2);
|
|
assert.equal(second.available.length,1);assert.equal(second.available[0],'1-high');assert.equal(JSON.stringify(source),before);
|
|
const weighted=new Debug(source,'u:test');assert.equal(weighted.draw(()=>0.26).rewardId,'1-high');
|
|
});
|
|
test('free debug round advances to six, claims remaining and final goods exactly once',()=>{
|
|
const session=new Debug(snapshot(),'u:test');
|
|
for(let level=1;level<=5;level++){assert.equal(session.draw(()=>0.9).previousLevel,level);assert.equal(session.state.currentLevel,level+1);}
|
|
assert.equal(session.state.canDraw,false);assert.equal(session.state.canClaimFinal,true);assert.equal(session.draw(),null);
|
|
const goods=session.claim();assert.equal(goods.length,7);assert.equal(goods.filter(g=>g.id===1001).reduce((n,g)=>n+g.count,0),60);
|
|
assert.equal(session.state.completed,true);assert.equal(session.state.canClaimFinal,false);assert.equal(session.claim().length,0);
|
|
assert.ok(session.state.levels.every(l=>l.rewards.every(r=>r.deliveryStatus==='delivered')));
|
|
});
|
|
function panelFixture(version='开发版',flag=true){
|
|
const source=snapshot(),calls=[],info={uid:'a'},service={busy:false,data:()=>source,buy:async()=>calls.push('buy'),sync:async()=>calls.push('sync'),deliver:async()=>calls.push('deliver'),act:async()=>calls.push('act')};
|
|
const cc={Component:class{},SpriteFrame:class{},_decorator:{ccclass:C=>C,property:()=>()=>{}},fx:{GameTool:{getWechatGameVersion:()=>version},GameConfig:{GM_INFO:info}},isValid:()=>true};
|
|
const Panel=load('assets/pyramid/scripts/PyramidPanel.ts',name=>name.includes('PyramidAnimationDebug')?{default:Debug}:name.includes('PyramidProbability')?probability:{default:service},
|
|
{cc,CC_PREVIEW:false},s=>flag?s.replace('const PYRAMID_ANIMATION_DEBUG = false','const PYRAMID_ANIMATION_DEBUG = true'):s).default;
|
|
const panel=new Panel();panel.tip={};panel.node={};panel.price={'0':{}};panel.render=()=>{};panel.animateRewards=async()=>{};panel.animateResult=async()=>{};
|
|
return {panel,source,calls,info,service,cc,animateRewards:Panel.prototype.animateRewards};
|
|
}
|
|
test('live draw delivers then opens the battle-pass reward prefab from publicUI, cached or cold',async()=>{
|
|
for(const cached of [false,true]){
|
|
const {panel,source,service,cc,animateRewards}=panelFixture('开发版',false),events=[];
|
|
const goods=[{id:2001,count:2},{id:2005,count:3600}];
|
|
source.canDraw=true;
|
|
service.act=async action=>{assert.equal(action,'draw');events.push('draw');service.lastDraw={requestId:'draw-1',goods};return true;};
|
|
service.deliver=async()=>{events.push('deliver');return true;};
|
|
panel.animateResult=async()=>events.push('selection');
|
|
panel.animateRewards=animateRewards;
|
|
panel.movingGoodsFrames=['coin','freeze','hammer','magic','infinite'];
|
|
let close,shown;
|
|
const prefab={},overlay={setPosition(){},getComponent(type){
|
|
if(type==='Reward')return {init(rewards,done,durationUnits){
|
|
events.push('reward');shown=rewards;close=done;assert.equal(durationUnits,true);
|
|
}};
|
|
return null;
|
|
}};
|
|
const bundle={load(path,type,done){
|
|
assert.ok(fs.existsSync(`assets/publicUI/${path}.prefab`),'reward prefab must exist in the requested bundle');
|
|
assert.equal(path,'prefab/RewardWindow');done(null,prefab);
|
|
}};
|
|
cc.assetManager={getBundle(name){assert.equal(name,'publicUI');return cached?bundle:null;},
|
|
loadBundle(name,done){assert.equal(name,'publicUI');done(null,bundle);}};
|
|
cc.instantiate=value=>{assert.equal(value,prefab);return overlay;};
|
|
panel.node={addChild(value){assert.equal(value,overlay);}};
|
|
let finished=false;
|
|
const action=panel.actionLive().then(()=>finished=true);
|
|
await new Promise(resolve=>setImmediate(resolve));
|
|
assert.deepEqual(events,['draw','selection','deliver','reward']);
|
|
assert.equal(shown[0].type,'freeze');assert.equal(shown[0].count,2);
|
|
assert.equal(shown[1].type,'infinite_health');assert.equal(shown[1].count,3600);
|
|
assert.equal(panel.drawing,true);assert.equal(finished,false);
|
|
close();await action;
|
|
assert.equal(panel.drawing,false);assert.equal(panel.rewardAnimation,null);
|
|
}
|
|
});
|
|
test('debug panel blocks double-clicks, retains local progress, skips recovery and resets on account change',async()=>{
|
|
const {panel,source,calls,info}=panelFixture(),before=JSON.stringify(source);let finish,rolls=0;
|
|
panel.animateResult=()=>{rolls++;return new Promise(resolve=>finish=resolve);};
|
|
const first=panel.action();await panel.action();assert.equal(rolls,1);await panel.recoverDelivery();finish();await first;
|
|
assert.equal(panel.state().levels[0].rewards.filter(r=>r.gain).length,1);assert.deepEqual(calls,[]);assert.equal(JSON.stringify(source),before);
|
|
info.uid='b';assert.equal(panel.state().levels[0].rewards.filter(r=>r.gain).length,0);
|
|
});
|
|
test('disabled flag and release environment both route exclusively to live purchase',async()=>{
|
|
for(const [version,flag] of [['开发版',false],['正式版',true]]){
|
|
const {panel,calls}=panelFixture(version,flag);await panel.action();assert.deepEqual(calls,['buy']);assert.equal(panel.debugSession,null);
|
|
}
|
|
});
|