fix: harden campaign resume UX and flow verification
This commit is contained in:
@@ -6389,7 +6389,8 @@ try {
|
||||
gold: 9800,
|
||||
turnNumber: 18,
|
||||
defeatedEnemies: 20,
|
||||
selectedSortieUnitIds: ['zhuge-liang', 'jiang-wei', 'wang-ping', 'ma-dai', 'huang-quan', 'li-yan', 'wei-yan']
|
||||
selectedSortieUnitIds: ['zhuge-liang', 'jiang-wei', 'wang-ping', 'ma-dai', 'huang-quan', 'li-yan', 'wei-yan'],
|
||||
pendingVictoryRewardNotice: true
|
||||
});
|
||||
await page.reload({ waitUntil: 'domcontentloaded' });
|
||||
await waitForTitle(page);
|
||||
@@ -6397,6 +6398,11 @@ try {
|
||||
await waitForCamp(page);
|
||||
await waitForCampSkinTransition(page, 'northern');
|
||||
await waitForCampSoundscapeTransition(page, 'camp-frontier', 'mountain-wind-ambience');
|
||||
await page.waitForFunction(
|
||||
() => window.__HEROS_DEBUG__?.camp()?.victoryRewardAcknowledgement?.visible === true,
|
||||
undefined,
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
const finalCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
assert(finalCampState?.campaign?.step === 'sixty-sixth-camp', `Expected final camp save to continue: ${JSON.stringify(finalCampState)}`);
|
||||
assertCampSkinState(finalCampState, 'northern', 'final camp');
|
||||
@@ -6420,29 +6426,61 @@ try {
|
||||
Array.isArray(finalCampState.sortieDeploymentPreview) && finalCampState.sortieDeploymentPreview.length === 0,
|
||||
`Expected final camp deployment preview to stay empty: ${JSON.stringify(finalCampState?.sortieDeploymentPreview)}`
|
||||
);
|
||||
if (finalCampState.victoryRewardAcknowledgement?.visible === true) {
|
||||
const finalCampRewardSaveBeforeClose = await readCampaignSave(page);
|
||||
const finalCampRewardClosePoint = await readCampVictoryRewardControlPoint(page, 'close');
|
||||
await page.mouse.click(finalCampRewardClosePoint.x, finalCampRewardClosePoint.y);
|
||||
await page.waitForFunction(
|
||||
() => window.__HEROS_DEBUG__?.camp()?.victoryRewardAcknowledgement?.visible === false,
|
||||
undefined,
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
const finalCampAfterRewardClose = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
const finalCampRewardSaveAfterClose = await readCampaignSave(page);
|
||||
assert(
|
||||
sameJsonValue(finalCampRewardSaveAfterClose, finalCampRewardSaveBeforeClose) &&
|
||||
finalCampAfterRewardClose?.campTabs?.find((tab) => tab.id === 'equipment')?.newBadgeVisible === true &&
|
||||
finalCampAfterRewardClose?.campTabs?.find((tab) => tab.id === 'supplies')?.newBadgeVisible === true,
|
||||
`Expected closing the final-camp reward notice to preserve its destination-specific NEW states: ${JSON.stringify({
|
||||
saveUnchanged: sameJsonValue(finalCampRewardSaveAfterClose, finalCampRewardSaveBeforeClose),
|
||||
tabs: finalCampAfterRewardClose?.campTabs
|
||||
?.filter((tab) => ['equipment', 'supplies'].includes(tab.id))
|
||||
.map((tab) => ({ id: tab.id, new: tab.newBadgeVisible }))
|
||||
})}`
|
||||
);
|
||||
}
|
||||
assert(
|
||||
finalCampState.victoryRewardAcknowledgement?.visible === true &&
|
||||
finalCampState.victoryRewardAcknowledgement?.battleId === 'sixty-sixth-battle-wuzhang-final',
|
||||
`Expected the seeded final victory to expose its undismissed reward notice: ${JSON.stringify(finalCampState.victoryRewardAcknowledgement)}`
|
||||
);
|
||||
const finalCampRewardSaveBeforeClose = await readCampaignSave(page);
|
||||
const finalCampRewardClosePoint = await readCampVictoryRewardControlPoint(page, 'close');
|
||||
await page.mouse.click(finalCampRewardClosePoint.x, finalCampRewardClosePoint.y);
|
||||
await page.waitForFunction(
|
||||
() => window.__HEROS_DEBUG__?.camp()?.victoryRewardAcknowledgement?.visible === false,
|
||||
undefined,
|
||||
{ timeout: 30000 }
|
||||
);
|
||||
const finalCampAfterRewardClose = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
const finalCampRewardSaveAfterClose = await readCampaignSave(page);
|
||||
const finalBattleId = 'sixty-sixth-battle-wuzhang-final';
|
||||
assert(
|
||||
sameJsonValue(
|
||||
campaignSaveWithoutVictoryRewardNoticeDismissals(finalCampRewardSaveAfterClose),
|
||||
campaignSaveWithoutVictoryRewardNoticeDismissals(finalCampRewardSaveBeforeClose)
|
||||
) &&
|
||||
sameJsonValue(
|
||||
campaignVictoryAcknowledgementSnapshot(finalCampRewardSaveAfterClose, finalBattleId),
|
||||
campaignVictoryAcknowledgementSnapshot(finalCampRewardSaveBeforeClose, finalBattleId)
|
||||
) &&
|
||||
campaignVictoryNoticeDismissalSnapshot(finalCampRewardSaveBeforeClose, finalBattleId).current === false &&
|
||||
campaignVictoryNoticeDismissalSnapshot(finalCampRewardSaveBeforeClose, finalBattleId).slot1 === false &&
|
||||
campaignVictoryNoticeDismissalSnapshot(finalCampRewardSaveAfterClose, finalBattleId).current === true &&
|
||||
campaignVictoryNoticeDismissalSnapshot(finalCampRewardSaveAfterClose, finalBattleId).slot1 === true &&
|
||||
finalCampAfterRewardClose?.campTabs?.find((tab) => tab.id === 'equipment')?.newBadgeVisible === true &&
|
||||
finalCampAfterRewardClose?.campTabs?.find((tab) => tab.id === 'supplies')?.newBadgeVisible === true,
|
||||
`Expected closing the final-camp reward notice to persist only its dismissal while preserving destination-specific NEW states: ${JSON.stringify({
|
||||
beforeDismissal: campaignVictoryNoticeDismissalSnapshot(finalCampRewardSaveBeforeClose, finalBattleId),
|
||||
afterDismissal: campaignVictoryNoticeDismissalSnapshot(finalCampRewardSaveAfterClose, finalBattleId),
|
||||
beforeAcknowledgement: campaignVictoryAcknowledgementSnapshot(finalCampRewardSaveBeforeClose, finalBattleId),
|
||||
afterAcknowledgement: campaignVictoryAcknowledgementSnapshot(finalCampRewardSaveAfterClose, finalBattleId),
|
||||
tabs: finalCampAfterRewardClose?.campTabs
|
||||
?.filter((tab) => ['equipment', 'supplies'].includes(tab.id))
|
||||
.map((tab) => ({ id: tab.id, new: tab.newBadgeVisible }))
|
||||
})}`
|
||||
);
|
||||
|
||||
await page.reload({ waitUntil: 'domcontentloaded' });
|
||||
await waitForTitle(page);
|
||||
await clickLegacyUi(page, 962, 310);
|
||||
await waitForCamp(page);
|
||||
await waitForCampSkinTransition(page, 'northern');
|
||||
const resumedFinalCampAfterRewardClose = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
assert(
|
||||
resumedFinalCampAfterRewardClose?.campaign?.step === 'sixty-sixth-camp' &&
|
||||
resumedFinalCampAfterRewardClose?.victoryRewardAcknowledgement?.visible === false &&
|
||||
resumedFinalCampAfterRewardClose?.campTabs?.find((tab) => tab.id === 'equipment')?.newBadgeVisible === true &&
|
||||
resumedFinalCampAfterRewardClose?.campTabs?.find((tab) => tab.id === 'supplies')?.newBadgeVisible === true,
|
||||
`Expected title continue to keep the dismissed reward notice closed without consuming NEW states: ${JSON.stringify(resumedFinalCampAfterRewardClose)}`
|
||||
);
|
||||
await captureStableCampScreenshot(page, `${screenshotDir}/rc-final-camp.png`, 0, 'final camp');
|
||||
await assertFinalCampRosterPagination(page);
|
||||
|
||||
@@ -9946,6 +9984,19 @@ async function seedCampaignSave(page, options) {
|
||||
reserveTraining: [],
|
||||
completedAt: now
|
||||
};
|
||||
const pendingVictoryRewardNotice = seed.pendingVictoryRewardNotice === true;
|
||||
const acknowledgedVictoryRewardCategories = {
|
||||
...(current.acknowledgedVictoryRewardCategories ?? {})
|
||||
};
|
||||
if (pendingVictoryRewardNotice) {
|
||||
delete acknowledgedVictoryRewardCategories[seed.battleId];
|
||||
}
|
||||
const previouslyRecordedVictoryBattleIds = Object.entries(current.battleHistory ?? {})
|
||||
.filter(([, settlement]) => settlement?.outcome === 'victory')
|
||||
.map(([battleId]) => battleId);
|
||||
if (current.firstBattleReport?.outcome === 'victory') {
|
||||
previouslyRecordedVictoryBattleIds.push(current.firstBattleReport.battleId);
|
||||
}
|
||||
const next = {
|
||||
...current,
|
||||
updatedAt: now,
|
||||
@@ -9956,9 +10007,18 @@ async function seedCampaignSave(page, options) {
|
||||
selectedSortieUnitIds: seed.selectedSortieUnitIds,
|
||||
latestBattleId: seed.battleId,
|
||||
firstBattleReport: report,
|
||||
acknowledgedVictoryRewardBattleIds: [
|
||||
...new Set([...(current.acknowledgedVictoryRewardBattleIds ?? []), seed.battleId])
|
||||
],
|
||||
acknowledgedVictoryRewardBattleIds: pendingVictoryRewardNotice
|
||||
? (current.acknowledgedVictoryRewardBattleIds ?? []).filter((battleId) => battleId !== seed.battleId)
|
||||
: [...new Set([...(current.acknowledgedVictoryRewardBattleIds ?? []), seed.battleId])],
|
||||
acknowledgedVictoryRewardCategories,
|
||||
dismissedVictoryRewardNoticeBattleIds: pendingVictoryRewardNotice
|
||||
? [
|
||||
...new Set([
|
||||
...(current.dismissedVictoryRewardNoticeBattleIds ?? []),
|
||||
...previouslyRecordedVictoryBattleIds.filter((battleId) => battleId !== seed.battleId)
|
||||
])
|
||||
].filter((battleId) => battleId !== seed.battleId)
|
||||
: [...(current.dismissedVictoryRewardNoticeBattleIds ?? [])],
|
||||
battleHistory: {
|
||||
...(current.battleHistory ?? {}),
|
||||
[seed.battleId]: settlement
|
||||
@@ -10259,6 +10319,32 @@ function campaignVictoryAcknowledgementSnapshot(save, battleId) {
|
||||
};
|
||||
}
|
||||
|
||||
function campaignVictoryNoticeDismissalSnapshot(save, battleId) {
|
||||
const stateSnapshot = (state) => (state?.dismissedVictoryRewardNoticeBattleIds ?? []).includes(battleId);
|
||||
return {
|
||||
current: stateSnapshot(save?.current),
|
||||
slot1: stateSnapshot(save?.slot1)
|
||||
};
|
||||
}
|
||||
|
||||
function campaignSaveWithoutVictoryRewardNoticeDismissals(save) {
|
||||
const stableState = (state) => {
|
||||
if (!state) {
|
||||
return state;
|
||||
}
|
||||
const {
|
||||
updatedAt: _updatedAt,
|
||||
dismissedVictoryRewardNoticeBattleIds: _dismissedVictoryRewardNoticeBattleIds,
|
||||
...stableFields
|
||||
} = state;
|
||||
return stableFields;
|
||||
};
|
||||
return {
|
||||
current: stableState(save?.current),
|
||||
slot1: stableState(save?.slot1)
|
||||
};
|
||||
}
|
||||
|
||||
function recommendationFeedbackSemantic(feedback) {
|
||||
if (!feedback) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user