107 lines
4.9 KiB
JavaScript
107 lines
4.9 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const { loadMembers, loadModule, resolveFile } = require('./new-player-ab-test-support.cjs');
|
|
const { LEVEL_TIME_BONUS } = loadModule('assets/Script/module/Config/LevelTimeBonusConfig.ts');
|
|
const configFile = 'assets/Script/module/Config/GameConfig.ts';
|
|
const readLevel = level => JSON.parse(fs.readFileSync(resolveFile(`assets/custom/Json/level${level}.json`), 'utf8'));
|
|
const plain = value => JSON.parse(JSON.stringify(value));
|
|
|
|
function config(info = {}) {
|
|
const Config = loadMembers(configFile, ['applyLevelData', 'LEVEL_INFO_init', 'getLevelConfigPath'], {
|
|
LEVEL_TIME_BONUS, console: { log() {} }, cc,
|
|
});
|
|
Config.GM_INFO = info;
|
|
return Config;
|
|
}
|
|
|
|
// Exercise the actual loader so file numbers, help levels and endless levels use the same key.
|
|
const requests = [];
|
|
const cc = {
|
|
v2: (x, y) => ({ x, y }), director: { getScene: () => null },
|
|
fx: { GameTool: { maxLevel: () => false } },
|
|
assetManager: {
|
|
loadBundle(_name, _options, done) { done(null, {}); },
|
|
loadAny(request, _options, done) {
|
|
requests.push(request.path);
|
|
done(null, { json: readLevel(Number(request.path.replace('Json/level', ''))) });
|
|
},
|
|
},
|
|
};
|
|
|
|
test('A, unassigned and other groups retain the original time for every configured level', () => {
|
|
assert.equal(Object.keys(LEVEL_TIME_BONUS).length, 100);
|
|
for (const info of [undefined, {}, { abTests: {} }, ...[0, 1, 3].map(layer_three => ({ abTests: { layer_three } }))]) {
|
|
const Config = config(info);
|
|
for (const level of Object.keys(LEVEL_TIME_BONUS)) {
|
|
const data = readLevel(level);
|
|
Config.applyLevelData(data, false, 0, Number(level));
|
|
assert.equal(Config.LEVEL_INFO[0].time, data.LEVEL_INFO[0].time);
|
|
assert.equal(Config.LEVEL_INFO, data.LEVEL_INFO);
|
|
}
|
|
}
|
|
});
|
|
|
|
test('B adds time once, preserves cached data and returns to original time when switched to A', () => {
|
|
const Config = config({ abTests: { layer_three: 2 } });
|
|
for (const [level, bonus] of Object.entries(LEVEL_TIME_BONUS)) {
|
|
assert.ok(Number.isInteger(bonus) && bonus > 0);
|
|
const data = readLevel(level), before = structuredClone(data);
|
|
Config.GM_INFO.abTests.layer_three = 2;
|
|
for (let retry = 0; retry < 2; retry++) {
|
|
Config.applyLevelData(data, false, 0, Number(level));
|
|
const expected = structuredClone(before.LEVEL_INFO);
|
|
expected[0].time += bonus;
|
|
assert.deepEqual(plain(Config.LEVEL_INFO), expected);
|
|
assert.equal(Config.BLOCK_INFO, data.BLOCK_INFO);
|
|
assert.equal(Config.WALL_INFO, data.WALL_INFO);
|
|
assert.deepEqual(data, before);
|
|
}
|
|
Config.GM_INFO.abTests.layer_three = 1;
|
|
Config.applyLevelData(data, false, 0, Number(level));
|
|
assert.equal(Config.LEVEL_INFO[0].time, before.LEVEL_INFO[0].time);
|
|
}
|
|
});
|
|
|
|
test('B leaves unlisted levels unchanged and uses the file number instead of a stale internal id', () => {
|
|
const Config = config({ abTests: { layer_three: 2 } });
|
|
for (const level of [1, 113, 115, 1282]) {
|
|
const data = readLevel(level);
|
|
Config.applyLevelData(data, false, 0, level);
|
|
assert.equal(Config.LEVEL_INFO, data.LEVEL_INFO);
|
|
}
|
|
const data = readLevel(222);
|
|
assert.equal(data.LEVEL_INFO[0].id, '158');
|
|
Config.applyLevelData(data, false, 0, 222);
|
|
assert.equal(Config.LEVEL_INFO[0].time, 70);
|
|
assert.equal(Config.LEVEL_INFO[0].id, '158');
|
|
});
|
|
|
|
test('loader applies B bonuses to the requested mainline, help and endless level', () => {
|
|
for (const mode of ['mainline', 'help', 'endless']) {
|
|
const Config = config({ level: mode === 'mainline' ? 221 : 0,
|
|
otherLevel: mode === 'help' ? 222 : 0, randomLevel: 222, abTests: { layer_three: 2 } });
|
|
cc.fx.GameConfig = Config;
|
|
Config.levelLoadRequest = Config.sceneLoadRequest = 0;
|
|
Config.takeEntryDownloadRelease = () => null;
|
|
Config.LEVEL_INFO_init(false, 0, mode === 'help', mode === 'endless');
|
|
assert.equal(requests.at(-1), 'Json/level222');
|
|
assert.equal(Config.LEVEL_INFO[0].time, 70, mode);
|
|
}
|
|
});
|
|
|
|
test('server A/B assignments select original and bonus times before entering the scene', () => {
|
|
const Manager = loadMembers('assets/Script/GameManager.ts', ['setABTests'], { cc });
|
|
const manager = new Manager();
|
|
const Config = config();
|
|
cc.fx.GameConfig = Config;
|
|
const seen = [];
|
|
Config.enterGameSceneWhenReady = (time, preparation) => seen.push([Config.LEVEL_INFO[0].time, time, preparation]);
|
|
const preparation = {};
|
|
for (const [group, expected] of [['A', 135], ['B', 165], [1, 135], [2, 165]]) {
|
|
manager.setABTests({ layer_3: { group } });
|
|
Config.applyLevelData(readLevel(114), true, 0.5, 114, preparation);
|
|
assert.deepEqual(seen.at(-1), [expected, 0.5, preparation]);
|
|
}
|
|
});
|