feat: reopen formation reviews in camp
This commit is contained in:
@@ -217,6 +217,135 @@ try {
|
||||
`Expected campaign report debug state to retain first battle unlock reward: ${JSON.stringify(firstCampProbe.state?.report?.campaignRewards)}`
|
||||
);
|
||||
|
||||
const firstCampEvaluation = firstCampProbe.state?.reportFormationEvaluation;
|
||||
const firstCampEvaluationSaveBefore = await readCampaignSave(page);
|
||||
assert(
|
||||
firstCampEvaluation?.available === true &&
|
||||
firstCampEvaluation.open === false &&
|
||||
firstCampEvaluation.battleId === 'first-battle-zhuo-commandery' &&
|
||||
firstCampEvaluation.grade === firstResultState?.sortieEvaluation?.grade &&
|
||||
firstCampEvaluation.score === firstResultState?.sortieEvaluation?.score &&
|
||||
sameJsonValue(firstCampEvaluation.snapshot, firstResultPerformance) &&
|
||||
firstCampEvaluation.toggleButtonBounds,
|
||||
`Expected the first camp report to expose the persisted battle formation evaluation: ${JSON.stringify(firstCampEvaluation)}`
|
||||
);
|
||||
const firstCampEvaluationTogglePoint = await readCampReportFormationEvaluationControlPoint(page, 'toggle');
|
||||
await page.mouse.click(firstCampEvaluationTogglePoint.x, firstCampEvaluationTogglePoint.y);
|
||||
await page.waitForFunction(
|
||||
() => window.__HEROS_DEBUG__?.camp()?.reportFormationEvaluation?.open === true,
|
||||
undefined,
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
const firstCampEvaluationProbe = await page.evaluate(() => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('CampScene');
|
||||
return {
|
||||
evaluation: window.__HEROS_DEBUG__?.camp()?.reportFormationEvaluation,
|
||||
texts: (scene?.reportFormationReviewObjects ?? [])
|
||||
.filter((object) => object?.type === 'Text')
|
||||
.map((object) => object.text)
|
||||
};
|
||||
});
|
||||
const firstCampEvaluationSaveOpen = await readCampaignSave(page);
|
||||
assert(
|
||||
firstCampEvaluationProbe.evaluation?.open === true &&
|
||||
firstCampEvaluationProbe.texts.includes('최근 전투 편성 평가') &&
|
||||
firstCampEvaluationProbe.texts.some((text) => text.includes('명단·역할만 저장') && text.includes('장비·보급 제외')) &&
|
||||
firstCampEvaluationProbe.evaluation?.presetCards?.length === 3 &&
|
||||
firstCampEvaluationProbe.evaluation.presetCards.every(
|
||||
(card) => card.saved === false && card.matching === false && card.actionButtonBounds
|
||||
) &&
|
||||
sameJsonValue(firstCampEvaluationSaveOpen, firstCampEvaluationSaveBefore),
|
||||
`Expected reopening the first camp formation evaluation to remain non-destructive and show three empty preset actions: ${JSON.stringify(firstCampEvaluationProbe)}`
|
||||
);
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-first-camp-formation-evaluation.png`, fullPage: true });
|
||||
await assertCanvasPainted(page, 'first camp formation evaluation');
|
||||
const firstCampEvaluationClosePoint = await readCampReportFormationEvaluationControlPoint(page, 'close');
|
||||
await page.mouse.click(firstCampEvaluationClosePoint.x, firstCampEvaluationClosePoint.y);
|
||||
await page.waitForFunction(
|
||||
() => window.__HEROS_DEBUG__?.camp()?.reportFormationEvaluation?.open === false,
|
||||
undefined,
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
|
||||
const firstCampSupplyMutationFixture = await page.evaluate(() => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('CampScene');
|
||||
const state = window.__HEROS_DEBUG__?.camp();
|
||||
const campaign = scene?.campaign;
|
||||
const report = scene?.report;
|
||||
const targetId = state?.reportFormationEvaluation?.snapshot?.selectedUnitIds?.find((unitId) =>
|
||||
campaign?.roster?.some((unit) => unit.id === unitId)
|
||||
);
|
||||
const target = campaign?.roster?.find((unit) => unit.id === targetId);
|
||||
const reportUnit = report?.units?.find((unit) => unit.id === targetId && unit.faction === 'ally');
|
||||
const settlementUnit = campaign?.battleHistory?.[report?.battleId]?.units?.find((unit) => unit.unitId === targetId);
|
||||
if (!scene || !campaign || !report || !target || !reportUnit || !settlementUnit || typeof scene.render !== 'function') {
|
||||
return { ready: false, targetId: targetId ?? null };
|
||||
}
|
||||
|
||||
const beanBefore = campaign.inventory?.['콩'] ?? 0;
|
||||
target.hp = Math.max(1, target.maxHp - 12);
|
||||
reportUnit.hp = target.hp;
|
||||
campaign.inventory['콩'] = beanBefore + 1;
|
||||
scene.selectedUnitId = target.id;
|
||||
scene.render();
|
||||
return {
|
||||
ready: true,
|
||||
targetId: target.id,
|
||||
woundedHp: target.hp,
|
||||
maxHp: target.maxHp,
|
||||
settlementHp: settlementUnit.hp,
|
||||
beanBefore
|
||||
};
|
||||
});
|
||||
assert(
|
||||
firstCampSupplyMutationFixture.ready === true &&
|
||||
firstCampSupplyMutationFixture.targetId &&
|
||||
firstCampSupplyMutationFixture.woundedHp < firstCampSupplyMutationFixture.maxHp,
|
||||
`Expected a deterministic wounded report-unit fixture for camp supply recovery: ${JSON.stringify(firstCampSupplyMutationFixture)}`
|
||||
);
|
||||
await page.mouse.click(798, 38);
|
||||
await page.waitForFunction(
|
||||
() => window.__HEROS_DEBUG__?.camp()?.activeTab === 'supplies',
|
||||
undefined,
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
const firstCampUseSupplyPoint = await readCampContentTextControlPoint(page, '사용', 0);
|
||||
await page.mouse.click(firstCampUseSupplyPoint.x, firstCampUseSupplyPoint.y);
|
||||
await page.waitForFunction((fixture) => {
|
||||
const state = window.__HEROS_DEBUG__?.camp();
|
||||
const target = state?.campaign?.roster?.find((unit) => unit.id === fixture.targetId);
|
||||
return target?.hp === fixture.maxHp;
|
||||
}, firstCampSupplyMutationFixture, { timeout: 30000 });
|
||||
const firstCampAfterSupplyProbe = await page.evaluate((fixture) => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('CampScene');
|
||||
const state = window.__HEROS_DEBUG__?.camp();
|
||||
const report = scene?.report;
|
||||
const settlement = scene?.campaign?.battleHistory?.[report?.battleId];
|
||||
return {
|
||||
evaluation: state?.reportFormationEvaluation,
|
||||
rosterHp: state?.campaign?.roster?.find((unit) => unit.id === fixture.targetId)?.hp ?? null,
|
||||
reportHp: report?.units?.find((unit) => unit.id === fixture.targetId && unit.faction === 'ally')?.hp ?? null,
|
||||
settlementHp: settlement?.units?.find((unit) => unit.unitId === fixture.targetId)?.hp ?? null,
|
||||
beanAmount: state?.campaign?.inventory?.['콩'] ?? 0
|
||||
};
|
||||
}, firstCampSupplyMutationFixture);
|
||||
assert(
|
||||
firstCampAfterSupplyProbe.rosterHp === firstCampSupplyMutationFixture.maxHp &&
|
||||
firstCampAfterSupplyProbe.reportHp === firstCampSupplyMutationFixture.maxHp &&
|
||||
firstCampAfterSupplyProbe.settlementHp === firstCampSupplyMutationFixture.settlementHp &&
|
||||
firstCampAfterSupplyProbe.beanAmount === firstCampSupplyMutationFixture.beanBefore &&
|
||||
firstCampAfterSupplyProbe.evaluation?.grade === firstCampEvaluation.grade &&
|
||||
firstCampAfterSupplyProbe.evaluation?.score === firstCampEvaluation.score &&
|
||||
firstCampAfterSupplyProbe.evaluation?.survivorCount === firstCampEvaluation.survivorCount &&
|
||||
firstCampAfterSupplyProbe.evaluation?.recoveryNeededCount === firstCampEvaluation.recoveryNeededCount &&
|
||||
sameJsonValue(firstCampAfterSupplyProbe.evaluation?.snapshot, firstCampEvaluation.snapshot),
|
||||
`Expected camp supply use to update report HP without rewriting the settlement-backed formation evaluation: ${JSON.stringify({
|
||||
before: firstCampEvaluation,
|
||||
fixture: firstCampSupplyMutationFixture,
|
||||
after: firstCampAfterSupplyProbe
|
||||
})}`
|
||||
);
|
||||
|
||||
const firstCampSelectedSortieUnitIds = firstCampProbe.state?.selectedSortieUnitIds ?? [];
|
||||
const firstCampDeploymentPreview = firstCampProbe.state?.sortieDeploymentPreview ?? [];
|
||||
await page.mouse.click(1160, 38);
|
||||
@@ -1008,6 +1137,44 @@ try {
|
||||
})}`
|
||||
);
|
||||
|
||||
const openPresetBookForSiegeFixturePoint = await readSortiePresetControlPoint(page, 'toggle');
|
||||
await page.mouse.click(openPresetBookForSiegeFixturePoint.x, openPresetBookForSiegeFixturePoint.y);
|
||||
await page.waitForFunction(
|
||||
() => window.__HEROS_DEBUG__?.camp()?.sortiePresetBrowser?.open === true,
|
||||
undefined,
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
const saveSiegePresetPoint = await readSortiePresetControlPoint(page, 'save', 'siege');
|
||||
await page.mouse.click(saveSiegePresetPoint.x, saveSiegePresetPoint.y);
|
||||
await page.waitForFunction(() => {
|
||||
const state = window.__HEROS_DEBUG__?.camp();
|
||||
return state?.sortiePresetBrowser?.open === true &&
|
||||
state?.sortieFormationPresets?.siege?.selectedUnitIds?.length > 0;
|
||||
}, undefined, { timeout: 30000 });
|
||||
const savedSiegeFixtureState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
const savedSiegeFixtureSave = await readCampaignSave(page);
|
||||
const savedSiegePreset = savedSiegeFixtureState?.sortieFormationPresets?.siege;
|
||||
assert(
|
||||
savedSiegePreset?.selectedUnitIds?.length === savedSiegeFixtureState?.selectedSortieUnitIds?.length &&
|
||||
savedSiegePreset.selectedUnitIds.every((unitId) => Boolean(savedSiegePreset.formationAssignments?.[unitId])) &&
|
||||
JSON.stringify(Object.keys(savedSiegePreset).sort()) === JSON.stringify(['formationAssignments', 'selectedUnitIds']) &&
|
||||
savedSiegePreset.sortieItemAssignments === undefined &&
|
||||
savedSiegePreset.itemAssignments === undefined &&
|
||||
sameJsonValue(savedSiegeFixtureSave.current?.sortieFormationPresets?.siege, savedSiegePreset) &&
|
||||
sameJsonValue(savedSiegeFixtureSave.slot1?.sortieFormationPresets?.siege, savedSiegePreset),
|
||||
`Expected a deterministic pre-battle siege preset fixture containing only the current roster and roles: ${JSON.stringify({
|
||||
state: savedSiegeFixtureState,
|
||||
save: savedSiegeFixtureSave
|
||||
})}`
|
||||
);
|
||||
const closePresetBookAfterSiegeFixturePoint = await readSortiePresetControlPoint(page, 'close');
|
||||
await page.mouse.click(closePresetBookAfterSiegeFixturePoint.x, closePresetBookAfterSiegeFixturePoint.y);
|
||||
await page.waitForFunction(
|
||||
() => window.__HEROS_DEBUG__?.camp()?.sortiePresetBrowser?.open === false,
|
||||
undefined,
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
|
||||
const midFormationFirstPage = await page.evaluate(() => window.__HEROS_DEBUG__?.camp()?.sortiePortraitRosterView);
|
||||
await page.mouse.click(658, 196);
|
||||
await page.waitForFunction((previousScroll) => {
|
||||
@@ -1363,6 +1530,146 @@ try {
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-mid-camp-formation-evaluation-updated.png`, fullPage: true });
|
||||
await assertCanvasPainted(page, 'mid camp formation evaluation update');
|
||||
|
||||
const closeMidBattleEvaluationPoint = await readBattleResultEvaluationControlPoint(page, 'close');
|
||||
await page.mouse.click(closeMidBattleEvaluationPoint.x, closeMidBattleEvaluationPoint.y);
|
||||
await page.waitForFunction(
|
||||
() => window.__HEROS_DEBUG__?.battle()?.sortieEvaluation?.open === false,
|
||||
undefined,
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
await page.mouse.click(738, 642);
|
||||
await waitForCampAfterBattleResult(page);
|
||||
|
||||
const midCampReviewState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
const midCampReviewSaveBefore = await readCampaignSave(page);
|
||||
const midCampFormationEvaluation = midCampReviewState?.reportFormationEvaluation;
|
||||
const midCampSiegeCard = midCampFormationEvaluation?.presetCards?.find((card) => card.id === 'siege');
|
||||
assert(
|
||||
midCampFormationEvaluation?.available === true &&
|
||||
midCampFormationEvaluation.open === false &&
|
||||
midCampFormationEvaluation.battleId === midCampNextBattleId &&
|
||||
midCampFormationEvaluation.grade === updatedMobileResultState?.sortieEvaluation?.grade &&
|
||||
midCampFormationEvaluation.score === updatedMobileResultState?.sortieEvaluation?.score &&
|
||||
sameJsonValue(midCampFormationEvaluation.snapshot, midResultPerformance) &&
|
||||
midCampFormationEvaluation.sourcePresetIds?.includes('mobile') === true &&
|
||||
midCampFormationEvaluation.sourcePresetIds?.includes('siege') === false &&
|
||||
midCampSiegeCard?.saved === true &&
|
||||
midCampSiegeCard.matching === false &&
|
||||
midCampFormationEvaluation.toggleButtonBounds &&
|
||||
!sameJsonValue(savedSiegePreset, expectedMidResultPreset),
|
||||
`Expected the next camp report to reopen the persisted result while keeping the older siege preset distinct: ${JSON.stringify({
|
||||
evaluation: midCampFormationEvaluation,
|
||||
savedSiegePreset
|
||||
})}`
|
||||
);
|
||||
|
||||
const midCampReviewTogglePoint = await readCampReportFormationEvaluationControlPoint(page, 'toggle');
|
||||
await page.mouse.click(midCampReviewTogglePoint.x, midCampReviewTogglePoint.y);
|
||||
await page.waitForFunction(
|
||||
() => window.__HEROS_DEBUG__?.camp()?.reportFormationEvaluation?.open === true,
|
||||
undefined,
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
const openedMidCampReviewProbe = await page.evaluate(() => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('CampScene');
|
||||
return {
|
||||
state: window.__HEROS_DEBUG__?.camp(),
|
||||
texts: (scene?.reportFormationReviewObjects ?? [])
|
||||
.filter((object) => object?.type === 'Text')
|
||||
.map((object) => object.text)
|
||||
};
|
||||
});
|
||||
const openedMidCampReviewSave = await readCampaignSave(page);
|
||||
const openedMidCampSiegeCard = openedMidCampReviewProbe.state?.reportFormationEvaluation?.presetCards?.find(
|
||||
(card) => card.id === 'siege'
|
||||
);
|
||||
assert(
|
||||
openedMidCampReviewProbe.state?.reportFormationEvaluation?.open === true &&
|
||||
openedMidCampReviewProbe.texts.includes('최근 전투 편성 평가') &&
|
||||
openedMidCampReviewProbe.texts.some((text) => text.includes('공성') && text.includes('갱신')) &&
|
||||
openedMidCampSiegeCard?.saved === true &&
|
||||
openedMidCampSiegeCard.matching === false &&
|
||||
openedMidCampSiegeCard.actionButtonBounds &&
|
||||
sameJsonValue(openedMidCampReviewSave, midCampReviewSaveBefore),
|
||||
`Expected opening the camp report evaluation to remain non-destructive and expose the siege update action: ${JSON.stringify(openedMidCampReviewProbe)}`
|
||||
);
|
||||
|
||||
const firstCampSiegeUpdatePoint = await readCampReportFormationEvaluationControlPoint(page, 'preset', 'siege');
|
||||
await page.mouse.click(firstCampSiegeUpdatePoint.x, firstCampSiegeUpdatePoint.y);
|
||||
await page.waitForFunction(() => {
|
||||
const evaluation = window.__HEROS_DEBUG__?.camp()?.reportFormationEvaluation;
|
||||
return evaluation?.open === true &&
|
||||
evaluation?.overwriteConfirmId === 'siege' &&
|
||||
evaluation?.feedback?.includes('한 번 더');
|
||||
}, undefined, { timeout: 30000 });
|
||||
const pendingCampSiegeUpdateState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
const pendingCampSiegeUpdateSave = await readCampaignSave(page);
|
||||
assert(
|
||||
pendingCampSiegeUpdateState?.reportFormationEvaluation?.sourcePresetIds?.includes('siege') === false &&
|
||||
pendingCampSiegeUpdateState?.reportFormationEvaluation?.presetCards?.find((card) => card.id === 'siege')?.matching === false &&
|
||||
sameJsonValue(pendingCampSiegeUpdateSave, midCampReviewSaveBefore),
|
||||
`Expected the first camp siege update click to request confirmation without mutating either save: ${JSON.stringify({
|
||||
evaluation: pendingCampSiegeUpdateState?.reportFormationEvaluation,
|
||||
save: pendingCampSiegeUpdateSave
|
||||
})}`
|
||||
);
|
||||
|
||||
const confirmCampSiegeUpdatePoint = await readCampReportFormationEvaluationControlPoint(page, 'preset', 'siege');
|
||||
await page.mouse.click(confirmCampSiegeUpdatePoint.x, confirmCampSiegeUpdatePoint.y);
|
||||
await page.waitForFunction(() => {
|
||||
const evaluation = window.__HEROS_DEBUG__?.camp()?.reportFormationEvaluation;
|
||||
return evaluation?.open === true &&
|
||||
evaluation?.overwriteConfirmId === null &&
|
||||
evaluation?.sourcePresetIds?.includes('siege') &&
|
||||
evaluation?.feedback?.includes('갱신 완료');
|
||||
}, undefined, { timeout: 30000 });
|
||||
const updatedCampSiegeState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
const updatedCampSiegeSave = await readCampaignSave(page);
|
||||
const updatedCurrentSiegePreset = updatedCampSiegeSave.current?.sortieFormationPresets?.siege;
|
||||
const updatedSlotSiegePreset = updatedCampSiegeSave.slot1?.sortieFormationPresets?.siege;
|
||||
assert(
|
||||
sameJsonValue(updatedCurrentSiegePreset, expectedMidResultPreset) &&
|
||||
sameJsonValue(updatedSlotSiegePreset, expectedMidResultPreset) &&
|
||||
JSON.stringify(Object.keys(updatedCurrentSiegePreset ?? {}).sort()) === JSON.stringify(['formationAssignments', 'selectedUnitIds']) &&
|
||||
updatedCurrentSiegePreset?.sortieItemAssignments === undefined &&
|
||||
updatedCurrentSiegePreset?.itemAssignments === undefined &&
|
||||
updatedCurrentSiegePreset?.unitStats === undefined,
|
||||
`Expected the confirmed camp action to store only the reviewed roster and roles in both siege preset saves: ${JSON.stringify(updatedCampSiegeSave)}`
|
||||
);
|
||||
assert(
|
||||
JSON.stringify(updatedCampSiegeSave.current?.selectedSortieUnitIds) === JSON.stringify(midCampReviewSaveBefore.current?.selectedSortieUnitIds) &&
|
||||
sameJsonValue(updatedCampSiegeSave.current?.sortieFormationAssignments, midCampReviewSaveBefore.current?.sortieFormationAssignments) &&
|
||||
sameJsonValue(updatedCampSiegeSave.current?.sortieItemAssignments, midCampReviewSaveBefore.current?.sortieItemAssignments) &&
|
||||
JSON.stringify(updatedCampSiegeSave.slot1?.selectedSortieUnitIds) === JSON.stringify(midCampReviewSaveBefore.slot1?.selectedSortieUnitIds) &&
|
||||
sameJsonValue(updatedCampSiegeSave.slot1?.sortieFormationAssignments, midCampReviewSaveBefore.slot1?.sortieFormationAssignments) &&
|
||||
sameJsonValue(updatedCampSiegeSave.slot1?.sortieItemAssignments, midCampReviewSaveBefore.slot1?.sortieItemAssignments) &&
|
||||
sameJsonValue(updatedCampSiegeSave.current?.firstBattleReport?.sortiePerformance, midResultPerformance) &&
|
||||
sameJsonValue(updatedCampSiegeSave.slot1?.battleHistory?.[midCampNextBattleId]?.sortiePerformance, midResultPerformance) &&
|
||||
sameJsonValue(updatedCampSiegeSave.current?.sortieFormationPresets?.mobile, midCampReviewSaveBefore.current?.sortieFormationPresets?.mobile) &&
|
||||
sameJsonValue(updatedCampSiegeSave.current?.sortieFormationPresets?.elite, midCampReviewSaveBefore.current?.sortieFormationPresets?.elite) &&
|
||||
JSON.stringify(updatedCampSiegeState?.selectedSortieUnitIds) === JSON.stringify(midCampReviewState?.selectedSortieUnitIds) &&
|
||||
sameJsonValue(updatedCampSiegeState?.sortieFormationAssignments, midCampReviewState?.sortieFormationAssignments) &&
|
||||
sameJsonValue(updatedCampSiegeState?.sortieItemAssignments, midCampReviewState?.sortieItemAssignments),
|
||||
`Expected the camp review update to preserve the active sortie, supplies, report snapshot, and other presets: ${JSON.stringify({
|
||||
before: midCampReviewSaveBefore,
|
||||
after: updatedCampSiegeSave
|
||||
})}`
|
||||
);
|
||||
assert(
|
||||
updatedCampSiegeState?.reportFormationEvaluation?.presetCards?.find((card) => card.id === 'siege')?.matching === true &&
|
||||
updatedCampSiegeState?.reportFormationEvaluation?.feedback?.includes('장비·보급은 저장하지 않았습니다.'),
|
||||
`Expected visible completion feedback and a matching siege card after the camp update: ${JSON.stringify(updatedCampSiegeState?.reportFormationEvaluation)}`
|
||||
);
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-mid-camp-report-formation-evaluation-updated.png`, fullPage: true });
|
||||
await assertCanvasPainted(page, 'mid camp report formation evaluation update');
|
||||
const closeUpdatedCampReviewPoint = await readCampReportFormationEvaluationControlPoint(page, 'close');
|
||||
await page.mouse.click(closeUpdatedCampReviewPoint.x, closeUpdatedCampReviewPoint.y);
|
||||
await page.waitForFunction(
|
||||
() => window.__HEROS_DEBUG__?.camp()?.reportFormationEvaluation?.open === false,
|
||||
undefined,
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
|
||||
await seedCampaignSave(page, {
|
||||
battleId: 'sixty-sixth-battle-wuzhang-final',
|
||||
battleTitle: '오장원 최종전',
|
||||
@@ -1381,6 +1688,13 @@ try {
|
||||
assert(finalCampState.sortieHasBattle === false, `Expected final camp to expose no playable sortie target: ${JSON.stringify(finalCampState)}`);
|
||||
assert(finalCampState.stagedSortiePrep === false, `Expected the non-battle final camp to avoid the three-stage sortie flow: ${JSON.stringify(finalCampState)}`);
|
||||
assert(finalCampState.nextSortieBattleId === null, `Expected final camp to route to ending instead of a battle: ${JSON.stringify(finalCampState)}`);
|
||||
assert(
|
||||
finalCampState.reportFormationEvaluation?.available === false &&
|
||||
finalCampState.reportFormationEvaluation.open === false &&
|
||||
finalCampState.reportFormationEvaluation.toggleButtonBounds === null &&
|
||||
finalCampState.reportFormationEvaluation.presetCards?.length === 0,
|
||||
`Expected a latest report without sortie performance to hide the camp evaluation instead of falling back to older history: ${JSON.stringify(finalCampState.reportFormationEvaluation)}`
|
||||
);
|
||||
assert(
|
||||
Array.isArray(finalCampState.sortieDeploymentPreview) && finalCampState.sortieDeploymentPreview.length === 0,
|
||||
`Expected final camp deployment preview to stay empty: ${JSON.stringify(finalCampState?.sortieDeploymentPreview)}`
|
||||
@@ -1723,6 +2037,80 @@ async function readBattleResultEvaluationControlPoint(page, control, presetId) {
|
||||
return probe;
|
||||
}
|
||||
|
||||
async function readCampReportFormationEvaluationControlPoint(page, control, presetId) {
|
||||
const probe = await page.evaluate(({ control, presetId }) => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('CampScene');
|
||||
const evaluation = window.__HEROS_DEBUG__?.camp()?.reportFormationEvaluation;
|
||||
const canvas = document.querySelector('canvas');
|
||||
const presetCard = evaluation?.presetCards?.find((card) => card.id === presetId);
|
||||
const bounds = control === 'toggle'
|
||||
? evaluation?.toggleButtonBounds
|
||||
: control === 'close'
|
||||
? evaluation?.closeButtonBounds
|
||||
: presetCard?.actionButtonBounds;
|
||||
if (!scene || !canvas || !bounds) {
|
||||
return {
|
||||
ready: false,
|
||||
control,
|
||||
presetId: presetId ?? null,
|
||||
evaluationOpen: evaluation?.open ?? false,
|
||||
bounds: bounds ?? null
|
||||
};
|
||||
}
|
||||
|
||||
const canvasBounds = canvas.getBoundingClientRect();
|
||||
const centerX = bounds.x + bounds.width / 2;
|
||||
const centerY = bounds.y + bounds.height / 2;
|
||||
return {
|
||||
ready: true,
|
||||
control,
|
||||
presetId: presetId ?? null,
|
||||
evaluationOpen: evaluation?.open ?? false,
|
||||
bounds,
|
||||
x: canvasBounds.left + centerX * canvasBounds.width / scene.scale.width,
|
||||
y: canvasBounds.top + centerY * canvasBounds.height / scene.scale.height
|
||||
};
|
||||
}, { control, presetId });
|
||||
assert(
|
||||
probe.ready === true && Number.isFinite(probe.x) && Number.isFinite(probe.y),
|
||||
`Expected a visible Phaser camp-report evaluation ${control} control with a canvas-scaled click point: ${JSON.stringify(probe)}`
|
||||
);
|
||||
return probe;
|
||||
}
|
||||
|
||||
async function readCampContentTextControlPoint(page, label, occurrence = 0) {
|
||||
const probe = await page.evaluate(({ label, occurrence }) => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('CampScene');
|
||||
const canvas = document.querySelector('canvas');
|
||||
const candidates = (scene?.contentObjects ?? [])
|
||||
.filter((object) => object?.type === 'Text' && object?.text === label && object?.active && object?.visible)
|
||||
.sort((left, right) => left.y - right.y || left.x - right.x);
|
||||
const target = candidates[occurrence];
|
||||
if (!scene || !canvas || !target) {
|
||||
return { ready: false, label, occurrence, candidateCount: candidates.length };
|
||||
}
|
||||
|
||||
const bounds = target.getBounds();
|
||||
const canvasBounds = canvas.getBoundingClientRect();
|
||||
const centerX = bounds.x + bounds.width / 2;
|
||||
const centerY = bounds.y + bounds.height / 2;
|
||||
return {
|
||||
ready: true,
|
||||
label,
|
||||
occurrence,
|
||||
candidateCount: candidates.length,
|
||||
bounds: { x: bounds.x, y: bounds.y, width: bounds.width, height: bounds.height },
|
||||
x: canvasBounds.left + centerX * canvasBounds.width / scene.scale.width,
|
||||
y: canvasBounds.top + centerY * canvasBounds.height / scene.scale.height
|
||||
};
|
||||
}, { label, occurrence });
|
||||
assert(
|
||||
probe.ready === true && Number.isFinite(probe.x) && Number.isFinite(probe.y),
|
||||
`Expected a visible Phaser camp text control "${label}" with a canvas-scaled click point: ${JSON.stringify(probe)}`
|
||||
);
|
||||
return probe;
|
||||
}
|
||||
|
||||
async function readSortieComparisonActionPoint(page) {
|
||||
const probe = await page.evaluate(() => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('CampScene');
|
||||
|
||||
Reference in New Issue
Block a user