Polish release candidate QA flow
This commit is contained in:
@@ -404,10 +404,7 @@ try {
|
||||
await page.screenshot({ path: 'dist/verification-battle-result-victory.png', fullPage: true });
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
await page.screenshot({ path: 'dist/verification-camp.png', fullPage: true });
|
||||
|
||||
const campState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
@@ -561,10 +558,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const campaignSaveAfterSecondBattle = await page.evaluate(() => {
|
||||
const raw = window.localStorage.getItem('heros-web:campaign-state');
|
||||
@@ -631,10 +625,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const campaignSaveAfterThirdBattle = await page.evaluate(() => {
|
||||
const raw = window.localStorage.getItem('heros-web:campaign-state');
|
||||
@@ -700,10 +691,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const campaignSaveAfterFourthBattle = await page.evaluate(() => {
|
||||
const raw = window.localStorage.getItem('heros-web:campaign-state');
|
||||
@@ -769,10 +757,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const campaignSaveAfterFifthBattle = await page.evaluate(() => {
|
||||
const raw = window.localStorage.getItem('heros-web:campaign-state');
|
||||
@@ -848,10 +833,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const campaignSaveAfterSixthBattle = await page.evaluate(() => {
|
||||
const raw = window.localStorage.getItem('heros-web:campaign-state');
|
||||
@@ -947,10 +929,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const campaignSaveAfterSeventhBattle = await page.evaluate(() => {
|
||||
const raw = window.localStorage.getItem('heros-web:campaign-state');
|
||||
@@ -1040,10 +1019,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const eighthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -1121,10 +1097,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const ninthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -1202,10 +1175,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const tenthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -1276,10 +1246,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const eleventhCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -1351,10 +1318,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const twelfthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -1435,10 +1399,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const thirteenthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -1518,10 +1479,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fourteenthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -1593,10 +1551,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fifteenthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -1695,10 +1650,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const sixteenthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -1806,10 +1758,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const seventeenthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -1934,10 +1883,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const eighteenthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -2087,10 +2033,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const nineteenthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -2222,10 +2165,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const twentiethCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -2359,10 +2299,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const twentyFirstCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -2496,10 +2433,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const twentySecondCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -2636,10 +2570,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const twentyThirdCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -2777,10 +2708,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const twentyFourthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -2919,10 +2847,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const twentyFifthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -3067,10 +2992,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const twentySixthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -3211,10 +3133,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const twentySeventhCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -3355,10 +3274,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const twentyEighthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -3505,10 +3421,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const twentyNinthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -3649,10 +3562,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const thirtiethCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -3802,10 +3712,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const thirtyFirstCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -3952,10 +3859,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const thirtySecondCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -4103,10 +4007,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const thirtyThirdCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -4259,10 +4160,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const thirtyFourthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -4412,10 +4310,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const thirtyFifthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -4571,10 +4466,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const thirtySixthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -4722,10 +4614,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const thirtySeventhCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -4782,10 +4671,7 @@ try {
|
||||
await page.keyboard.press('Space');
|
||||
await page.waitForTimeout(320);
|
||||
}
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene') && !activeScenes.includes('StoryScene');
|
||||
});
|
||||
await waitForCampReady(page, { withoutStory: true });
|
||||
|
||||
const hanzhongKingCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -4839,10 +4725,7 @@ try {
|
||||
await page.keyboard.press('Space');
|
||||
await page.waitForTimeout(320);
|
||||
}
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene') && !activeScenes.includes('StoryScene');
|
||||
});
|
||||
await waitForCampReady(page, { withoutStory: true });
|
||||
|
||||
const shuHanFoundationCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -4986,10 +4869,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const thirtyEighthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -5136,10 +5016,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const thirtyNinthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -5286,10 +5163,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fortiethCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -5437,10 +5311,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fortyFirstCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -5592,10 +5463,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fortySecondCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -5748,10 +5616,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fortyThirdCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -5903,10 +5768,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fortyFourthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -6057,10 +5919,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fortyFifthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -6212,10 +6071,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fortySixthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -6273,11 +6129,7 @@ try {
|
||||
await page.keyboard.press('Space');
|
||||
await page.waitForTimeout(320);
|
||||
}
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
const camp = window.__HEROS_DEBUG__?.camp?.();
|
||||
return activeScenes.includes('CampScene') && camp?.campaign?.step === 'baidi-entrustment-camp';
|
||||
});
|
||||
await waitForCampReady(page, { step: 'baidi-entrustment-camp' });
|
||||
|
||||
const baidiCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -6433,10 +6285,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fortySeventhCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -6592,10 +6441,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fortyEighthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -6751,10 +6597,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fortyNinthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -6913,10 +6756,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fiftiethCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -7076,10 +6916,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fiftyFirstCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -7239,10 +7076,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fiftySecondCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -7401,10 +7235,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fiftyThirdCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -7563,10 +7394,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fiftyFourthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -7633,10 +7461,7 @@ try {
|
||||
await page.keyboard.press('Space');
|
||||
await page.waitForTimeout(320);
|
||||
}
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene') && !activeScenes.includes('StoryScene');
|
||||
});
|
||||
await waitForCampReady(page, { withoutStory: true });
|
||||
|
||||
const northernPrepCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -7780,10 +7605,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fiftyFifthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -7927,10 +7749,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fiftySixthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -8078,10 +7897,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fiftySeventhCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -8226,10 +8042,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fiftyEighthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -8374,10 +8187,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const fiftyNinthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -8528,10 +8338,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const sixtiethCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -8685,10 +8492,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const sixtyFirstCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -8845,10 +8649,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const sixtySecondCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -9028,10 +8829,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const sixtyThirdCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -9213,10 +9011,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const sixtyFourthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -9410,10 +9205,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const sixtyFifthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -9541,10 +9333,7 @@ try {
|
||||
});
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('CampScene');
|
||||
});
|
||||
await waitForCampReady(page);
|
||||
|
||||
const sixtySixthCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
if (
|
||||
@@ -9766,6 +9555,21 @@ async function waitForStoryReady(page) {
|
||||
}, undefined, { timeout: 90000 });
|
||||
}
|
||||
|
||||
async function waitForCampReady(page, options = {}) {
|
||||
await page.waitForFunction((expected) => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
const campScene = window.__HEROS_DEBUG__?.scene('CampScene');
|
||||
const campState = window.__HEROS_DEBUG__?.camp();
|
||||
return (
|
||||
activeScenes.includes('CampScene') &&
|
||||
(!expected.withoutStory || !activeScenes.includes('StoryScene')) &&
|
||||
campState?.scene === 'CampScene' &&
|
||||
(campScene?.contentObjects?.length ?? 0) > 0 &&
|
||||
(!expected.step || campState?.campaign?.step === expected.step)
|
||||
);
|
||||
}, options, { timeout: 90000 });
|
||||
}
|
||||
|
||||
function delay(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
418
scripts/verify-release-candidate.mjs
Normal file
418
scripts/verify-release-candidate.mjs
Normal file
@@ -0,0 +1,418 @@
|
||||
import { spawn } from 'node:child_process';
|
||||
import { mkdirSync } from 'node:fs';
|
||||
import { chromium } from 'playwright';
|
||||
|
||||
const targetUrl = withDebugParam(process.env.RELEASE_QA_URL ?? 'http://127.0.0.1:4173/');
|
||||
const screenshotDir = 'dist';
|
||||
|
||||
let serverProcess;
|
||||
let browser;
|
||||
|
||||
try {
|
||||
mkdirSync(screenshotDir, { recursive: true });
|
||||
serverProcess = await ensurePreviewServer(targetUrl);
|
||||
|
||||
browser = await chromium.launch({ headless: true });
|
||||
const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
|
||||
const consoleMessages = [];
|
||||
page.on('console', (message) => {
|
||||
consoleMessages.push({ type: message.type(), text: message.text() });
|
||||
});
|
||||
|
||||
await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });
|
||||
await page.evaluate(() => window.localStorage.clear());
|
||||
await page.reload({ waitUntil: 'domcontentloaded' });
|
||||
await waitForTitle(page);
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-title-first-run.png`, fullPage: true });
|
||||
|
||||
const emptySave = await readCampaignSave(page);
|
||||
assert(!emptySave.current && !emptySave.slot1, `Expected first run without campaign save: ${JSON.stringify(emptySave)}`);
|
||||
|
||||
await page.mouse.click(962, 240);
|
||||
await waitForStoryReady(page);
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-new-game-story.png`, fullPage: true });
|
||||
await advanceUntilBattle(page, 'first-battle-zhuo-commandery');
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-first-battle.png`, fullPage: true });
|
||||
|
||||
const firstBattleProbe = await page.evaluate(() => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('BattleScene');
|
||||
const state = window.__HEROS_DEBUG__?.battle();
|
||||
const sideTexts = textValues(scene?.sidePanelObjects);
|
||||
return {
|
||||
battleId: state?.battleId,
|
||||
objectiveText: scene?.objectiveTrackerText?.text,
|
||||
objectiveSubText: scene?.objectiveTrackerSubText?.text,
|
||||
sideTexts
|
||||
};
|
||||
|
||||
function textValues(objects = []) {
|
||||
return objects.filter((object) => object?.type === 'Text').map((object) => object.text);
|
||||
}
|
||||
});
|
||||
assert(firstBattleProbe.battleId === 'first-battle-zhuo-commandery', `Expected first battle: ${JSON.stringify(firstBattleProbe)}`);
|
||||
assert(firstBattleProbe.objectiveText?.startsWith('승리 목표:'), `Expected clear victory objective label: ${JSON.stringify(firstBattleProbe)}`);
|
||||
assert(firstBattleProbe.objectiveSubText?.includes('패배 조건:'), `Expected clear defeat condition label: ${JSON.stringify(firstBattleProbe)}`);
|
||||
assert(
|
||||
firstBattleProbe.sideTexts.some((text) => text.includes('황건적의 전열이 무너집니다.')) &&
|
||||
!firstBattleProbe.sideTexts.some((text) => text.includes('...')),
|
||||
`Expected opening objective text without ASCII truncation: ${JSON.stringify(firstBattleProbe.sideTexts)}`
|
||||
);
|
||||
|
||||
await page.evaluate(() => window.__HEROS_DEBUG__?.forceBattleOutcome('victory'));
|
||||
await waitForBattleOutcome(page, 'victory');
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-first-battle-result.png`, fullPage: true });
|
||||
|
||||
const resultProbe = await page.evaluate(() => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('BattleScene');
|
||||
const state = window.__HEROS_DEBUG__?.battle();
|
||||
return {
|
||||
outcome: state?.battleOutcome,
|
||||
resultTexts: textValues(scene?.resultObjects)
|
||||
};
|
||||
|
||||
function textValues(objects = []) {
|
||||
return objects.filter((object) => object?.type === 'Text').map((object) => object.text);
|
||||
}
|
||||
});
|
||||
assert(resultProbe.outcome === 'victory', `Expected forced victory result: ${JSON.stringify(resultProbe)}`);
|
||||
assert(resultProbe.resultTexts.includes('목표 정산'), `Expected result objective settlement title: ${JSON.stringify(resultProbe.resultTexts)}`);
|
||||
assert(resultProbe.resultTexts.some((text) => text.includes('목표 보상')), `Expected reward panel to name objective rewards: ${JSON.stringify(resultProbe.resultTexts)}`);
|
||||
assert(!resultProbe.resultTexts.some((text) => text.includes('미달')), `Expected result screen to avoid harsh optional-goal wording: ${JSON.stringify(resultProbe.resultTexts)}`);
|
||||
|
||||
await page.mouse.click(738, 642);
|
||||
await waitForCamp(page);
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-first-camp.png`, fullPage: true });
|
||||
|
||||
const firstCampProbe = await page.evaluate(() => {
|
||||
const scene = window.__HEROS_GAME__?.scene.getScene('CampScene');
|
||||
return {
|
||||
state: window.__HEROS_DEBUG__?.camp(),
|
||||
summary: scene?.reportSummary?.(),
|
||||
texts: textValues(scene?.contentObjects)
|
||||
};
|
||||
|
||||
function textValues(objects = []) {
|
||||
return objects.filter((object) => object?.type === 'Text').map((object) => object.text);
|
||||
}
|
||||
});
|
||||
assert(firstCampProbe.state?.campaign?.step === 'first-camp', `Expected victory to return to first camp: ${JSON.stringify(firstCampProbe.state)}`);
|
||||
assert(firstCampProbe.summary?.includes('보유 군자금'), `Expected camp summary to show held gold: ${JSON.stringify(firstCampProbe)}`);
|
||||
assert(firstCampProbe.texts.some((text) => text.includes('전투 보상')), `Expected camp report to show battle reward: ${JSON.stringify(firstCampProbe.texts)}`);
|
||||
|
||||
await seedCampaignSave(page, {
|
||||
battleId: 'fifty-eighth-battle-qishan-retreat',
|
||||
battleTitle: '기산 후퇴로',
|
||||
step: 'fifty-eighth-camp',
|
||||
gold: 7400,
|
||||
turnNumber: 13,
|
||||
defeatedEnemies: 16,
|
||||
selectedSortieUnitIds: ['zhuge-liang', 'jiang-wei', 'wang-ping', 'zhao-yun', 'huang-quan', 'ma-liang', 'ma-dai']
|
||||
});
|
||||
await page.reload({ waitUntil: 'domcontentloaded' });
|
||||
await waitForTitle(page);
|
||||
await page.mouse.click(962, 310);
|
||||
await waitForCamp(page);
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-mid-campaign-continue.png`, fullPage: true });
|
||||
|
||||
const midCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||
assert(midCampState?.campaign?.step === 'fifty-eighth-camp', `Expected mid-campaign save to continue into camp: ${JSON.stringify(midCampState)}`);
|
||||
assert(midCampState.campBattleId === 'fifty-eighth-battle-qishan-retreat', `Expected mid-campaign battle id: ${JSON.stringify(midCampState)}`);
|
||||
assert(midCampState.sortiePlan?.selectedCount > 0, `Expected mid-campaign formation state: ${JSON.stringify(midCampState?.sortiePlan)}`);
|
||||
|
||||
await seedCampaignSave(page, {
|
||||
battleId: 'sixty-sixth-battle-wuzhang-final',
|
||||
battleTitle: '오장원 최종전',
|
||||
step: 'sixty-sixth-camp',
|
||||
gold: 9800,
|
||||
turnNumber: 18,
|
||||
defeatedEnemies: 20,
|
||||
selectedSortieUnitIds: ['zhuge-liang', 'jiang-wei', 'wang-ping', 'ma-dai', 'huang-quan', 'li-yan', 'wei-yan']
|
||||
});
|
||||
await page.reload({ waitUntil: 'domcontentloaded' });
|
||||
await waitForTitle(page);
|
||||
await page.mouse.click(962, 310);
|
||||
await waitForCamp(page);
|
||||
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)}`);
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-final-camp.png`, fullPage: true });
|
||||
|
||||
await page.mouse.click(1160, 38);
|
||||
const finalTransitionScenes = await waitForStoryOrEnding(page);
|
||||
if (finalTransitionScenes.includes('StoryScene')) {
|
||||
await waitForStoryReady(page);
|
||||
await advanceStoryUntilEnding(page);
|
||||
}
|
||||
await waitForEnding(page);
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-ending.png`, fullPage: true });
|
||||
|
||||
const endingState = await page.evaluate(() => window.__HEROS_DEBUG__?.scene('EndingScene')?.getDebugState?.());
|
||||
assert(endingState?.campaignStep === 'ending-complete', `Expected ending-complete state: ${JSON.stringify(endingState)}`);
|
||||
assert(endingState.latestBattleId === 'sixty-sixth-battle-wuzhang-final', `Expected Wuzhang final as latest battle: ${JSON.stringify(endingState)}`);
|
||||
|
||||
await page.keyboard.press('Enter');
|
||||
await waitForTitle(page);
|
||||
await page.mouse.click(962, 310);
|
||||
await waitForEnding(page);
|
||||
await page.screenshot({ path: `${screenshotDir}/rc-ending-continue.png`, fullPage: true });
|
||||
|
||||
const endingContinueState = await page.evaluate(() => ({
|
||||
activeScenes: window.__HEROS_DEBUG__?.activeScenes() ?? [],
|
||||
ending: window.__HEROS_DEBUG__?.scene('EndingScene')?.getDebugState?.()
|
||||
}));
|
||||
assert(
|
||||
endingContinueState.activeScenes.includes('EndingScene') && endingContinueState.ending?.campaignStep === 'ending-complete',
|
||||
`Expected title continue to reopen ending: ${JSON.stringify(endingContinueState)}`
|
||||
);
|
||||
|
||||
const errors = consoleMessages.filter((message) => message.type === 'error');
|
||||
assert(errors.length === 0, `Unexpected browser console errors: ${JSON.stringify(errors)}`);
|
||||
|
||||
console.log(`Verified release-candidate user flow at ${targetUrl}`);
|
||||
} finally {
|
||||
await browser?.close();
|
||||
if (serverProcess && !serverProcess.killed) {
|
||||
serverProcess.kill();
|
||||
}
|
||||
}
|
||||
|
||||
function withDebugParam(url) {
|
||||
const parsed = new URL(url);
|
||||
parsed.searchParams.set('debug', '1');
|
||||
parsed.searchParams.set('renderer', 'canvas');
|
||||
return parsed.toString();
|
||||
}
|
||||
|
||||
async function waitForTitle(page) {
|
||||
await page.waitForFunction(() => document.querySelector('canvas') !== null, undefined, { timeout: 90000 });
|
||||
await page.waitForFunction(() => window.__HEROS_DEBUG__ !== undefined, undefined, { timeout: 90000 });
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('TitleScene');
|
||||
}, undefined, { timeout: 90000 });
|
||||
}
|
||||
|
||||
async function waitForStoryReady(page) {
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
const story = window.__HEROS_DEBUG__?.scene('StoryScene')?.getDebugState?.();
|
||||
return activeScenes.includes('StoryScene') && story?.ready === true;
|
||||
}, undefined, { timeout: 90000 });
|
||||
}
|
||||
|
||||
async function waitForStoryOrEnding(page) {
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
return activeScenes.includes('StoryScene') || activeScenes.includes('EndingScene');
|
||||
}, undefined, { timeout: 30000 });
|
||||
return page.evaluate(() => window.__HEROS_DEBUG__?.activeScenes() ?? []);
|
||||
}
|
||||
|
||||
async function advanceUntilBattle(page, battleId) {
|
||||
for (let i = 0; i < 48; i += 1) {
|
||||
const ready = await page.evaluate((expectedBattleId) => {
|
||||
const state = window.__HEROS_DEBUG__?.battle();
|
||||
return state?.scene === 'BattleScene' && state?.battleId === expectedBattleId && state?.phase === 'idle' && state?.mapBackgroundReady === true;
|
||||
}, battleId);
|
||||
|
||||
if (ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
await page.keyboard.press('Space');
|
||||
await page.waitForTimeout(220);
|
||||
}
|
||||
|
||||
await waitForBattleReady(page, battleId);
|
||||
}
|
||||
|
||||
async function waitForBattleReady(page, battleId) {
|
||||
await page.waitForFunction((expectedBattleId) => {
|
||||
const state = window.__HEROS_DEBUG__?.battle();
|
||||
return state?.scene === 'BattleScene' && state?.battleId === expectedBattleId && state?.phase === 'idle' && state?.mapBackgroundReady === true;
|
||||
}, battleId, { timeout: 90000 });
|
||||
}
|
||||
|
||||
async function waitForBattleOutcome(page, outcome) {
|
||||
await page.waitForFunction((expectedOutcome) => {
|
||||
const state = window.__HEROS_DEBUG__?.battle();
|
||||
return state?.battleOutcome === expectedOutcome && state?.phase === 'resolved' && state?.resultVisible === true;
|
||||
}, outcome, { timeout: 90000 });
|
||||
}
|
||||
|
||||
async function waitForCamp(page) {
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
const scene = window.__HEROS_DEBUG__?.scene('CampScene');
|
||||
return (
|
||||
activeScenes.includes('CampScene') &&
|
||||
window.__HEROS_DEBUG__?.camp()?.scene === 'CampScene' &&
|
||||
(scene?.contentObjects?.length ?? 0) > 0
|
||||
);
|
||||
}, undefined, { timeout: 90000 });
|
||||
}
|
||||
|
||||
async function advanceStoryUntilEnding(page) {
|
||||
for (let i = 0; i < 48; i += 1) {
|
||||
const activeScenes = await page.evaluate(() => window.__HEROS_DEBUG__?.activeScenes() ?? []);
|
||||
if (activeScenes.includes('EndingScene')) {
|
||||
return;
|
||||
}
|
||||
|
||||
await page.keyboard.press('Space');
|
||||
await page.waitForTimeout(240);
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForEnding(page) {
|
||||
await page.waitForFunction(() => {
|
||||
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||
const ending = window.__HEROS_DEBUG__?.scene('EndingScene')?.getDebugState?.();
|
||||
return activeScenes.includes('EndingScene') && ending?.ready === true && ending?.campaignStep === 'ending-complete';
|
||||
}, undefined, { timeout: 90000 });
|
||||
}
|
||||
|
||||
async function readCampaignSave(page) {
|
||||
return page.evaluate(() => {
|
||||
const read = (key) => {
|
||||
const raw = window.localStorage.getItem(key);
|
||||
return raw ? JSON.parse(raw) : undefined;
|
||||
};
|
||||
return {
|
||||
current: read('heros-web:campaign-state'),
|
||||
slot1: read('heros-web:campaign-state:slot-1')
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function seedCampaignSave(page, options) {
|
||||
await page.evaluate((seed) => {
|
||||
const storageKey = 'heros-web:campaign-state';
|
||||
const current = JSON.parse(window.localStorage.getItem(storageKey) ?? 'null');
|
||||
if (!current?.firstBattleReport) {
|
||||
throw new Error('Expected an existing campaign report before seeding RC save.');
|
||||
}
|
||||
|
||||
const now = new Date().toISOString();
|
||||
const objectives = [
|
||||
{ id: 'leader', label: '지휘관 격파', achieved: true, status: 'done', detail: '전장 목표 완료', rewardGold: 420 },
|
||||
{ id: 'survive', label: '본대 보존', achieved: true, status: 'done', detail: '핵심 장수 생존', rewardGold: 260 },
|
||||
{ id: 'supply', label: '보급선 유지', achieved: true, status: 'done', detail: '수레와 군량 확보', rewardGold: 220 },
|
||||
{ id: 'quick', label: '빠른 정리', achieved: false, status: 'failed', detail: `${seed.turnNumber}/12턴`, rewardGold: 180 }
|
||||
];
|
||||
const units = current.roster?.length ? current.roster : current.firstBattleReport.units;
|
||||
const bonds = current.bonds?.length ? current.bonds : current.firstBattleReport.bonds;
|
||||
const report = {
|
||||
...current.firstBattleReport,
|
||||
battleId: seed.battleId,
|
||||
battleTitle: seed.battleTitle,
|
||||
outcome: 'victory',
|
||||
turnNumber: seed.turnNumber,
|
||||
rewardGold: 1080,
|
||||
defeatedEnemies: seed.defeatedEnemies,
|
||||
totalEnemies: seed.defeatedEnemies,
|
||||
objectives,
|
||||
units,
|
||||
bonds,
|
||||
mvp: current.firstBattleReport.mvp ?? { unitId: 'zhuge-liang', name: '제갈량', damageDealt: 320, defeats: 2 },
|
||||
itemRewards: ['상처약 2', '탁주 1'],
|
||||
completedCampDialogues: current.completedCampDialogues ?? [],
|
||||
completedCampVisits: current.completedCampVisits ?? [],
|
||||
createdAt: now
|
||||
};
|
||||
const settlement = {
|
||||
battleId: report.battleId,
|
||||
battleTitle: report.battleTitle,
|
||||
outcome: 'victory',
|
||||
rewardGold: report.rewardGold,
|
||||
itemRewards: report.itemRewards,
|
||||
objectives,
|
||||
units: units.map((unit) => ({
|
||||
unitId: unit.id,
|
||||
name: unit.name,
|
||||
level: unit.level ?? 1,
|
||||
exp: unit.exp ?? 0,
|
||||
hp: unit.hp ?? unit.maxHp ?? 1,
|
||||
maxHp: unit.maxHp ?? 1,
|
||||
equipment: unit.equipment
|
||||
})),
|
||||
bonds: bonds.map((bond) => ({
|
||||
id: bond.id,
|
||||
title: bond.title,
|
||||
level: bond.level ?? 1,
|
||||
exp: bond.exp ?? 0,
|
||||
battleExp: bond.battleExp ?? 0
|
||||
})),
|
||||
reserveTraining: [],
|
||||
completedAt: now
|
||||
};
|
||||
const next = {
|
||||
...current,
|
||||
updatedAt: now,
|
||||
step: seed.step,
|
||||
activeSaveSlot: 1,
|
||||
gold: seed.gold,
|
||||
inventory: { ...(current.inventory ?? {}), 콩: 12, 상처약: 6, 탁주: 4 },
|
||||
selectedSortieUnitIds: seed.selectedSortieUnitIds,
|
||||
latestBattleId: seed.battleId,
|
||||
firstBattleReport: report,
|
||||
battleHistory: {
|
||||
...(current.battleHistory ?? {}),
|
||||
[seed.battleId]: settlement
|
||||
}
|
||||
};
|
||||
|
||||
window.localStorage.setItem(storageKey, JSON.stringify(next));
|
||||
window.localStorage.setItem(`${storageKey}:slot-1`, JSON.stringify(next));
|
||||
}, options);
|
||||
}
|
||||
|
||||
async function ensurePreviewServer(url) {
|
||||
if (await canReach(url)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const parsed = new URL(url);
|
||||
const isLocal = ['localhost', '127.0.0.1', '0.0.0.0'].includes(parsed.hostname);
|
||||
if (!isLocal) {
|
||||
throw new Error(`No server responded at ${url}`);
|
||||
}
|
||||
|
||||
const stderr = [];
|
||||
const child = spawn(process.execPath, ['node_modules/vite/bin/vite.js', 'preview', '--host', '127.0.0.1', '--port', parsed.port || '4173'], {
|
||||
cwd: process.cwd(),
|
||||
env: process.env,
|
||||
stdio: ['ignore', 'pipe', 'pipe']
|
||||
});
|
||||
|
||||
child.stderr.on('data', (chunk) => stderr.push(chunk.toString()));
|
||||
child.stdout.on('data', () => {});
|
||||
|
||||
for (let i = 0; i < 120; i += 1) {
|
||||
if (await canReach(url)) {
|
||||
return child;
|
||||
}
|
||||
await delay(250);
|
||||
}
|
||||
|
||||
child.kill();
|
||||
throw new Error(`Vite preview did not start at ${url}\n${stderr.join('')}`);
|
||||
}
|
||||
|
||||
async function canReach(url) {
|
||||
try {
|
||||
const response = await fetch(url, { signal: AbortSignal.timeout(1000) });
|
||||
return response.ok;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function delay(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function assert(condition, message) {
|
||||
if (!condition) {
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user