171 lines
7.1 KiB
JavaScript
171 lines
7.1 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const { loadMembers, loadModule } = require('./new-player-ab-test-support.cjs');
|
|
|
|
const level = JSON.parse(fs.readFileSync('assets/custom/Json/level1963.json', 'utf8')).LEVEL_INFO[0];
|
|
const cc = {
|
|
Component: class {}, SpriteFrame: class {},
|
|
_decorator: { ccclass: type => type, property: () => () => {} },
|
|
isValid: node => !!node,
|
|
fx: {
|
|
GameConfig: { GM_INFO: { canIos: true }, getShopPrefabPath: () => 'prefab/shop', isShopB: () => false },
|
|
GameTool: { tryReactivateStarterPack() {}, shushu_Track() {} },
|
|
AudioManager: { _instance: { playEffect() {} } },
|
|
StorageMessage: { getStorage: () => 'test-user' },
|
|
},
|
|
};
|
|
const Gate = loadModule('assets/Script/SpawnGate.ts', {}, { cc, sp: { SkeletonData: class {} } }).default;
|
|
const MapController = loadMembers('assets/Script/Map.ts', ['iceTrue', 'isSpawnGateAreaEmpty'], { cc });
|
|
|
|
function fixture(frozen = true, wxAvailable = true) {
|
|
const ice = { active: frozen };
|
|
const batches = [], unlocked = [], requests = [];
|
|
const map = Object.assign(new MapController(), {
|
|
pause: frozen, shopPause: false, gameOver: false, gameWin: false,
|
|
node: { parent: { getChildByName: () => ice } },
|
|
mapBlocksWall: Array.from({ length: level.map[0] }, () =>
|
|
Array.from({ length: level.map[1] }, () => {
|
|
const cell = { block_Id: '' };
|
|
return { getComponent: () => cell };
|
|
})),
|
|
createSpawnGateBatch(members) {
|
|
batches.push(members);
|
|
return { nodes: [{ opacity: 0 }], opacities: [255] };
|
|
},
|
|
unlockSpawnGateBatch: nodes => unlocked.push(nodes),
|
|
stopBoom() {},
|
|
});
|
|
const utilsGlobals = { cc, wx: wxAvailable ? {} : undefined, console: { log() {} } };
|
|
const Utils = loadMembers('assets/Script/module/Pay/Utils.ts', ['getShopDouble'], utilsGlobals);
|
|
utilsGlobals.Utils = Utils;
|
|
Utils.POST = (path, data, callback) => requests.push(callback);
|
|
const Manager = loadMembers('assets/Script/SceneManager.ts',
|
|
['isPauseOpen', 'isSpawnGateBlocked', 'openShop'], {
|
|
cc, MapConroler: { _instance: map }, console: { log() {} },
|
|
SceneManager: { clearInvalidShopPrefabCaches() {}, cachedShopPrefab: {} },
|
|
Utils,
|
|
});
|
|
const popups = {};
|
|
const scene = Object.assign(new Manager(), {
|
|
pendingShopRequests: 0, dynamicPopupLoads: {},
|
|
isPopupRuntimeAlive: () => true,
|
|
getDynamicPopup: name => popups[name] || null,
|
|
shopNodePrefabPath: 'prefab/shop',
|
|
shopNode: { active: false, getComponent: () => ({ init() {} }) },
|
|
});
|
|
map.SceneManager = scene;
|
|
const gate = new Gate();
|
|
gate.map = map;
|
|
gate.config = level.spawnGates[0];
|
|
gate.countLabel = { node: { active: true }, string: '8' };
|
|
return { gate, map, scene, ice, popups, batches, unlocked, requests };
|
|
}
|
|
|
|
for (const frozen of [false, true]) {
|
|
test(`${frozen ? 'frozen' : 'normal'} level 1963 opens one batch and finishes its reveal`, () => {
|
|
const { gate, map, ice, batches, unlocked } = fixture(frozen);
|
|
gate.update(0);
|
|
assert.equal(batches.length, 1);
|
|
assert.equal(batches[0], level.spawnGates[0].spawnQueue[0].members);
|
|
gate.update(0.3);
|
|
gate.update(0.15);
|
|
gate.update(0.2);
|
|
assert.equal(unlocked.length, 1);
|
|
assert.equal(unlocked[0][0].opacity, 255);
|
|
assert.equal(gate.countLabel.string, '7');
|
|
assert.equal(gate.countLabel.node.active, true);
|
|
assert.equal(map.pause, frozen, 'opening must not resume the timer');
|
|
assert.equal(ice.active, frozen, 'opening must not end the freeze effect');
|
|
});
|
|
}
|
|
|
|
test('moving a block out of the frozen gate area starts the next batch without unfreezing', () => {
|
|
const { gate, map, batches } = fixture();
|
|
const { x, y } = gate.config;
|
|
const cell = map.mapBlocksWall[x][y].getComponent();
|
|
cell.block_Id = 'block';
|
|
gate.update(1);
|
|
assert.equal(batches.length, 0);
|
|
cell.block_Id = '';
|
|
gate.update(0);
|
|
assert.equal(batches.length, 1);
|
|
assert.equal(map.pause, true);
|
|
});
|
|
|
|
const blockers = {
|
|
'ordinary pause': state => { state.ice.active = false; },
|
|
'pause loading or retry': state => { state.scene.dynamicPopupLoads.pause = true; },
|
|
'pause visible': state => { state.popups.pause = { active: true }; },
|
|
'gameplay introduction loading': state => { state.scene.dynamicPopupLoads.gameplayIntro = true; },
|
|
'gameplay introduction visible': state => { state.scene.gameplayIntro = { node: { active: true } }; },
|
|
'prop purchase loading or retry': state => { state.scene.dynamicPopupLoads.propWindow = true; },
|
|
'prop purchase visible': state => { state.popups.propWindow = { active: true }; },
|
|
'shop or starter pack': state => { state.map.shopPause = true; },
|
|
'game over': state => { state.map.gameOver = true; },
|
|
'game won': state => { state.map.gameWin = true; },
|
|
};
|
|
for (const [name, block] of Object.entries(blockers)) {
|
|
test(`${name} still blocks a new batch during freeze`, () => {
|
|
const state = fixture();
|
|
block(state);
|
|
state.gate.update(1);
|
|
assert.equal(state.batches.length, 0);
|
|
assert.equal(state.gate.countLabel.string, '8');
|
|
});
|
|
}
|
|
|
|
test('closing a prop popup while still frozen allows the waiting gate to open', () => {
|
|
const { gate, scene, popups, batches, map } = fixture();
|
|
scene.dynamicPopupLoads.propWindow = true;
|
|
gate.update(1);
|
|
delete scene.dynamicPopupLoads.propWindow;
|
|
popups.propWindow = { active: true };
|
|
gate.update(1);
|
|
assert.equal(batches.length, 0);
|
|
popups.propWindow.active = false;
|
|
gate.update(0);
|
|
assert.equal(batches.length, 1);
|
|
assert.equal(map.pause, true);
|
|
});
|
|
|
|
test('shop requests and the displayed shop both block spawning during freeze', () => {
|
|
const { scene, requests, gate, batches, map } = fixture();
|
|
scene.openShop(null);
|
|
scene.openShop(null);
|
|
gate.update(1);
|
|
assert.equal(batches.length, 0);
|
|
requests[0]({ code: 0 });
|
|
gate.update(1);
|
|
assert.equal(batches.length, 0, 'another shop request is still pending');
|
|
requests[1]({ code: 1, data: { shopDouble: false } });
|
|
assert.equal(map.shopPause, true);
|
|
gate.update(1);
|
|
assert.equal(batches.length, 0);
|
|
map.shopPause = false;
|
|
scene.shopNode.active = false;
|
|
gate.update(0);
|
|
assert.equal(batches.length, 1);
|
|
assert.equal(map.pause, true);
|
|
});
|
|
|
|
test('failed shop request releases only its gate blocker and keeps time frozen', () => {
|
|
const { scene, requests, gate, batches, map } = fixture();
|
|
scene.openShop(null);
|
|
gate.update(1);
|
|
assert.equal(batches.length, 0);
|
|
requests[0]({ code: 0 });
|
|
gate.update(0);
|
|
assert.equal(batches.length, 1);
|
|
assert.equal(map.pause, true);
|
|
assert.equal(scene.shopNode.active, false);
|
|
});
|
|
|
|
test('non-WeChat preview does not leave a pending shop request blocking the frozen gate', () => {
|
|
const { scene, requests, gate, batches } = fixture(true, false);
|
|
scene.openShop(null);
|
|
assert.equal(requests.length, 0);
|
|
gate.update(0);
|
|
assert.equal(batches.length, 1);
|
|
});
|