// La cerbottana nel browser vero: dalla bottega di Pierin di Frilli al muro della piazza; mira, fiato e tiro col mouse // e col dito. npm run browser:cerbottana — schermate in /tmp/regolo-cerbottana. import { chromium } from 'playwright'; import { mkdirSync } from 'node:fs'; import assert from 'node:assert/strict'; import { staticServer } from './helpers.mjs'; import { ARGS } from './chromium.mjs'; const out = process.env.OUT ?? '/tmp/regolo-cerbottana'; mkdirSync(out, { recursive: true }); const server = await staticServer(); let browser; const errors = []; try { browser = await chromium.launch({ args: ARGS }); for (const [name, mobile, viewport] of [['desktop', false, { width: 1280, height: 860 }], ['touch', true, { width: 844, height: 390 }]]) { const page = await browser.newPage({ viewport, hasTouch: mobile, isMobile: mobile }); page.on('pageerror', e => errors.push(e.message)); await page.goto(`http://127.0.0.1:${server.port}/`); await page.click('#splash'); await page.click('#new-game'); await page.click('#rione [data-rione="campomigliaio"]'); await page.click('#skip-intro'); await page.evaluate(async () => { const { settle } = await import('/tests/helpers.mjs'); settle(game); game.go('piazza'); settle(game); game.act('talk', 'pierin'); settle(game); game.choose(game.options().findIndex(o => o.text.startsWith('Una cerbottana'))); settle(game); game.choose(game.options().findIndex(o => o.text === 'Seria.')); settle(game); }); await page.waitForSelector('#bocce-controls:not([hidden])'); await page.waitForFunction(async () => (await import('/src/engine/render.js')).hasBackground('assets/closeups/muro-cerbottana.png')); assert.equal(await page.locator('#bocce-throw').textContent(), 'Spara'); assert.ok(await page.locator('#cerbottana-help').isVisible()); await page.waitForTimeout(1600); const box = await page.locator('#scene').boundingBox(), P = (x, y) => [box.x + x / 640 * box.width, box.y + y / 360 * box.height]; if (mobile) await page.touchscreen.tap(...P(320, 118)); else { await page.mouse.move(...P(320, 118)); await page.mouse.click(...P(320, 118)); } assert.equal(await page.evaluate(() => game.closeup.step), 'aim', 'un tocco mira soltanto'); await page.screenshot({ path: `${out}/${name}-mira.png` }); if (mobile) { await page.locator('#bocce-power').fill('70'); await page.locator('#bocce-throw').tap(); } else { await page.mouse.down(); await page.waitForFunction(() => game.closeup.power >= 0.6); await page.mouse.up(); } await page.waitForFunction(() => game.closeup.left === 11 && game.closeup.step === 'aim', null, { timeout: 10000 }); await page.screenshot({ path: `${out}/${name}-dopo.png` }); await page.close(); } assert.deepEqual(errors, []); console.log(`ok: schermate in ${out}`); } finally { await browser?.close(); server.kill(); }