const test = require('node:test'); const assert = require('node:assert/strict'); const { loadMembers } = require('./new-player-ab-test-support.cjs'); function fixture(hp = 5, powerSeconds = 60) { let now = 1000; const info = { hp, hp_Max: 5, userPowerTime: powerSeconds ? now + powerSeconds : 0, min_Time: 120, useravatarIcon: '', useravaterkuang: '', coin: 100 }; const node = () => { const children = new Map(), component = {}; return { active: true, opacity: 255, getChildByName(name) { if (!children.has(name)) children.set(name, node()); return children.get(name); }, getComponent: () => component }; }; const cc = { sys: { platform: 'browser', WECHAT_GAME: 'wechat', BYTEDANCE_GAME: 'bytedance' }, Sprite: {}, Label: {}, find: () => ({ getComponent: () => null }), fx: { GameConfig: { GM_INFO: info }, GameTool: { getUserPowerTime() { if (info.userPowerTime <= now) { info.userPowerTime = 0; return false; } return true; }, getTimeMargin: value => String(value), getTimeMargin2: value => String(value), getActionName() {}, loadSpineSimple() {}, getSetScreenResolutionFlag: () => false, }, } }; const Shop = loadMembers('assets/shop/script/shop.ts', [ 'init', 'setHealthInfo', 'updatePower', 'startPowerTime', 'stopPowerTime', 'startTimeCutDown', 'stopTimeCutDown', 'removeOnShowListener', ], { cc, Date: { now: () => now * 1000 }, SceneManager: {}, MapConroler: {}, NumberToImage: { numberToImageNodes() {}, numberToImageNodesCoin() {} }, console: { log() {} } }); const shop = new Shop(), scheduled = new Set(); Object.assign(shop, { node: node(), Stamina: node(), coin: node(), ui: { getSpriteFrame() {} }, refreshJungleEntryLayout() {}, openShop() {}, updateIcon() {}, schedule: callback => scheduled.add(callback), unschedule: callback => scheduled.delete(callback) }); const get = name => shop.Stamina.getChildByName(name); const open = () => { shop.node.active = true; shop.init({}); }; const tick = seconds => { now += seconds; [...scheduled].forEach(callback => callback()); }; return { shop, info, scheduled, get, open, tick, advance: seconds => { now += seconds; } }; } test('full stamina and infinite stamina never show both labels when repeatedly reopening the cached shop', () => { const f = fixture(); for (let i = 0; i < 3; i++) { f.open(); assert.equal(f.get('man').active, false, 'full label must already be hidden before the first timer tick'); assert.equal(f.get('skyLine').active, true); assert.equal(f.scheduled.size, 1, 'reopening must not duplicate the infinite stamina timer'); f.tick(1); assert.equal(f.get('man').active, false); assert.equal(f.get('skyLine').getChildByName('skyTime').getComponent().string, String(59 - i)); f.shop.node.active = false; } }); test('a later ordinary health refresh cannot cover the infinite stamina countdown', () => { const f = fixture(); f.open(); f.tick(1); f.shop.setHealthInfo(true); assert.equal(f.get('man').active, false); assert.equal(f.get('skyLine').active, true); assert.equal(f.info.hp, 5); }); test('full stamina without infinite stamina still displays full immediately', () => { const f = fixture(5, 0); for (let i = 0; i < 2; i++) { f.open(); assert.equal(f.get('man').active, true); assert.equal(f.get('skyLine').active, false); assert.equal(f.get('time').active, false); assert.equal(f.scheduled.size, 0); } }); test('infinite stamina expiring while the shop is closed restores the full label on reopening', () => { const f = fixture(5, 2); f.open(); f.shop.node.active = false; f.advance(2); f.open(); assert.equal(f.get('skyLine').active, false); assert.equal(f.get('man').active, true); assert.equal(f.scheduled.size, 0); }); test('infinite stamina expiring in the open shop restores the full label', () => { const f = fixture(5, 2); f.open(); f.tick(2); assert.equal(f.get('skyLine').active, false); assert.equal(f.get('man').active, true); assert.equal(f.scheduled.size, 0); }); test('non-full stamina preserves ordinary and infinite countdown visibility', () => { for (const power of [0, 60]) { const f = fixture(3, power); f.open(); assert.equal(f.get('man').active, false); assert.equal(f.get('skyLine').active, power > 0); assert.equal(f.get('time').active, true); assert.equal(f.get('time').opacity, power ? 0 : 255); assert.equal(f.get('progresss').getComponent().fillRange, 3 / 5); assert.equal(f.info.hp, 3); } });