111 lines
7.1 KiB
JavaScript
111 lines
7.1 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const ts = require('typescript');
|
|
const { fixture } = require('./check-api.cjs');
|
|
const at = (f, time) => { f.client.offset = time - Date.now(); };
|
|
const DAY = 86400000;
|
|
|
|
test('daily reminder uses server Beijing date, survives relogin and isolates accounts/environments', () => {
|
|
const storage = new Map(), f = fixture(storage);
|
|
f.client.info = { ...f.info }; at(f, f.info.serverTime);
|
|
const reminder = f.client.dailyReminder(); assert(reminder);
|
|
assert.equal(reminder.day, Math.floor((f.info.serverTime + 8 * 3600000) / DAY));
|
|
f.client.markDailyReminderShown(reminder); assert.equal(f.client.dailyReminder(), null);
|
|
const restarted = fixture(storage); restarted.client.info = { ...f.info }; at(restarted, f.info.serverTime);
|
|
assert.equal(restarted.client.dailyReminder(), null);
|
|
const midnight = (reminder.day + 1) * DAY - 8 * 3600000;
|
|
at(f, midnight + 1000); assert.equal(f.client.dailyReminder().day, reminder.day + 1);
|
|
f.client.markDailyReminderShown(reminder); assert(f.client.dailyReminder(), 'old date cannot consume new day');
|
|
f.game.uid = 'bob'; assert.equal(f.client.dailyReminder(), null, 'stale account client cannot remind');
|
|
const other = new f.client.constructor('bob', 'https://test/:bob');
|
|
other.info = { ...f.info }; other.offset = f.client.offset;
|
|
assert.notEqual(other.dailyReminder().key, reminder.key);
|
|
const production = fixture(storage, { baseUrl: 'https://production/' });
|
|
production.client.info = { ...f.info }; at(production, f.info.serverTime);
|
|
assert.notEqual(production.client.dailyReminder().key, reminder.key);
|
|
});
|
|
|
|
test('only qualified active periods remind; paid and purchase-disabled players are included', () => {
|
|
const f = fixture(); at(f, f.info.serverTime);
|
|
assert.equal(f.client.dailyReminder(), null);
|
|
f.client.info = { ...f.info };
|
|
for (const status of ['unavailable', 'locked', 'intermission']) {
|
|
f.client.info.status = status; assert.equal(f.client.dailyReminder(), null);
|
|
}
|
|
for (const status of ['purchasable', 'purchase_disabled', 'unlocked']) {
|
|
f.client.info.status = status; assert(f.client.dailyReminder());
|
|
}
|
|
at(f, f.info.startsAt - 1000); assert.equal(f.client.dailyReminder(), null);
|
|
at(f, f.info.endsAt + 1000); assert.equal(f.client.dailyReminder(), null);
|
|
at(f, f.info.serverTime); const old = f.client.dailyReminder();
|
|
f.client.info.periodId = 'goldMiner:test:new'; f.client.markDailyReminderShown(old);
|
|
assert(f.client.dailyReminder(), 'stale period cannot consume current reminder');
|
|
f.game.token = ''; assert.equal(f.client.dailyReminder(), null);
|
|
});
|
|
|
|
const hostCode = ts.transpileModule(fs.readFileSync('assets/Script/coin_madness/CoinMadnessHost.ts', 'utf8'), {
|
|
compilerOptions: { target: ts.ScriptTarget.ES2017, module: ts.ModuleKind.CommonJS, experimentalDecorators: true }
|
|
}).outputText;
|
|
function hostFixture() {
|
|
const f = fixture(); f.client.info = { ...f.info }; at(f, f.info.serverTime); f.game.canIos = true;
|
|
let current = f.client, notice = 0, asset, initialized = 0, done = 0;
|
|
Object.defineProperty(f.client, 'settlementNotice', { get: () => notice });
|
|
f.client.readForDisplay = () => Promise.resolve({ state: {} });
|
|
f.client.refresh = () => new Promise(() => {});
|
|
const queued = [], bundle = { load(_path, _type, cb) { asset = cb; }, releaseAll() {} };
|
|
const cc = { ...f.cc, Component: class {}, _decorator: { ccclass: c => c }, isValid: () => true,
|
|
Prefab: class {}, macro: { MAX_ZINDEX: 100 }, Director: { EVENT_AFTER_DRAW: 1 }, director: { once(_e, cb) { cb(); } },
|
|
assetManager: { loadBundle(_name, cb) { cb(null, bundle); }, getBundle: () => bundle, removeBundle() {} },
|
|
instantiate: () => ({ destroy() {}, getComponent: () => ({ initialize() { initialized++; } }) }) };
|
|
const exports = {};
|
|
new Function('require', 'exports', 'cc', hostCode)(name => {
|
|
if (name.includes('HomePopupQueue')) return { default: { get: () => ({ enqueue: (key, priority, run) => queued.push({ key, priority, run }) }) } };
|
|
if (name.includes('GoldMinerService')) return { default: { current: () => current } };
|
|
if (name.includes('Utils')) return { default: { serverUrl: () => 'https://test/' } };
|
|
return { MiniGameSdk: { API: { showToast() {} } } };
|
|
}, exports, cc);
|
|
const host = new exports.default(); host.service = f.client; host.entry = { active: true };
|
|
host.node = { getComponent: () => null, addChild() {} };
|
|
return { ...f, host, queued, run: () => queued.shift().run(() => done++),
|
|
assets: error => asset(error, {}), setCurrent: value => current = value, setNotice: value => notice = value,
|
|
initialized: () => initialized, done: () => done };
|
|
}
|
|
|
|
test('queued reminder marks only after successful mount, holds queue until close and never repeats today', async () => {
|
|
const f = hostFixture(); f.host.queueDailyReminder(); f.host.queueDailyReminder();
|
|
assert.equal(f.queued.length, 1); assert.equal(f.queued[0].priority, 11);
|
|
f.run(); assert(f.client.dailyReminder()); assert.equal(f.done(), 0);
|
|
await f.assets(null);
|
|
assert.equal(f.initialized(), 1); assert.equal(f.client.dailyReminder(), null); assert.equal(f.done(), 0);
|
|
f.host.close(); assert.equal(f.done(), 1);
|
|
f.host.nextDailyReminderAt = 0; f.host.queueDailyReminder(); assert.equal(f.queued.length, 0);
|
|
});
|
|
|
|
test('failed load keeps daily eligibility and releases queue for retry', async () => {
|
|
const f = hostFixture(); f.host.queueDailyReminder(); f.run(); await f.assets(new Error('asset failed'));
|
|
assert.equal(f.initialized(), 0); assert.equal(f.done(), 1); assert(f.client.dailyReminder());
|
|
f.host.queueDailyReminder(); assert.equal(f.queued.length, 0, 'retry has backoff');
|
|
f.host.nextDailyReminderAt = 0; f.host.queueDailyReminder(); f.run(); await f.assets(null);
|
|
assert.equal(f.initialized(), 1); f.host.close();
|
|
});
|
|
|
|
test('settlement, hidden entry and manual panel suppress automatic reminder', () => {
|
|
const f = hostFixture(); f.setNotice(100); f.host.queueDailyReminder(); assert.equal(f.queued.length, 0);
|
|
f.setNotice(0); f.host.entry.active = false; f.host.queueDailyReminder(); assert.equal(f.queued.length, 0);
|
|
f.host.entry.active = true; f.host.panel = {}; f.host.queueDailyReminder(); assert.equal(f.queued.length, 0);
|
|
f.host.panel = null; f.host.queueDailyReminder(); f.setNotice(100); f.run();
|
|
assert.equal(f.done(), 1); assert(f.client.dailyReminder());
|
|
});
|
|
|
|
test('account or expiry changes while queued/loading do not open or consume the reminder', async () => {
|
|
const queued = hostFixture(); queued.host.queueDailyReminder(); queued.setCurrent(null); queued.run();
|
|
assert.equal(queued.done(), 1); assert.equal(queued.initialized(), 0);
|
|
for (const expire of [false, true]) {
|
|
const f = hostFixture(); f.host.queueDailyReminder(); f.run();
|
|
if (expire) at(f, f.info.endsAt + 1000); else f.setCurrent(null);
|
|
await f.assets(null); assert.equal(f.initialized(), 0); assert.equal(f.done(), 1);
|
|
assert.equal(f.storage.has('goldMinerDailyReminder:https://test/:alice'), false);
|
|
}
|
|
});
|