const fs = require('node:fs'), ts = require('typescript'), assert = require('node:assert/strict'); const code = ts.transpileModule(fs.readFileSync('assets/coin_madness/script/CoinMadnessPanel.ts', 'utf8'), { compilerOptions: { target: ts.ScriptTarget.ES2017, module: ts.ModuleKind.CommonJS, experimentalDecorators: true } }).outputText; const cc = { _decorator: { ccclass: () => C => C, property: () => () => {} }, Component: class { scheduleOnce(fn) { this.pending = fn; } } }; const exportsPanel = {}; new Function('require', 'exports', 'cc', code)(() => ({ default: class {} }), exportsPanel, cc); for (const status of ['unavailable', 'locked', 'unlocked']) { const panel = new exportsPanel.default(); let closed = 0; panel.api = { request() {}, expired() { closed++; } }; panel.render({ serverNow: Date.now(), status, state: { config: { endsAt: status === 'unlocked' ? Date.now() - 1 : Date.now() + 10000 } } }); assert(panel.closing); assert.equal(closed, 0, 'release must wait until render finishes'); panel.pending(); assert.equal(closed, 1); } const panel = new exportsPanel.default(); let expired = 0; panel.api = { request() {}, expired() { expired++; } }; panel.data = { state: { config: { endsAt: Date.now() - 1 } } }; panel.countdown = { setText(value) { assert.equal(value, '00:00:00'); } }; panel.tick(); const first = panel.pending; panel.tick(); assert.equal(panel.pending, first); first(); assert.equal(expired, 1, 'expiry fires once even without a server refresh'); console.log('PASS: expired/disabled panel exits before empty rendering; countdown expiry fires once');