// Run: node --test tools/test-finish-stage.cjs const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const vm = require('node:vm'); const ts = require('typescript'); const file = path.join(__dirname, '../assets/Script/module/Tool/GameTool.ts'); const source = ts.createSourceFile(file, fs.readFileSync(file, 'utf8'), ts.ScriptTarget.Latest, true); const declaration = source.statements.filter(ts.isVariableStatement) .flatMap(statement => [...statement.declarationList.declarations]) .find(node => node.name.getText(source) === 'GameTool'); const members = declaration.initializer.properties.filter(node => ['MAX_NORMAL_LEVEL', 'addLevel', 'maxLevel', 'shushu_Track'].includes(node.name?.getText(source))); const code = ts.transpileModule('({' + members.map(node => node.getText(source)).join(',\n') + '})', { compilerOptions: { target: ts.ScriptTarget.ES2017 }, }).outputText; function fixture(overrides = {}) { const info = { level: 0, GameplayType: 1, randomLevel: 321, otherLevel: 0, addLevel: 0, winStreak: 2, address: 'test', ...overrides }; const events = [], progress = [], gravity = [], storage = new Map(); const cc = { fx: { GameConfig: { GM_INFO: info }, StorageMessage: { setStorage: (key, value) => storage.set(key, value), } } }; const api = { setNewCloudlevel: () => progress.push({ target: 'cloud', level: info.level }), shushu_SetSuperProperties() {}, shushu_Track: (name, data) => events.push({ name, data }), yinli_FinishiStage: () => gravity.push(info.level), }; const tool = vm.runInNewContext(code, { cc, MiniGameSdk: { API: api }, MapConroler: { _instance: { is_frenzy: true, use_frenzy: true, total_steps_count: 7 } }, Utils: { setUserLevel(done, infinity) { progress.push({ target: 'server', level: info.level, infinity }); done({ code: 1, data: {} }); } }, }); cc.fx.GameTool = tool; return { info, tool, events, progress, gravity, storage }; } const maxLevel = fixture().tool.MAX_NORMAL_LEVEL; for (const scenario of [ { name: 'first stage', level: 0, stage: 1 }, { name: 'ordinary stage', level: 41, stage: 42 }, { name: 'last normal stage', level: maxLevel - 1, stage: maxLevel }, { name: 'endless stage', level: maxLevel, stage: 321, infinity: true }, ]) { test(`${scenario.name}: success reports the entered stage and saves advanced progress`, () => { const f = fixture({ level: scenario.level }); f.tool.shushu_Track('enter_stage', { infinity: !!scenario.infinity }); let completed = false; f.tool.addLevel(1200, 0, () => { completed = true; }); const entered = f.events.find(event => event.name === 'enter_stage').data; const finished = f.events.find(event => event.name === 'finish_stage').data; assert.equal(finished.stage_id, scenario.stage); assert.equal(finished.stage_id, entered.stage_id); assert.equal(finished.infinity, !!scenario.infinity); assert.equal(finished.result, 'success'); assert.equal(finished.stage_duration, 1200); assert.equal(finished.added_time, 0); assert.equal(finished.use_frenzy, true); assert.equal(finished.total_steps_count, 7); const nextLevel = Math.min(scenario.level + 1, maxLevel); assert.equal(f.info.level, nextLevel); assert.equal(f.storage.get('level').level, nextLevel); assert.deepEqual(f.progress, [ { target: 'cloud', level: nextLevel }, { target: 'server', level: nextLevel, infinity: nextLevel === maxLevel }, ]); assert.deepEqual(f.gravity, [nextLevel]); assert.equal(completed, true); }); } for (const result of ['failreason: time', 'give_up']) { for (const scenario of [ { name: 'normal', level: 41, stage: 42 }, { name: 'endless', level: maxLevel, stage: 321 }, { name: 'shared', level: 41, otherLevel: 88, stage: 88 }, ]) { test(`${scenario.name}: ${result} keeps its current stage without advancing progress`, () => { const f = fixture(scenario); f.tool.shushu_Track('finish_stage', { result, time: 1200, add_Time: 0 }); assert.equal(f.events[0].data.stage_id, scenario.stage); assert.equal(f.events[0].data.result, result); assert.equal(f.info.level, scenario.level); }); } } test('skipping a missing level advances progress without a success event', () => { const f = fixture(); f.tool.addLevel(null, null, null); assert.equal(f.info.level, 1); assert.equal(f.events.length, 0); });