feat: finish FHD battle sidebar
This commit is contained in:
@@ -24,14 +24,14 @@ async function moveLegacyUi(page, x, y, options) {
|
||||
async function clickBattleDeploymentStart(page) {
|
||||
const point = await page.evaluate(() => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('BattleScene');
|
||||
const layout = scene?.layout;
|
||||
const startButton = window.__HEROS_DEBUG__?.battle()?.battleHud?.deploymentPanel?.startButtonBounds;
|
||||
const canvas = document.querySelector('canvas');
|
||||
const bounds = canvas?.getBoundingClientRect();
|
||||
if (!scene || !layout || !canvas || !bounds) {
|
||||
if (!scene || !startButton || !canvas || !bounds) {
|
||||
return null;
|
||||
}
|
||||
const logicalX = layout.panelX + 24 + (layout.panelWidth - 48) / 2;
|
||||
const logicalY = layout.panelY + layout.panelHeight - 76 + 17;
|
||||
const logicalX = startButton.x + startButton.width / 2;
|
||||
const logicalY = startButton.y + startButton.height / 2;
|
||||
return {
|
||||
x: bounds.left + logicalX * bounds.width / scene.scale.width,
|
||||
y: bounds.top + logicalY * bounds.height / scene.scale.height
|
||||
@@ -174,8 +174,10 @@ try {
|
||||
boundsInside(firstBattleRecentActions, firstBattleProbe.panelBounds) &&
|
||||
boundsInside(firstBattleRecentActions, firstBattleProbe.sceneBounds) &&
|
||||
firstBattleRecentActions?.compact === false &&
|
||||
firstBattleRecentActions.height === 118 &&
|
||||
firstBattleRecentActions.height === 126 &&
|
||||
firstBattleRecentActions.rowCount === Math.min(3, firstBattleProbe.battleLog.length) &&
|
||||
firstBattleRecentActions.textBounds.length === firstBattleRecentActions.rowCount &&
|
||||
firstBattleRecentActions.textBounds.every((bounds) => boundsInside(bounds, firstBattleRecentActions)) &&
|
||||
firstBattleProbe.sideTexts.includes('최근 행동') &&
|
||||
firstBattleRecentActions.bottom === firstBattleRecentActions.y + firstBattleRecentActions.height &&
|
||||
firstBattleRecentActions.gapToMiniMap >= 6 &&
|
||||
@@ -5470,12 +5472,33 @@ async function assertLargeRosterHud(browser, url) {
|
||||
JSON.stringify([...battle.deployedAllyIds].sort()) === JSON.stringify([...expectedIds].sort())
|
||||
);
|
||||
}, expectedRosterIds, { timeout: 90000 });
|
||||
|
||||
const deploymentProbe = await readLargeRosterHudProbe(page);
|
||||
assertLateBattleHeaderLayout(deploymentProbe, 'deployment');
|
||||
assertLateBattleSidebarLayout(deploymentProbe, 'deployment', false);
|
||||
assertLateBattleDeploymentLayout(deploymentProbe);
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-final-battle-deployment.png`, fullPage: true });
|
||||
await assertCanvasPainted(page, 'final battle deployment');
|
||||
|
||||
await page.evaluate(() => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('BattleScene');
|
||||
if (scene?.phase === 'deployment') {
|
||||
scene.confirmPreBattleDeployment?.();
|
||||
}
|
||||
scene?.hideBattleEventBanner?.();
|
||||
scene?.renderSituationPanel?.();
|
||||
});
|
||||
await page.waitForFunction(() => {
|
||||
const hud = window.__HEROS_DEBUG__?.battle()?.battleHud;
|
||||
return hud?.miniMap?.visible === true && hud?.sidebar?.bounds && hud?.deploymentPanel === null;
|
||||
}, undefined, { timeout: 30000 });
|
||||
|
||||
const situationProbe = await readLargeRosterHudProbe(page);
|
||||
assertLateBattleHeaderLayout(situationProbe, 'situation');
|
||||
assertLateBattleSidebarLayout(situationProbe, 'situation', true);
|
||||
|
||||
await page.evaluate(() => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('BattleScene');
|
||||
scene?.renderRosterPanel?.('ally', '출전 위치 확정. 행동할 장수를 선택하세요.');
|
||||
});
|
||||
await page.waitForFunction(() => {
|
||||
@@ -5519,6 +5542,25 @@ async function assertLargeRosterHud(browser, url) {
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-final-battle-roster-last-page.png`, fullPage: true });
|
||||
await assertCanvasPainted(page, 'final battle roster last page');
|
||||
|
||||
await page.evaluate(() => {
|
||||
window.__HEROS_GAME__?.scene.getScene('BattleScene')?.renderRosterPanel?.('enemy', '적군 전력을 확인하세요.');
|
||||
});
|
||||
await page.waitForFunction(() => {
|
||||
const roster = window.__HEROS_DEBUG__?.battle()?.battleHud?.rosterPanel;
|
||||
return roster?.tab === 'enemy' && roster?.pageCount > 1;
|
||||
}, undefined, { timeout: 30000 });
|
||||
await page.evaluate(() => new Promise((resolve) => {
|
||||
requestAnimationFrame(() => requestAnimationFrame(resolve));
|
||||
}));
|
||||
const enemyPage = await readLargeRosterHudProbe(page);
|
||||
assert(
|
||||
enemyPage.roster.rowLayouts.some((row) => row.unitName.length >= 8),
|
||||
`Expected the enemy roster fixture to exercise a long unit name: ${JSON.stringify(enemyPage)}`
|
||||
);
|
||||
assertLargeRosterPageLayout(enemyPage, 'enemy first');
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-final-battle-enemy-roster.png`, fullPage: true });
|
||||
await assertCanvasPainted(page, 'final battle enemy roster');
|
||||
|
||||
await page.evaluate((selectedSortieUnitIds) => {
|
||||
window.__HEROS_GAME__?.scene.getScene('BattleScene')?.scene.restart({
|
||||
battleId: 'sixty-sixth-battle-wuzhang-final',
|
||||
@@ -5559,6 +5601,12 @@ async function readLargeRosterHudProbe(page) {
|
||||
roster: hud?.rosterPanel ?? null,
|
||||
recentActions: hud?.recentActions ?? null,
|
||||
miniMap: hud?.miniMap ?? null,
|
||||
header: hud?.header ?? null,
|
||||
sidebar: hud?.sidebar ?? null,
|
||||
deploymentPanel: hud?.deploymentPanel ?? null,
|
||||
sceneBounds: scene
|
||||
? { x: 0, y: 0, width: scene.scale.width, height: scene.scale.height }
|
||||
: null,
|
||||
panelBounds: scene
|
||||
? { x: scene.layout.panelX, y: scene.layout.panelY, width: scene.layout.panelWidth, height: scene.layout.panelHeight }
|
||||
: null
|
||||
@@ -5566,11 +5614,113 @@ async function readLargeRosterHudProbe(page) {
|
||||
});
|
||||
}
|
||||
|
||||
function assertLateBattleHeaderLayout(probe, label) {
|
||||
const { header, panelBounds, sceneBounds } = probe;
|
||||
const headerBounds = [
|
||||
header?.titleBounds,
|
||||
header?.turnBounds,
|
||||
header?.speedBounds,
|
||||
header?.objectiveBounds,
|
||||
header?.defeatBounds,
|
||||
header?.sortieOrderBounds
|
||||
];
|
||||
assert(
|
||||
isFiniteBounds(panelBounds) &&
|
||||
isFiniteBounds(sceneBounds) &&
|
||||
boundsInside(panelBounds, sceneBounds) &&
|
||||
headerBounds.every((bounds) => boundsInside(bounds, panelBounds) && boundsInside(bounds, sceneBounds)),
|
||||
`Expected every late-battle ${label} header element inside the FHD side panel and scene: ${JSON.stringify(probe)}`
|
||||
);
|
||||
assert(
|
||||
header.titleBounds.y + header.titleBounds.height <= Math.min(header.turnBounds.y, header.speedBounds.y) &&
|
||||
header.turnBounds.x + header.turnBounds.width <= header.speedBounds.x &&
|
||||
Math.max(
|
||||
header.turnBounds.y + header.turnBounds.height,
|
||||
header.speedBounds.y + header.speedBounds.height
|
||||
) <= header.objectiveBounds.y &&
|
||||
header.objectiveBounds.y + header.objectiveBounds.height <= header.defeatBounds.y &&
|
||||
header.defeatBounds.y + header.defeatBounds.height <= header.sortieOrderBounds.y &&
|
||||
header.sortieOrderBounds.y + header.sortieOrderBounds.height <= header.contentTop,
|
||||
`Expected the wrapped late-battle ${label} objective, defeat condition, and sortie order to remain separated: ${JSON.stringify(header)}`
|
||||
);
|
||||
}
|
||||
|
||||
function assertLateBattleSidebarLayout(probe, label, expectMiniMap) {
|
||||
const { sidebar, miniMap, header, panelBounds, sceneBounds } = probe;
|
||||
assert(
|
||||
isFiniteBounds(sidebar?.bounds) &&
|
||||
boundsInside(sidebar.bounds, panelBounds) &&
|
||||
boundsInside(sidebar.bounds, sceneBounds) &&
|
||||
sidebar.contentTop === header?.contentTop &&
|
||||
sidebar.bounds.y >= sidebar.contentTop &&
|
||||
sidebar.bounds.y + sidebar.bounds.height <= sidebar.contentBottom,
|
||||
`Expected the late-battle ${label} sidebar inside its FHD content region: ${JSON.stringify(probe)}`
|
||||
);
|
||||
assert(
|
||||
header.sortieOrderBounds.y + header.sortieOrderBounds.height <= sidebar.bounds.y,
|
||||
`Expected the late-battle ${label} sidebar below the sortie-order header: ${JSON.stringify(probe)}`
|
||||
);
|
||||
if (!expectMiniMap) {
|
||||
assert(miniMap?.visible === false, `Expected deployment to reserve the full sidebar by hiding the minimap: ${JSON.stringify(probe)}`);
|
||||
return;
|
||||
}
|
||||
assert(
|
||||
miniMap?.visible === true &&
|
||||
boundsInside(miniMap.frameBounds, panelBounds) &&
|
||||
boundsInside(miniMap.frameBounds, sceneBounds) &&
|
||||
sidebar.bounds.y + sidebar.bounds.height <= miniMap.frameBounds.y,
|
||||
`Expected the late-battle ${label} sidebar to stay above the FHD minimap: ${JSON.stringify(probe)}`
|
||||
);
|
||||
}
|
||||
|
||||
function assertLateBattleDeploymentLayout(probe) {
|
||||
const { deploymentPanel, sidebar, panelBounds, sceneBounds } = probe;
|
||||
const roleBounds = deploymentPanel?.roleBounds ?? [];
|
||||
const deploymentBounds = [
|
||||
deploymentPanel?.headerBounds,
|
||||
deploymentPanel?.noticeBounds,
|
||||
...roleBounds,
|
||||
deploymentPanel?.restoreButtonBounds,
|
||||
deploymentPanel?.startButtonBounds
|
||||
];
|
||||
assert(
|
||||
roleBounds.length > 0 && deploymentBounds.every((bounds) =>
|
||||
boundsInside(bounds, sidebar?.bounds) &&
|
||||
boundsInside(bounds, panelBounds) &&
|
||||
boundsInside(bounds, sceneBounds)
|
||||
) && boundsInside(deploymentPanel?.noticeTextBounds, deploymentPanel?.noticeBounds),
|
||||
`Expected every late-battle deployment section inside the FHD sidebar and scene: ${JSON.stringify(probe)}`
|
||||
);
|
||||
assert(
|
||||
deploymentPanel.headerBounds.y + deploymentPanel.headerBounds.height <= deploymentPanel.noticeBounds.y &&
|
||||
deploymentPanel.noticeBounds.y + deploymentPanel.noticeBounds.height <= roleBounds[0].y &&
|
||||
roleBounds.every((bounds, index) =>
|
||||
index === 0 || roleBounds[index - 1].y + roleBounds[index - 1].height <= bounds.y
|
||||
) &&
|
||||
roleBounds.at(-1).y + roleBounds.at(-1).height <= deploymentPanel.restoreButtonBounds.y &&
|
||||
deploymentPanel.restoreButtonBounds.y + deploymentPanel.restoreButtonBounds.height <= deploymentPanel.startButtonBounds.y,
|
||||
`Expected the late-battle deployment header, notice, roles, and actions not to overlap: ${JSON.stringify(deploymentPanel)}`
|
||||
);
|
||||
}
|
||||
|
||||
function assertLargeRosterPageLayout(probe, label) {
|
||||
const { roster, panelBounds } = probe;
|
||||
assert(boundsInside(roster.listBounds, panelBounds), `Expected roster rows on page ${label} inside the side panel: ${JSON.stringify(probe)}`);
|
||||
assert(boundsInside(roster.navigationBounds, panelBounds), `Expected roster navigation on page ${label} inside the side panel: ${JSON.stringify(probe)}`);
|
||||
assert(boundsInside(roster.messageBounds, panelBounds), `Expected roster guidance on page ${label} inside the side panel: ${JSON.stringify(probe)}`);
|
||||
assert(
|
||||
roster.rowLayouts.length === roster.visibleUnitIds.length &&
|
||||
roster.rowLayouts.every((row) =>
|
||||
boundsInside(row.rowBounds, roster.listBounds) &&
|
||||
boundsInside(row.nameBounds, row.rowBounds) &&
|
||||
boundsInside(row.metaBounds, row.rowBounds) &&
|
||||
boundsInside(row.hpBounds, row.rowBounds) &&
|
||||
boundsInside(row.gaugeBounds, row.rowBounds) &&
|
||||
row.nameBounds.x + row.nameBounds.width <= row.hpBounds.x &&
|
||||
row.metaBounds.x + row.metaBounds.width <= row.gaugeBounds.x
|
||||
),
|
||||
`Expected roster page ${label} names, classes, HP, and gauges to remain in separate columns: ${JSON.stringify(probe)}`
|
||||
);
|
||||
assert(
|
||||
roster.listBounds.y + roster.listBounds.height <= roster.navigationBounds.y &&
|
||||
roster.navigationBounds.y + roster.navigationBounds.height <= roster.messageBounds.y &&
|
||||
|
||||
Reference in New Issue
Block a user