import fs from 'node:fs'; import path from 'node:path'; import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); const nodePathEntries = (process.env.NODE_PATH || '') .split(path.delimiter) .filter(Boolean); const resolveOptions = nodePathEntries.length > 0 ? { paths: nodePathEntries } : undefined; const { chromium } = require(require.resolve('playwright', resolveOptions)); const url = process.env.FARM_GODOT_URL || 'http://127.0.0.1:8792/index.html'; const outDir = process.env.FARM_SMOKE_OUT || path.resolve('docs/ui-baseline/smoke'); const waitMs = Number(process.env.FARM_SMOKE_WAIT_MS || 900); const errors = []; fs.mkdirSync(outDir, { recursive: true }); for (const file of fs.readdirSync(outDir)) { if (file.endsWith('.png')) { fs.unlinkSync(path.join(outDir, file)); } } const browser = await chromium.launch({ headless: true }); const page = await browser.newPage({ viewport: { width: 640, height: 960 }, deviceScaleFactor: 1 }); page.on('pageerror', error => errors.push(`pageerror: ${error.message}`)); page.on('console', message => { if (message.type() === 'error') { errors.push(`console: ${message.text()}`); } }); async function shot(name) { await page.screenshot({ path: path.join(outDir, `${name}.png`), fullPage: false }); } async function waitForGame() { await page.waitForFunction(() => { const canvas = document.querySelector('canvas'); return canvas && canvas.clientWidth > 0 && canvas.clientHeight > 0; }, { timeout: 60000 }); await page.waitForTimeout(7000); } async function clickShot(name, x, y) { await page.mouse.click(x, y); await page.waitForTimeout(waitMs); await shot(name); } async function closePanel() { await page.mouse.click(320, 730); await page.waitForTimeout(250); await page.mouse.click(320, 810); await page.waitForTimeout(250); await page.mouse.click(320, 875); await page.waitForTimeout(500); } try { await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 }); await waitForGame(); await shot('01-main'); await clickShot('02-log-panel', 237, 144); await closePanel(); await clickShot('03-land-upgrade-panel', 340, 145); await closePanel(); await clickShot('04-pay-panel', 451, 144); await closePanel(); await clickShot('05-level-gift-panel', 539, 144); await closePanel(); await clickShot('06-lottery-panel', 445, 221); await closePanel(); await clickShot('07-notice-panel', 43, 294); await closePanel(); await clickShot('08-sign-panel', 43, 379); await closePanel(); await clickShot('09-online-gift-panel', 43, 466); await closePanel(); await clickShot('11-gold-exchange-panel', 58, 560); await closePanel(); await clickShot('12-land-menu', 366, 551); await page.mouse.click(600, 500); await page.waitForTimeout(500); await clickShot('13-market-panel', 88, 870); await page.waitForTimeout(500); await shot('14-market-panel-opened'); await page.mouse.click(496, 338); await page.waitForTimeout(waitMs); await shot('15-market-sell-quantity'); await page.mouse.click(520, 318); await page.waitForTimeout(300); await page.mouse.click(496, 294); await page.waitForTimeout(waitMs); await shot('16-market-buy-quantity'); await page.mouse.click(520, 318); await page.waitForTimeout(300); await closePanel(); await page.mouse.click(500, 870); await page.waitForTimeout(500); await clickShot('17-dog-panel', 494, 558); await closePanel(); await page.keyboard.down('Control'); await page.mouse.wheel(0, -700); await page.keyboard.up('Control'); await page.waitForTimeout(500); await shot('18-zoom-in'); await page.keyboard.down('Control'); await page.mouse.wheel(0, 1200); await page.keyboard.up('Control'); await page.waitForTimeout(500); await shot('19-zoom-out'); } finally { await browser.close(); } if (errors.length > 0) { console.error(JSON.stringify({ ok: false, url, outDir, errors }, null, 2)); process.exit(1); } console.log(JSON.stringify({ ok: true, url, outDir }, null, 2));