const ts = require('typescript'); const fs = require('node:fs'); const assert = require('node:assert/strict'); const source = fs.readFileSync('assets/coin_madness/CoinMadnessMockApi.ts', 'utf8'); const exportsMock = {}; new Function('exports', ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS } }).outputText)(exportsMock); let state, now = 100000, level = 10; const store = { read: () => state && JSON.parse(JSON.stringify(state)), write: s => state = JSON.parse(JSON.stringify(s)), level: () => level }; let api = new exportsMock.default(store, () => now); let data = api.request('read').data; const periodId = data.state.config.periodId; api.request('simulate_win'); assert.equal(state.totalWins, 0); api.request('purchase', { periodId }); api.request('simulate_win'); api.request('simulate_win'); api.request('simulate_win'); assert.equal(api.request('read').data.state.progress, 2); api.request('purchase', { periodId }); assert.equal(state.totalWins, 3); api.request('claim', { periodId, stage: 0 }); assert.equal(state.mockBalance, 1150); assert.equal(api.request('read').data.state.progress, 0); assert.equal(api.request('claim', { periodId, stage: 0 }).code, 0); assert.equal(state.mockBalance, 1150); api = new exportsMock.default(store, () => now); assert.equal(api.request('read').data.state.stage, 1); api.request('fail_next'); assert.equal(api.request('simulate_win').code, 0); assert.equal(state.totalWins, 3); for(let i=0;i<3;i++) api.request('simulate_win'); api.request('expire'); assert.equal(state.mockBalance, 1350); api.request('read'); assert.equal(state.mockBalance, 1350); assert.equal(api.request('purchase', { periodId }).code, 0); now++; api.request('reset'); api.request('purchase', { periodId: state.config.periodId }); api.request('simulate_win'); api.request('expire'); assert.equal(state.mockBalance, 1000); console.log('Mock checks passed: prepay, stage gating, idempotency, persistence, failure, expiry compensation.'); const progressExports = {}; const ccMock = { fx: { GameConfig: { GM_INFO: { uid: 'test' } }, StorageMessage: { getStorage: store.read, setStorage: (key, value) => store.write(value) } } }; new Function('exports', 'cc', 'CC_PREVIEW', ts.transpileModule(fs.readFileSync('assets/Script/CoinMadnessProgress.ts', 'utf8'), { compilerOptions: { module: ts.ModuleKind.CommonJS } }).outputText)(progressExports, ccMock, true); now = Date.now(); api.request('reset'); progressExports.recordCoinMadnessMockWin(11); assert.equal(state.totalWins, 0); api.request('purchase', { periodId: state.config.periodId }); progressExports.recordCoinMadnessMockWin(11); progressExports.recordCoinMadnessMockWin(11); assert.equal(state.totalWins, 1); progressExports.recordCoinMadnessMockWin(14); assert.equal(state.totalWins, 2); progressExports.recordCoinMadnessMockWin(15); assert.equal(state.totalWins, 3); console.log('Closed-panel progress checks passed: no prepay/duplicates; a live win after a gap counts once without backfill.');