MatchMaster/tools/test-game-shop.cjs
2026-09-21 18:05:43 +08:00

99 lines
4.7 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const { loadMembers } = require('./new-player-ab-test-support.cjs');
function fixture(legacy = false) {
const data = JSON.parse(fs.readFileSync('assets/Scene/GameScene.fire', 'utf8'));
class Widget {
static AlignMode = { ON_WINDOW_RESIZE: 1 };
updateAlignment() {
const node = this.node;
node.y = node.parent.height * (1 - node.parent.anchorY) - this.top
- node.height * (1 - node.anchorY) * node.scaleY;
}
}
const nodes = data.map(n => n.__type__ === 'cc.Node' ? {
name: n._name, children: [], components: [],
x: n._trs.array[0], y: n._trs.array[1], scaleY: n._trs.array[8],
height: n._contentSize.height, anchorY: n._anchorPoint.y,
get parent() { return this._parent; },
set parent(value) {
if (this._parent) this._parent.children = this._parent.children.filter(n => n !== this);
this._parent = value;
value.children.push(this);
},
getChildByName(name) { return this.children.find(n => n.name === name) || null; },
getComponent(type) { return this.components.find(c => c instanceof type) || null; },
addComponent(type) { const c = new type(); c.node = this; this.components.push(c); return c; },
setPosition(p) { this.x = p.x; this.y = p.y; },
convertToWorldSpaceAR(p) {
const result = { x: p.x + this.x, y: p.y + this.y };
return this.parent ? this.parent.convertToWorldSpaceAR(result) : result;
},
convertToNodeSpaceAR(p) {
const origin = this.convertToWorldSpaceAR({ x: 0, y: 0 });
return { x: p.x - origin.x, y: p.y - origin.y };
},
} : null);
nodes.forEach((node, i) => {
if (!node) return;
if (nodes[data[i]._parent?.__id__]) node.parent = nodes[data[i]._parent.__id__];
for (const ref of data[i]._components) {
const c = data[ref.__id__];
if (c.__type__ === 'cc.Widget') Object.assign(node.addComponent(Widget), { top: c._top });
}
});
const canvas = nodes.find(n => n?.name === 'Canvas');
const game = canvas.getChildByName('Game');
const gameNode = game.getChildByName('GameNode');
const top = gameNode.getChildByName('Top');
const shop = game.getChildByName('shop');
top.getComponent(Widget).updateAlignment();
if (legacy) {
shop.parent = top;
shop.y = -67.741;
shop.components = [];
} else if (shop.getComponent(Widget)) shop.getComponent(Widget).updateAlignment();
const cc = {
Widget, macro: { MAX_ZINDEX: 32767 }, isValid: node => !!node,
v2: (x, y) => ({ x, y }),
find: (path, root) => path.split('/').reduce((node, name) => node && node.getChildByName(name), root),
};
const Manager = loadMembers('assets/Script/SceneManager.ts', ['ensureGameShop', 'getWinCoinFlyTarget'], { cc });
return { manager: Object.assign(new Manager(), { node: canvas }), game, top, shop, Widget };
}
for (const legacy of [false, true]) {
test(`${legacy ? 'old' : 'new'} scene keeps Shop above Lose with valid coin children and unchanged position`, () => {
for (const height of [1280, 1920, 2400]) {
const { manager, game, shop, top, Widget } = fixture(legacy);
const before = shop.convertToWorldSpaceAR({ x: 0, y: 0 });
assert.equal(manager.ensureGameShop(), shop);
assert.equal(shop.parent, game);
assert.equal(top.getChildByName('shop'), null);
assert.equal(shop.zIndex, 32766);
shop.getComponent(Widget).updateAlignment();
assert.deepEqual(shop.convertToWorldSpaceAR({ x: 0, y: 0 }), before);
assert.ok(shop.getChildByName('coin'));
assert.equal(manager.getWinCoinFlyTarget(), shop.getChildByName('coins'));
assert.equal(manager.ensureGameShop(), shop);
assert.equal(shop.components.filter(c => c instanceof Widget).length, 1);
assert.equal(game.children.filter(n => n === shop).length, 1);
game.height = height;
shop.getComponent(Widget).updateAlignment();
assert.ok(Math.abs(shop.y - (height / 2 - 297.741)) < 1e-9);
}
});
}
test('missing Shop returns null instead of throwing while setting zIndex or resolving coins', () => {
const { manager, game, shop } = fixture();
game.children = game.children.filter(n => n !== shop);
assert.equal(manager.ensureGameShop(), null);
assert.equal(manager.getWinCoinFlyTarget(), null);
manager.node = null;
assert.equal(manager.ensureGameShop(), null);
assert.equal(manager.getWinCoinFlyTarget(), null);
});