Files
healer-man/scripts/playtest-party-heal-popups.cjs
T
2026-10-04 22:51:21 -04:00

112 lines
5.9 KiB
JavaScript

const { selectDefaultTestDungeon, openSelectedDungeonRoles } = require('./playtest-defaults.cjs');
const { chromium } = require('C:/Users/phenom/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const directory = path.resolve('playtest-artifacts', 'party-heal-popups');
const runtimeData = fs.mkdtempSync(path.join(os.tmpdir(), 'healer-man-party-heals-'));
fs.mkdirSync(directory, { recursive: true });
(async () => {
const { createGameServer } = await import('../server/server.mjs');
const runtime = createGameServer({ dataDir: runtimeData, enableShelvedModes: false });
await new Promise((resolve) => runtime.server.listen(4194, '127.0.0.1', resolve));
const browser = await chromium.launch({ channel: 'msedge', headless: true });
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
page.setDefaultTimeout(180_000);
const pageErrors = [];
page.on('pageerror', (error) => pageErrors.push(error.message));
const moduleUrls = fs.readdirSync('dist/assets')
.filter((file) => /^(?:index|GameRuntime|combatStore)-.*\.js$/.test(file))
.map((file) => `/assets/${file}`);
await page.addInitScript((urls) => {
const stores = async () => {
const values = (await Promise.all(urls.map((url) => import(url)))).flatMap(Object.values);
const candidates = values.filter((value) => value && typeof value.getState === 'function');
const party = candidates.find((store) => Array.isArray(store.getState()?.members)
&& typeof store.getState()?.initializeParty === 'function');
const combat = candidates.find((store) => Array.isArray(store.getState()?.combatEvents)
&& typeof store.getState()?.healActor === 'function');
const shell = candidates.find((store) => Array.isArray(store.getState()?.characters)
&& typeof store.getState()?.openMainMenu === 'function');
if (!party || !combat || !shell) throw new Error('Party/combat/shell stores were not found.');
return { party, combat, shell };
};
window.openMainMenuForPartyHealPlaytest = async () => {
const { shell } = await stores();
shell.getState().openMainMenu();
};
window.openDungeonsForPartyHealPlaytest = async () => {
const { shell } = await stores();
shell.getState().openDungeons();
};
window.triggerPartyHealPopup = async () => {
const { party, combat } = await stores();
const member = party.getState().members[0];
if (!member) throw new Error('No NPC party member is available.');
const injuredHealth = Math.max(1, member.maxHealth - 300);
party.setState({
members: party.getState().members.map((candidate) => candidate.id === member.id
? { ...candidate, health: injuredHealth }
: candidate),
});
const actor = combat.getState().actors[member.id];
if (!actor) throw new Error('The NPC party actor is unavailable.');
combat.setState({ actors: {
...combat.getState().actors,
[member.id]: { ...actor, health: injuredHealth, alive: true },
} });
const mob = Object.values(combat.getState().mobs).find((candidate) => !candidate.dead && !candidate.despawned);
if (!mob) throw new Error('No living dungeon enemy is available.');
combat.setState({ mobs: { ...combat.getState().mobs, [mob.id]: { ...mob, engaged: true } } });
const result = combat.getState().healActor(member.id, 137, {
sourceActorId: '__player__',
abilityId: 'party-frame-playtest-heal',
now: Date.now(),
amountAlreadyModified: true,
});
return { memberId: member.id, amount: result.effectiveAmount };
};
}, moduleUrls);
try {
await page.goto('http://127.0.0.1:4194', { waitUntil: 'domcontentloaded' });
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('HealpopupQA');
await page.getByRole('button', { name: /Create character/ }).click();
await page.evaluate(() => window.openMainMenuForPartyHealPlaytest());
await page.locator('.main-menu-screen').waitFor();
await page.evaluate(() => window.openDungeonsForPartyHealPlaytest());
await page.locator('.dungeon-select-screen').waitFor();
await selectDefaultTestDungeon(page);
await openSelectedDungeonRoles(page);
await page.locator('.dungeon-role-option--healer').click();
await page.locator('.party-frames').waitFor();
await page.locator('.party-frame').nth(4).waitFor();
await page.locator('.loading-screen').waitFor({ state: 'detached' });
const result = await page.evaluate(() => window.triggerPartyHealPopup());
assert.equal(result.amount, 137);
const popup = page.locator('.party-frame__heal-popup', { hasText: '+137' });
await popup.waitFor({ state: 'visible' });
const targetFrame = page.locator('.party-frame').filter({ has: popup });
assert.equal(await targetFrame.count(), 1, 'heal number belongs to exactly one receiving frame');
assert.equal(await page.locator('.desktop-action-feedback').count(), 0, 'center action feedback is absent');
assert.equal((await page.locator('.action-bar__feedback').allInnerTexts()).join('').trim(), '', 'controller bar has no combat log text');
await page.screenshot({ path: path.join(directory, 'party-heal-popup.png') });
assert.deepEqual(pageErrors, []);
console.log(`Party-frame heal popup playtest passed for ${result.memberId}.`);
} finally {
await browser.close();
await new Promise((resolve) => runtime.server.close(resolve));
fs.rmSync(runtimeData, { recursive: true, force: true });
}
})().catch((error) => {
console.error(error);
process.exitCode = 1;
});