MatchMaster/tools/coin-madness/check-claim-waiting.cjs

81 lines
4.5 KiB
JavaScript

// No network or real rewards: exercise the panel's request/animation handoff.
const fs = require('fs'), ts = require('typescript'), assert = require('node:assert/strict');
class Node {
constructor(name) { this.name = name; this.children = []; this.active = true; this.position = {x: 200, y: 0}; }
addChild(n) { this.children.push(n); }
getChildByName(name) { return this.children.find(n => n.name === name); }
setPosition(p) { this.position = p; }
setContentSize() {}
addComponent() { return {arc() {}, stroke() {}}; }
destroy() { this.destroyed = true; }
}
const cc = { Component: class {}, Node, Graphics: class {}, Color: class {},
_decorator: {ccclass: () => C => C, property: (...args) => args.length >= 2 ? undefined : () => {}},
isValid: n => !n.destroyed, Tween: {stopAllByTarget() {}},
tween: () => ({by() {return this;}, repeatForever() {return this;}, start() {}}) };
const source = fs.readFileSync('assets/coin_madness/script/CoinMadnessPanel.ts', 'utf8');
const code = ts.transpileModule(source, {compilerOptions: {
target: ts.ScriptTarget.ES2017, module: ts.ModuleKind.CommonJS, experimentalDecorators: true
}, reportDiagnostics: true});
assert.equal(code.diagnostics.length, 0);
const out = {};
new Function('require', 'exports', 'cc', code.outputText)(() => ({default: class {}}), out, cc);
function fixture() {
const panel = new out.default(), row = new Node('Stage0');
row.addChild(new Node('Claim'));
panel.content = {children: [row]}; panel.message = {};
panel.data = {state: {claimed: [false]}};
const events = [];
panel.render = data => {
panel.data = data;
events.push(panel.displayedClaims.has(0) ? 'claimed' : 'unclaimed');
row.getChildByName('Claim').active = !panel.displayedClaims.has(0) && !panel.claimWaiters.has(0);
};
panel.showRewardAnimation = () => {
assert(!panel.claimWaiters.has(0));
assert(panel.displayedClaims.has(0));
events.push('animation');
};
let resolve, reject, calls = 0;
panel.api = {request: () => {calls++; return new Promise((yes, no) => {resolve = yes; reject = no;});}, toast() {}};
return {panel, row, events, resolve: value => resolve(value), reject: error => reject(error), calls: () => calls};
}
(async () => {
let f = fixture();
const pending = f.panel.run('claim', {stage: 0});
assert(f.panel.claimWaiters.has(0)); assert(!f.row.getChildByName('Claim').active);
const spinner = f.panel.claimWaiters.get(0);
await f.panel.run('claim', {stage: 0}); assert.equal(f.calls(), 1);
f.panel.rewardSaved(0);
assert(spinner.destroyed); assert.deepEqual(f.events, ['claimed', 'animation']);
// A stale response after wallet persistence must not turn the button back on.
f.resolve({code: 1, data: {state: {claimed: [false]}}}); await pending;
assert(!f.row.getChildByName('Claim').active);
await f.panel.run('claim', {stage: 0}); assert.equal(f.calls(), 1);
for (const throws of [false, true]) {
f = fixture(); const failed = f.panel.run('claim', {stage: 0});
const waiting = f.panel.claimWaiters.get(0);
if (throws) f.reject(new Error('offline')); else f.resolve({code: 0, msg: 'retry'});
await failed;
assert(waiting.destroyed); assert.equal(f.panel.claimWaiters.size, 0);
assert(f.row.getChildByName('Claim').active); assert(!f.events.includes('animation'));
}
f = fixture();
const other = new Node('Stage1'); other.addChild(new Node('Claim'));
f.panel.content.children.push(other);
const queued = [];
f.panel.api.request = (action, body) => new Promise(resolve => queued.push({stage: body.stage, resolve}));
const first = f.panel.run('claim', {stage: 0});
f.panel.rewardSaved(0); // Coins are flying; confirmation is still pending.
const second = f.panel.run('claim', {stage: 1});
assert.deepEqual(queued.map(q => q.stage), [0, 1]);
assert(f.panel.claimWaiters.has(1)); assert(!other.getChildByName('Claim').active);
await f.panel.run('claim', {stage: 1}); assert.equal(queued.length, 2);
queued[0].resolve({code: 1}); await first;
assert(f.panel.claimWaiters.has(1), 'first completion must not clear another row spinner');
queued[1].resolve({code: 1}); await second;
assert.equal(f.panel.claimWaiters.size, 0);
assert(source.includes('.to(.06, { scale: .75 }'));
console.log('PASS: row spinner, duplicate suppression, synchronized claimed state/animation, stale response and failure recovery; coins start at 75%.');
})().catch(error => {console.error(error); process.exitCode = 1;});