forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
48a678dcc5
commit
9c5fb4c614
18 files changed
+397
-46
No files matched your search
@@ -0,0 +1,139 @@
|
||||
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('artifacts/playtest/rom-status-effects');
|
||||
const runtimeData = fs.mkdtempSync(path.join(os.tmpdir(), 'healer-man-rom-status-'));
|
||||
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(4195, '127.0.0.1', resolve));
|
||||
const browser = await chromium.launch({ channel: 'msedge', headless: true });
|
||||
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
|
||||
page.setDefaultTimeout(180_000);
|
||||
const errors = [];
|
||||
page.on('pageerror', (error) => errors.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) => {
|
||||
window.romStatusStores = async () => {
|
||||
const exports = (await Promise.all(urls.map((url) => import(url)))).flatMap(Object.values);
|
||||
const stores = exports.filter((value) => value && typeof value.getState === 'function');
|
||||
return {
|
||||
game: stores.find((store) => typeof store.getState()?.relocatePlayer === 'function'),
|
||||
shell: stores.find((store) => typeof store.getState()?.saveActiveProgression === 'function'),
|
||||
combat: stores.find((store) => typeof store.getState()?.castAbility === 'function'),
|
||||
party: stores.find((store) => typeof store.getState()?.setCommand === 'function'
|
||||
&& Array.isArray(store.getState()?.members)),
|
||||
};
|
||||
};
|
||||
}, moduleUrls);
|
||||
|
||||
try {
|
||||
await page.goto('http://127.0.0.1:4195', { waitUntil: 'domcontentloaded' });
|
||||
await page.getByRole('button', { name: /Play offline/ }).click();
|
||||
await page.getByRole('button', { name: /Create character/ }).click();
|
||||
await page.locator('.creator-category-tabs button').filter({ hasText: 'RoM' }).click();
|
||||
await page.locator('.class-option').filter({ hasText: 'Priest' }).click();
|
||||
await page.getByRole('button', { name: /Customize & name/ }).click();
|
||||
await page.getByLabel('Character name').fill('RomPriestStatusQA');
|
||||
await page.getByRole('button', { name: /Create character/ }).click();
|
||||
await page.locator('.character-select-screen').waitFor();
|
||||
await page.evaluate(async () => {
|
||||
const { shell } = await window.romStatusStores();
|
||||
const state = shell.getState();
|
||||
const character = state.characters.find((entry) => entry.id === state.selectedCharacterId);
|
||||
if (!character) throw new Error('Priest character was not selected.');
|
||||
shell.setState({ activeCharacter: character });
|
||||
shell.getState().saveActiveProgression(30, 0, character.talentRanks);
|
||||
shell.setState({ activeCharacter: null });
|
||||
shell.getState().openMainMenu();
|
||||
});
|
||||
await page.locator('.main-menu-screen').waitFor();
|
||||
await page.evaluate(async () => {
|
||||
const { shell } = await window.romStatusStores();
|
||||
shell.getState().openDungeons();
|
||||
});
|
||||
await page.locator('.dungeon-select-screen').waitFor();
|
||||
await page.locator('.dungeon-select-row').first().waitFor();
|
||||
const entry = await page.evaluate(async () => {
|
||||
const { shell } = await window.romStatusStores();
|
||||
const ok = shell.getState().enterDungeon('wailing-caverns');
|
||||
return { ok, notice: shell.getState().notice };
|
||||
});
|
||||
assert.equal(entry.ok, true, JSON.stringify(entry));
|
||||
await page.locator('.party-frames').waitFor();
|
||||
await page.locator('.loading-screen').waitFor({ state: 'detached' });
|
||||
await page.evaluate(async () => {
|
||||
const { game } = await window.romStatusStores();
|
||||
game.getState().closeOverlay();
|
||||
});
|
||||
await page.locator('.dungeon-boss-intro').waitFor({ state: 'detached' });
|
||||
await page.waitForFunction(async () => {
|
||||
const { combat } = await window.romStatusStores();
|
||||
return combat.getState().level >= 30 && Object.values(combat.getState().mobs)
|
||||
.some((mob) => !mob.dead && mob.homePosition);
|
||||
});
|
||||
const setup = await page.evaluate(async () => {
|
||||
const { game, combat, party } = await window.romStatusStores();
|
||||
party?.getState().setCommand('stop');
|
||||
const mob = Object.values(combat.getState().mobs)
|
||||
.find((candidate) => !candidate.dead && candidate.homePosition);
|
||||
if (!mob) throw new Error('No living dungeon mob is available.');
|
||||
const [x, y, z] = mob.homePosition;
|
||||
game.getState().relocatePlayer({ footPosition: [x + 3, y, z], yaw: -Math.PI / 2 });
|
||||
combat.getState().setPlayerPosition(game.getState().playerPosition);
|
||||
combat.setState((state) => ({ mobs: { ...state.mobs, [mob.id]: {
|
||||
...state.mobs[mob.id], health: 100_000, maxHealth: 100_000,
|
||||
} } }));
|
||||
combat.getState().selectMob(mob.id);
|
||||
const now = Date.now();
|
||||
combat.setState((state) => ({ effects: [
|
||||
...state.effects,
|
||||
...[1, 2, 3].map((index) => ({
|
||||
id: `rom-status-poison-${index}`,
|
||||
kind: 'dot',
|
||||
sourceAbilityId: 'rom-priest-primary-4',
|
||||
sourceActorId: `qa-source-${index}`,
|
||||
targetId: mob.id,
|
||||
coefficient: 0,
|
||||
remainingTicks: 6,
|
||||
intervalMs: 2_000,
|
||||
nextTickAt: now + 10_000,
|
||||
})),
|
||||
] }));
|
||||
return { mobId: mob.id };
|
||||
});
|
||||
await page.waitForTimeout(500);
|
||||
const castState = await page.evaluate(async () => {
|
||||
const { combat } = await window.romStatusStores();
|
||||
const cast = combat.getState().castAbility('rom-priest-primary-9', undefined, Date.now());
|
||||
return { cast, activeCast: combat.getState().activeCast };
|
||||
});
|
||||
assert.equal(castState.cast.ok, true, JSON.stringify({ ...setup, ...castState }));
|
||||
assert.equal(castState.activeCast.mode, 'channel');
|
||||
await page.locator('.timed-effect-strip--target .timed-effect').first().waitFor();
|
||||
assert.equal(await page.locator('.timed-effect-strip--target .timed-effect').count(), 1);
|
||||
assert.equal(await page.locator('.timed-effect-strip--target .timed-effect__stacks').innerText(), '3');
|
||||
await page.screenshot({ path: path.join(directory, 'chain-of-light-and-stacked-dot.png') });
|
||||
assert.deepEqual(errors, []);
|
||||
console.log(`RoM channel and stacked DoT playtest passed: ${directory}`);
|
||||
} finally {
|
||||
await browser.close();
|
||||
await new Promise((resolve) => runtime.server.close(resolve));
|
||||
const tempRoot = fs.realpathSync(os.tmpdir());
|
||||
const resolvedData = fs.realpathSync(runtimeData);
|
||||
if (path.dirname(resolvedData) === tempRoot
|
||||
&& path.basename(resolvedData).startsWith('healer-man-rom-status-')) {
|
||||
fs.rmSync(resolvedData, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
})().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
Reference in new issue
Block a user