MatchMaster/tools/coin-madness/check-number-layout.cjs

77 lines
4.7 KiB
JavaScript

const assert = require('node:assert/strict');
const fs = require('node:fs');
const ts = require('typescript');
const { chromium } = require('playwright');
const output = ts.transpileModule(fs.readFileSync('assets/Script/coin_madness/GoldMinerService.ts', 'utf8'), {
compilerOptions: { target: ts.ScriptTarget.ES2017, module: ts.ModuleKind.CommonJS }
}).outputText;
const exported = {};
new Function('require', 'exports', output)(() => ({}), exported);
const service = Object.create(exported.default.prototype);
service.ledger = { notices: {} };
for (const status of ['purchasable', 'unlocked']) {
service.info = { status, progressWins: 4, tasks: [{ targetWins: 5, claimStatus: 'locked' }] };
assert.equal(service.hasBadge, false);
service.info.progressWins = 5;
assert.equal(service.hasBadge, true);
service.info.tasks[0].claimStatus = 'claimed';
assert.equal(service.hasBadge, false);
}
service.info.tasks[0].claimStatus = 'pending_unlock';
assert.equal(service.hasBadge, true);
service.info = null; service.ledger.notices = { old: 100 };
assert.equal(service.hasBadge, true);
(async () => {
const browser = await chromium.launch({ headless: true, channel: 'msedge' });
try {
const page = await browser.newPage({ viewport: { width: 450, height: 800 } });
page.on('pageerror', error => console.error('Preview:', error.message));
await page.goto('http://127.0.0.1:' + (process.env.PORT || 8879));
await page.waitForFunction(() => window.demo && demo.ready);
await page.evaluate(() => {
const data = { serverNow: Date.now(), status: 'purchasable', state: {
config: { periodId: 'layout-test', startsAt: Date.now() - 1000, endsAt: Date.now() + 3600000,
priceCents: 300, stages: Array.from({ length: 5 }, (_, i) => ({ wins: i + 1, coins: 1000 })) },
totalWins: 0, paidAt: 0, claimed: Array(5).fill(false), stage: 0 } };
window.testService = { info: { ...data.state.config, status: data.status },
settlementNotice: 0, serverNow: Date.now(), hasBadge: false,
readForDisplay: async () => data, refresh: async () => data, view: () => data, stopPolling() {} };
cc.director.getScene().children[0].getComponent('CoinMadnessHost').resumeSync();
});
await page.evaluate(() => { demo.open(); });
await page.waitForFunction(() => cc.director.getScene().children[0].getChildByName('CoinMadness')?.getComponent('CoinMadnessPanel')?.data);
for (const price of [3, 68, 128, 3]) {
const result = await page.evaluate(price => {
const panel = demo.panel(), data = JSON.parse(JSON.stringify(panel.data));
data.state.config.priceCents = price * 100;
data.state.config.stages.forEach((s, i) => { s.coins = i ? 9999 : 45000; });
data.state.paidAt = 0; data.status = 'purchasable';
panel.render(data);
function bounds(digits) {
const boxes = digits.node.children.filter(n => n.active).map(n => {
const image = n.getChildByName('Image');
return { left: n.x - image.width / 2, right: n.x + image.width / 2 };
});
return { left: boxes[0].left, right: boxes[boxes.length - 1].right,
separated: boxes.every((b, i) => !i || b.left >= boxes[i - 1].right) };
}
const p = bounds(panel.priceDigits), total = bounds(panel.totalDigits);
return { total, price: p, priceRight: panel.priceDigits.node.x + p.right,
currencyLeft: panel.currency.x - panel.currency.width / 2,
currencyRight: panel.currency.x + panel.currency.width / 2,
buttonRight: panel.purchaseButton.width / 2,
rewards: panel.content.children.filter(n => n.active).map(n => bounds(n.getChildByName('Reward').getComponent('CoinMadnessDigits'))) };
}, price);
assert(result.total.separated && result.total.right - result.total.left <= 164.01);
assert(result.price.separated && result.priceRight < result.currencyLeft);
assert(result.currencyRight < result.buttonRight);
assert(result.rewards.every(r => r.separated && r.right - r.left <= 170.01));
fs.mkdirSync('.codex_tmp/number-layout', { recursive: true });
await page.screenshot({ path: '.codex_tmp/number-layout/price-' + price + '.png' });
}
console.log('PASS: 4/5-digit rewards, 1/2/3-digit prices, repeated layout and unpaid completion badge');
} finally { await browser.close(); }
})().catch(error => { console.error(error); process.exitCode = 1; });