const { chromium } = require('C:/Users/phenom/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright'); const fs = require('node:fs'); const path = require('node:path'); const assert = require('node:assert/strict'); const directory = path.resolve('playtest-artifacts/boss-testing'); fs.mkdirSync(directory, { recursive: true }); const base = process.env.BOSS_TEST_URL || 'http://127.0.0.1:4187'; (async () => { const { createGameServer } = await import('../server/server.mjs'); const runtime = createGameServer({ dataDir: path.join(directory, 'test-database'), enableShelvedModes: false }); await new Promise((resolve) => runtime.server.listen(4187, '127.0.0.1', resolve)); console.log('Started isolated production test server'); const browser = await chromium.launch({ channel: 'msedge', headless: true }); const context = await browser.newContext({ viewport: { width: 1440, height: 1000 } }); const page = await context.newPage(); page.setDefaultTimeout(60000); const errors = []; const assetFiles = fs.readdirSync(path.resolve('dist/assets')); const mainModule = `/assets/${assetFiles.find((file) => /^index-.*\.js$/.test(file))}`; const combatModule = `/assets/${assetFiles.find((file) => /^combatStore-.*\.js$/.test(file))}`; await page.addInitScript(({ mainModule, combatModule }) => { window.bossTestingStores = async () => { const main = Object.values(await import(mainModule)); const combat = Object.values(await import(combatModule)); return { useGameStore: main.find((value) => value?.getState && 'bossTest' in value.getState()), useShellStore: main.find((value) => value?.getState && 'characters' in value.getState()), useCombatStore: combat.find((value) => value?.getState && 'damageMob' in value.getState()), }; }; }, { mainModule, combatModule }); page.on('pageerror', (error) => errors.push(error.message)); const capture = async (name) => { await page.screenshot({ path: path.join(directory, `${name}.png`) }); console.log(`Captured ${name}`); }; try { await page.goto(base, { waitUntil: 'domcontentloaded' }); console.log('Production menu loaded'); await page.getByRole('button', { name: /Play offline/ }).click(); await page.getByRole('button', { name: /Create character/ }).click(); await page.getByRole('button', { name: /Customize & name/ }).click(); await page.getByLabel('Character name').fill('Bosstester'); await page.getByRole('button', { name: /Create character/ }).click(); await page.getByRole('button', { name: /Continue|Enter world/ }).first().click(); await page.locator('.main-menu-screen').waitFor(); await capture('01-main-menu'); await page.getByRole('button', { name: /Boss Testing/ }).click(); await page.getByRole('heading', { name: 'Boss Testing', exact: true }).waitFor(); const picker = page.getByLabel(/Choose a boss/); const option = await picker.locator('option').evaluateAll((options) => options.find((entry) => /Lady Anacondra.*Wailing Caverns/.test(entry.textContent))?.value); assert(option, 'Lady Anacondra is selectable'); await picker.selectOption(option); await page.getByRole('button', { name: 'Test selected boss', exact: true }).waitFor({ state: 'visible' }); await capture('02-boss-selection'); await page.getByRole('button', { name: 'Test selected boss', exact: true }).click(); if (await page.getByRole('alert').count()) throw new Error(await page.getByRole('alert').innerText()); await page.locator('canvas').waitFor(); await page.waitForFunction(async () => { const { useGameStore, useCombatStore } = await window.bossTestingStores(); const game = useGameStore.getState(); return game.assetStatus === 'ready' && game.bossTest?.runtimeIds.every((id) => useCombatStore.getState().mobs[id]); }, null, { timeout: 90000 }); await page.waitForTimeout(4000); await capture('03-empty-room'); const before = await page.evaluate(async () => { const { useGameStore, useCombatStore, useShellStore } = await window.bossTestingStores(); const game = useGameStore.getState(); const combat = useCombatStore.getState(); const boss = game.bossTest; return { boss, xp: combat.xp, saved: JSON.stringify(useShellStore.getState().characters), count: Object.keys(combat.mobs).length }; }); assert.equal(before.count, 1, 'Only the selected boss spawns initially'); await page.keyboard.press('Escape'); await page.getByRole('button', { name: 'Boss readiness & report', exact: true }).click(); await page.getByRole('button', { name: 'Mark not ready', exact: true }).click(); await page.getByRole('status').filter({ hasText: 'Marked not ready.' }).waitFor(); await page.getByRole('button', { name: 'Mark needs testing', exact: true }).click(); await page.getByRole('status').filter({ hasText: 'Marked needs testing.' }).waitFor(); await capture('04-pause-review'); await page.getByRole('button', { name: 'Submit a boss report', exact: true }).click(); await page.getByLabel('Describe the issue', { exact: true }).fill('Boss Testing playtest: verify mechanic telegraphs.'); await page.getByRole('button', { name: 'Submit report', exact: true }).click(); await page.getByText('Report submitted.', { exact: false }).waitFor(); await capture('05-boss-report'); await page.getByRole('button', { name: 'Back to boss review', exact: true }).click(); await page.getByRole('button', { name: 'Fight this boss again', exact: true }).click(); await page.waitForTimeout(1000); await page.evaluate(async () => { const { useGameStore, useCombatStore } = await window.bossTestingStores(); const game = useGameStore.getState(); const combat = useCombatStore.getState(); combat.selectMob(game.bossTest.runtimeIds[0]); combat.damageMob(game.bossTest.runtimeIds[0], 1000000, Date.now()); }); await page.getByText('Boss defeated', { exact: true }).waitFor(); await page.getByRole('button', { name: 'Mark ready', exact: true }).click(); await page.getByRole('status').filter({ hasText: 'Marked ready.' }).waitFor(); await capture('06-victory-review'); const after = await page.evaluate(async () => { const { useCombatStore, useShellStore } = await window.bossTestingStores(); return { xp: useCombatStore.getState().xp, saved: JSON.stringify(useShellStore.getState().characters) }; }); assert.equal(after.xp, before.xp); assert.equal(after.saved, before.saved); const reports = runtime.database.listDungeonReports().reports; assert.equal(reports[0].bossKey, before.boss.key); assert.equal(runtime.database.listBossTestingReviews().reviews[0].status, 'ready'); await page.getByRole('button', { name: 'Return to main menu', exact: true }).click(); await page.locator('.main-menu-screen').waitFor(); await page.getByRole('button', { name: /Boss Testing/ }).click(); await picker.selectOption(option); await page.getByRole('article').getByText('Ready', { exact: true }).waitFor(); await page.setViewportSize({ width: 390, height: 844 }); await capture('07-mobile-selection'); assert(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1), 'No mobile horizontal overflow'); await page.setViewportSize({ width: 1440, height: 1000 }); await page.getByLabel('Search bosses').fill('Lady Anacondra'); await page.getByRole('button', { name: 'Fight a random boss', exact: true }).click(); await page.locator('canvas').waitFor(); await page.waitForTimeout(3000); await capture('08-random-fight'); await page.keyboard.press('Escape'); await page.getByRole('button', { name: 'Return to main menu', exact: true }).click(); await page.getByRole('button', { name: /Boss Testing/ }).click(); const missing = await picker.locator('option').evaluateAll((options) => options.find((entry) => /Taragaman the Hungerer.*Ragefire Chasm/.test(entry.textContent))?.value); assert(missing, 'An uninstalled boss is selectable'); await picker.selectOption(missing); await capture('09-automatic-download'); await page.waitForFunction(() => { const button = [...document.querySelectorAll('button')].find((entry) => entry.textContent === 'Test selected boss'); const error = document.querySelector('[role="alert"]'); if (error) throw new Error(error.textContent); return button && !button.disabled; }, null, { timeout: 120000 }); const installed = await page.evaluate(() => JSON.parse(localStorage.getItem('healer-man.content-state.v2') || '{}')); assert(installed.packs['dungeon:ragefire-chasm'], 'The selected boss pack downloads automatically'); await page.getByRole('button', { name: 'Test selected boss', exact: true }).click(); await page.waitForFunction(async () => { const { useGameStore, useCombatStore } = await window.bossTestingStores(); const game = useGameStore.getState(); return game.assetStatus === 'ready' && game.bossTest?.runtimeIds.every((id) => useCombatStore.getState().mobs[id]); }, null, { timeout: 90000 }); await page.waitForTimeout(1500); await capture('10-downloaded-boss-room'); const bottom = await page.context().newPage(); bottom.on('pageerror', (error) => errors.push(error.message)); await bottom.setViewportSize({ width: 1240, height: 1080 }); await bottom.goto(`${base}/?display=bottom&nativeLayout=1`, { waitUntil: 'domcontentloaded' }); await bottom.getByRole('button', { name: 'Boss review', exact: true }).waitFor(); await bottom.screenshot({ path: path.join(directory, '11-bottom-display.png') }); await bottom.getByRole('button', { name: 'Boss review', exact: true }).click(); await page.getByRole('heading', { name: 'Taragaman the Hungerer', exact: true }).waitFor(); await capture('12-bottom-display-review'); await bottom.close(); assert.deepEqual(errors, [], 'No browser runtime errors'); fs.writeFileSync(path.join(directory, 'results.json'), `${JSON.stringify({ passed: true, boss: before.boss, initialMobCount: before.count, xpUnchanged: true, profileUnchanged: true, automaticDownload: 'dungeon:ragefire-chasm', report: reports[0], errors }, null, 2)}\n`); console.log('Boss Testing live flow passed'); } catch (error) { await capture('failure'); console.log((await page.locator('body').innerText()).slice(-2000)); console.log('Browser errors:', errors); throw error; } finally { await browser.close(); await new Promise((resolve) => runtime.server.close(resolve)); } })().catch((error) => { console.error(error); process.exitCode = 1; });