forked from phenom/healer-man
112 lines
5.9 KiB
JavaScript
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;
|
|
});
|