81 lines
4.5 KiB
JavaScript
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;});
|