Add Fan Castle siege chapter

This commit is contained in:
2026-06-23 16:42:33 +09:00
parent 628e73ba58
commit 6a55313492
11 changed files with 902 additions and 50 deletions

View File

@@ -1,4 +1,4 @@
import { spawn } from 'node:child_process';
import { spawn } from 'node:child_process';
import { chromium } from 'playwright';
const targetUrl = process.env.VERIFY_URL ?? 'http://localhost:5173/';
@@ -1736,7 +1736,7 @@ try {
if (
progressTabState?.activeTab !== 'progress' ||
progressTabState.campaignProgress?.completedKnown !== 17 ||
progressTabState.campaignProgress?.totalKnown !== 40 ||
progressTabState.campaignProgress?.totalKnown !== 41 ||
progressTabState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
progressTabState.campaignProgress?.latestBattleTitle !== '융중 방문로' ||
progressTabState.campaignProgress?.nextBattleTitle !== '박망파 매복전'
@@ -1888,7 +1888,7 @@ try {
if (
postBowangProgressState?.activeTab !== 'progress' ||
postBowangProgressState.campaignProgress?.completedKnown !== 18 ||
postBowangProgressState.campaignProgress?.totalKnown !== 40 ||
postBowangProgressState.campaignProgress?.totalKnown !== 41 ||
postBowangProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
postBowangProgressState.campaignProgress?.latestBattleTitle !== '박망파 매복전' ||
postBowangProgressState.campaignProgress?.nextBattleTitle !== '장판파 피난로'
@@ -2026,7 +2026,7 @@ try {
if (
postChangbanProgressState?.activeTab !== 'progress' ||
postChangbanProgressState.campaignProgress?.completedKnown !== 19 ||
postChangbanProgressState.campaignProgress?.totalKnown !== 40 ||
postChangbanProgressState.campaignProgress?.totalKnown !== 41 ||
postChangbanProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
postChangbanProgressState.campaignProgress?.latestBattleTitle !== '장판파 피난로' ||
postChangbanProgressState.campaignProgress?.nextBattleTitle !== '강동 사절로'
@@ -2164,7 +2164,7 @@ try {
if (
postJiangdongProgressState?.activeTab !== 'progress' ||
postJiangdongProgressState.campaignProgress?.completedKnown !== 20 ||
postJiangdongProgressState.campaignProgress?.totalKnown !== 40 ||
postJiangdongProgressState.campaignProgress?.totalKnown !== 41 ||
postJiangdongProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
postJiangdongProgressState.campaignProgress?.latestBattleTitle !== '강동 사절로' ||
postJiangdongProgressState.campaignProgress?.nextBattleTitle !== '적벽 전초전'
@@ -2304,7 +2304,7 @@ try {
if (
postRedCliffsProgressState?.activeTab !== 'progress' ||
postRedCliffsProgressState.campaignProgress?.completedKnown !== 21 ||
postRedCliffsProgressState.campaignProgress?.totalKnown !== 40 ||
postRedCliffsProgressState.campaignProgress?.totalKnown !== 41 ||
postRedCliffsProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
postRedCliffsProgressState.campaignProgress?.latestBattleTitle !== '적벽 전초전' ||
postRedCliffsProgressState.campaignProgress?.nextBattleTitle !== '적벽 화공전'
@@ -2444,7 +2444,7 @@ try {
if (
postFireAttackProgressState?.activeTab !== 'progress' ||
postFireAttackProgressState.campaignProgress?.completedKnown !== 22 ||
postFireAttackProgressState.campaignProgress?.totalKnown !== 40 ||
postFireAttackProgressState.campaignProgress?.totalKnown !== 41 ||
postFireAttackProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postFireAttackProgressState.campaignProgress?.latestBattleTitle !== '적벽 화공전' ||
postFireAttackProgressState.campaignProgress?.nextBattleTitle !== '형주 남부 진입전'
@@ -2587,7 +2587,7 @@ try {
if (
postJingzhouProgressState?.activeTab !== 'progress' ||
postJingzhouProgressState.campaignProgress?.completedKnown !== 23 ||
postJingzhouProgressState.campaignProgress?.totalKnown !== 40 ||
postJingzhouProgressState.campaignProgress?.totalKnown !== 41 ||
postJingzhouProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postJingzhouProgressState.campaignProgress?.latestBattleTitle !== '형주 남부 진입전' ||
postJingzhouProgressState.campaignProgress?.nextBattleTitle !== '계양 설득전'
@@ -2729,7 +2729,7 @@ try {
if (
postGuiyangProgressState?.activeTab !== 'progress' ||
postGuiyangProgressState.campaignProgress?.completedKnown !== 24 ||
postGuiyangProgressState.campaignProgress?.totalKnown !== 40 ||
postGuiyangProgressState.campaignProgress?.totalKnown !== 41 ||
postGuiyangProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postGuiyangProgressState.campaignProgress?.latestBattleTitle !== '계양 설득전' ||
postGuiyangProgressState.campaignProgress?.nextBattleTitle !== '무릉 산길 확보전'
@@ -2872,7 +2872,7 @@ try {
if (
postWulingProgressState?.activeTab !== 'progress' ||
postWulingProgressState.campaignProgress?.completedKnown !== 25 ||
postWulingProgressState.campaignProgress?.totalKnown !== 40 ||
postWulingProgressState.campaignProgress?.totalKnown !== 41 ||
postWulingProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postWulingProgressState.campaignProgress?.latestBattleTitle !== '무릉 산길 확보전' ||
postWulingProgressState.campaignProgress?.nextBattleTitle !== '장사 노장 대면전'
@@ -3021,7 +3021,7 @@ try {
if (
postChangshaProgressState?.activeTab !== 'progress' ||
postChangshaProgressState.campaignProgress?.completedKnown !== 26 ||
postChangshaProgressState.campaignProgress?.totalKnown !== 40 ||
postChangshaProgressState.campaignProgress?.totalKnown !== 41 ||
postChangshaProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postChangshaProgressState.campaignProgress?.latestBattleTitle !== '장사 노장 대면전' ||
postChangshaProgressState.campaignProgress?.nextBattleTitle !== '익주 원군로'
@@ -3166,7 +3166,7 @@ try {
if (
postYizhouProgressState?.activeTab !== 'progress' ||
postYizhouProgressState.campaignProgress?.completedKnown !== 27 ||
postYizhouProgressState.campaignProgress?.totalKnown !== 40 ||
postYizhouProgressState.campaignProgress?.totalKnown !== 41 ||
postYizhouProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postYizhouProgressState.campaignProgress?.latestBattleTitle !== '익주 원군로' ||
postYizhouProgressState.campaignProgress?.nextBattleTitle !== '부수관 진입전'
@@ -3313,7 +3313,7 @@ try {
if (
postFuPassProgressState?.activeTab !== 'progress' ||
postFuPassProgressState.campaignProgress?.completedKnown !== 28 ||
postFuPassProgressState.campaignProgress?.totalKnown !== 40 ||
postFuPassProgressState.campaignProgress?.totalKnown !== 41 ||
postFuPassProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postFuPassProgressState.campaignProgress?.latestBattleTitle !== '부수관 진입전' ||
postFuPassProgressState.campaignProgress?.nextBattleTitle !== '낙성 외곽전'
@@ -3462,7 +3462,7 @@ try {
if (
postLuoProgressState?.activeTab !== 'progress' ||
postLuoProgressState.campaignProgress?.completedKnown !== 29 ||
postLuoProgressState.campaignProgress?.totalKnown !== 40 ||
postLuoProgressState.campaignProgress?.totalKnown !== 41 ||
postLuoProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postLuoProgressState.campaignProgress?.latestBattleTitle !== '낙성 외곽전' ||
postLuoProgressState.campaignProgress?.nextBattleTitle !== '낙봉파 매복전'
@@ -3608,7 +3608,7 @@ try {
if (
postLuofengProgressState?.activeTab !== 'progress' ||
postLuofengProgressState.campaignProgress?.completedKnown !== 30 ||
postLuofengProgressState.campaignProgress?.totalKnown !== 40 ||
postLuofengProgressState.campaignProgress?.totalKnown !== 41 ||
postLuofengProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postLuofengProgressState.campaignProgress?.latestBattleTitle !== '낙봉파 매복전' ||
postLuofengProgressState.campaignProgress?.nextBattleTitle !== '낙성 본성 공략'
@@ -3760,7 +3760,7 @@ try {
if (
postLuoMainProgressState?.activeTab !== 'progress' ||
postLuoMainProgressState.campaignProgress?.completedKnown !== 31 ||
postLuoMainProgressState.campaignProgress?.totalKnown !== 40 ||
postLuoMainProgressState.campaignProgress?.totalKnown !== 41 ||
postLuoMainProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postLuoMainProgressState.campaignProgress?.latestBattleTitle !== '낙성 본성 공략' ||
postLuoMainProgressState.campaignProgress?.nextBattleTitle !== '면죽관 압박전'
@@ -3913,7 +3913,7 @@ try {
if (
postMianzhuProgressState?.activeTab !== 'progress' ||
postMianzhuProgressState.campaignProgress?.completedKnown !== 32 ||
postMianzhuProgressState.campaignProgress?.totalKnown !== 40 ||
postMianzhuProgressState.campaignProgress?.totalKnown !== 41 ||
postMianzhuProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
postMianzhuProgressState.campaignProgress?.latestBattleTitle !== '면죽관 압박전' ||
postMianzhuProgressState.campaignProgress?.nextBattleTitle !== '성도 항복 권고전'
@@ -4067,7 +4067,7 @@ try {
if (
postChengduProgressState?.activeTab !== 'progress' ||
postChengduProgressState.campaignProgress?.completedKnown !== 33 ||
postChengduProgressState.campaignProgress?.totalKnown !== 40 ||
postChengduProgressState.campaignProgress?.totalKnown !== 41 ||
postChengduProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
postChengduProgressState.campaignProgress?.latestBattleTitle !== '성도 항복 권고전' ||
postChengduProgressState.campaignProgress?.nextBattleTitle !== '가맹관 마초 대면전'
@@ -4222,7 +4222,7 @@ try {
if (
postJiamengProgressState?.activeTab !== 'progress' ||
postJiamengProgressState.campaignProgress?.completedKnown !== 34 ||
postJiamengProgressState.campaignProgress?.totalKnown !== 40 ||
postJiamengProgressState.campaignProgress?.totalKnown !== 41 ||
postJiamengProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
postJiamengProgressState.campaignProgress?.latestBattleTitle !== '가맹관 마초 대면전' ||
postJiamengProgressState.campaignProgress?.nextBattleTitle !== '양평관 정찰전'
@@ -4378,7 +4378,7 @@ try {
if (
postYangpingProgressState?.activeTab !== 'progress' ||
postYangpingProgressState.campaignProgress?.completedKnown !== 35 ||
postYangpingProgressState.campaignProgress?.totalKnown !== 40 ||
postYangpingProgressState.campaignProgress?.totalKnown !== 41 ||
postYangpingProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
postYangpingProgressState.campaignProgress?.latestBattleTitle !== '양평관 정찰전' ||
postYangpingProgressState.campaignProgress?.nextBattleTitle !== '정군산 전초전'
@@ -4535,7 +4535,7 @@ try {
if (
postDingjunProgressState?.activeTab !== 'progress' ||
postDingjunProgressState.campaignProgress?.completedKnown !== 36 ||
postDingjunProgressState.campaignProgress?.totalKnown !== 40 ||
postDingjunProgressState.campaignProgress?.totalKnown !== 41 ||
postDingjunProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
postDingjunProgressState.campaignProgress?.latestBattleTitle !== '정군산 전초전' ||
postDingjunProgressState.campaignProgress?.nextBattleTitle !== '한중 결전'
@@ -4688,7 +4688,7 @@ try {
if (
postHanzhongProgressState?.activeTab !== 'progress' ||
postHanzhongProgressState.campaignProgress?.completedKnown !== 37 ||
postHanzhongProgressState.campaignProgress?.totalKnown !== 40 ||
postHanzhongProgressState.campaignProgress?.totalKnown !== 41 ||
postHanzhongProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
postHanzhongProgressState.campaignProgress?.latestBattleTitle !== '한중 결전' ||
postHanzhongProgressState.campaignProgress?.nextBattleTitle !== '한중왕 즉위 준비'
@@ -4749,7 +4749,7 @@ try {
if (
postKingCouncilProgressState?.activeTab !== 'progress' ||
postKingCouncilProgressState.campaignProgress?.completedKnown !== 37 ||
postKingCouncilProgressState.campaignProgress?.totalKnown !== 40 ||
postKingCouncilProgressState.campaignProgress?.totalKnown !== 41 ||
postKingCouncilProgressState.campaignProgress?.latestBattleTitle !== '한중 결전' ||
postKingCouncilProgressState.campaignProgress?.nextBattleTitle !== '촉한 건국 선포'
) {
@@ -4809,7 +4809,7 @@ try {
if (
postFoundationProgressState?.activeTab !== 'progress' ||
postFoundationProgressState.campaignProgress?.completedKnown !== 37 ||
postFoundationProgressState.campaignProgress?.totalKnown !== 40 ||
postFoundationProgressState.campaignProgress?.totalKnown !== 41 ||
postFoundationProgressState.campaignProgress?.latestBattleTitle !== '한중 결전' ||
postFoundationProgressState.campaignProgress?.nextBattleTitle !== '형주 방위 전초전'
) {
@@ -4960,7 +4960,7 @@ try {
if (
postJingDefenseProgressState?.activeTab !== 'progress' ||
postJingDefenseProgressState.campaignProgress?.completedKnown !== 38 ||
postJingDefenseProgressState.campaignProgress?.totalKnown !== 40 ||
postJingDefenseProgressState.campaignProgress?.totalKnown !== 41 ||
postJingDefenseProgressState.campaignProgress?.latestBattleTitle !== '형주 방위 전초전' ||
postJingDefenseProgressState.campaignProgress?.nextBattleTitle !== '번성 외곽 압박전'
) {
@@ -5113,7 +5113,7 @@ try {
if (
postFanCastleProgressState?.activeTab !== 'progress' ||
postFanCastleProgressState.campaignProgress?.completedKnown !== 39 ||
postFanCastleProgressState.campaignProgress?.totalKnown !== 40 ||
postFanCastleProgressState.campaignProgress?.totalKnown !== 41 ||
postFanCastleProgressState.campaignProgress?.latestBattleTitle !== '번성 외곽 압박전' ||
postFanCastleProgressState.campaignProgress?.nextBattleTitle !== '한수 수공'
) {
@@ -5267,14 +5267,168 @@ try {
if (
postHanRiverProgressState?.activeTab !== 'progress' ||
postHanRiverProgressState.campaignProgress?.completedKnown !== 40 ||
postHanRiverProgressState.campaignProgress?.totalKnown !== 40 ||
postHanRiverProgressState.campaignProgress?.totalKnown !== 41 ||
postHanRiverProgressState.campaignProgress?.latestBattleTitle !== '한수 수공' ||
postHanRiverProgressState.campaignProgress?.nextBattleTitle !== '준비 중'
postHanRiverProgressState.campaignProgress?.nextBattleTitle !== '번성 공성전'
) {
throw new Error(`Expected post-Han River progress tab to complete the fortieth battle and leave Fan Castle siege as the next prepared slice: ${JSON.stringify(postHanRiverProgressState?.campaignProgress)}`);
throw new Error(`Expected post-Han River progress tab to complete the fortieth battle and point to Fan Castle siege: ${JSON.stringify(postHanRiverProgressState?.campaignProgress)}`);
}
await page.screenshot({ path: 'dist/verification-post-han-river-progress.png', fullPage: true });
await page.mouse.click(1120, 38);
await page.waitForTimeout(180);
const fanSiegeSortieState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
!fanSiegeSortieState?.sortieVisible ||
fanSiegeSortieState.campaign?.step !== 'fortieth-camp' ||
fanSiegeSortieState.sortiePlan?.objectiveLine !== '번성 공성전 · 조인 성문 방어선 격파' ||
fanSiegeSortieState.sortiePlan?.maxCount !== 7 ||
fanSiegeSortieState.sortiePlan?.recommendedTotal !== 7 ||
!fanSiegeSortieState.sortieRoster?.some((unit) => unit.id === 'guan-yu' && unit.selected && unit.required)
) {
throw new Error(`Expected Fan Castle siege sortie prep to lock Guan Yu and expose a seven-officer castle choice: ${JSON.stringify(fanSiegeSortieState)}`);
}
assertSortieTacticalRoster(fanSiegeSortieState, [
'liu-bei',
'guan-yu',
'zhang-fei',
'jian-yong',
'mi-zhu',
'sun-qian',
'zhao-yun',
'zhuge-liang',
'ma-liang',
'yi-ji',
'gong-zhi',
'huang-zhong',
'wei-yan',
'pang-tong',
'fa-zheng',
'wu-yi',
'yan-yan',
'li-yan',
'huang-quan',
'ma-chao',
'ma-dai',
'wang-ping'
]);
const fanSiegePriorityUnits = ['huang-zhong', 'ma-liang', 'fa-zheng', 'zhao-yun', 'ma-chao'];
for (const unitId of fanSiegePriorityUnits) {
const currentSortieState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (!currentSortieState.sortieRoster?.some((unit) => unit.id === unitId && unit.selected)) {
const removable = currentSortieState.sortieRoster?.find(
(unit) => unit.selected && !unit.required && !fanSiegePriorityUnits.includes(unit.id)
);
if (removable) {
await clickSortieRosterUnit(page, removable.id);
}
await clickSortieRosterUnit(page, unitId);
}
}
const fanSiegeSortieReadyState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
!fanSiegePriorityUnits.every((unitId) =>
fanSiegeSortieReadyState.sortieRoster?.some((unit) => unit.id === unitId && unit.selected)
) ||
!fanSiegeSortieReadyState.sortieRoster?.some((unit) => unit.id === 'liu-bei' && unit.selected && unit.required) ||
!fanSiegeSortieReadyState.sortieRoster?.some((unit) => unit.id === 'guan-yu' && unit.selected && unit.required) ||
fanSiegeSortieReadyState.sortiePlan?.selectedCount !== 7 ||
fanSiegeSortieReadyState.sortiePlan?.recommendedSelectedCount < 7
) {
throw new Error(`Expected Fan Castle siege sortie to deploy Liu Bei, Guan Yu, Huang Zhong, Ma Liang, Fa Zheng, Zhao Yun, and Ma Chao: ${JSON.stringify(fanSiegeSortieReadyState)}`);
}
await page.screenshot({ path: 'dist/verification-fan-siege-sortie.png', fullPage: true });
await page.mouse.click(1068, 646);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('StoryScene');
});
await page.screenshot({ path: 'dist/verification-fan-siege-story.png', fullPage: true });
for (let i = 0; i < 45; i += 1) {
const enteredFortyFirstBattle = await page.evaluate(() => {
const state = window.__HEROS_DEBUG__?.battle();
return state?.scene === 'BattleScene' && state?.battleId === 'forty-first-battle-fan-castle-siege';
});
if (enteredFortyFirstBattle) {
break;
}
await page.keyboard.press('Space');
await page.waitForTimeout(320);
}
await page.waitForFunction(() => {
const state = window.__HEROS_DEBUG__?.battle();
return state?.scene === 'BattleScene' && state?.battleId === 'forty-first-battle-fan-castle-siege' && state?.battleOutcome === null && state?.phase === 'idle';
});
await page.screenshot({ path: 'dist/verification-forty-first-battle.png', fullPage: true });
const fortyFirstBattleState = await page.evaluate(() => window.__HEROS_DEBUG__?.battle());
const fortyFirstEnemies = fortyFirstBattleState.units.filter((unit) => unit.faction === 'enemy');
const fortyFirstAllies = fortyFirstBattleState.units.filter((unit) => unit.faction === 'ally');
const fortyFirstEnemyBehaviors = new Set(fortyFirstEnemies.map((unit) => unit.ai));
if (
fortyFirstBattleState.camera?.mapWidth !== 82 ||
fortyFirstBattleState.camera?.mapHeight !== 64 ||
fortyFirstBattleState.victoryConditionLabel !== '조인 성문 방어선 격파' ||
fortyFirstEnemies.length < 35 ||
!fortyFirstEnemyBehaviors.has('aggressive') ||
!fortyFirstEnemyBehaviors.has('guard') ||
!fortyFirstEnemyBehaviors.has('hold') ||
!fortyFirstEnemies.some((unit) => unit.id === 'fan-siege-leader-cao-ren') ||
!fortyFirstEnemies.some((unit) => unit.id === 'fan-siege-officer-pang-de') ||
!fortyFirstEnemies.some((unit) => unit.id === 'fan-siege-officer-lu-meng') ||
!fortyFirstAllies.some((unit) => unit.id === 'guan-yu') ||
!fortyFirstAllies.some((unit) => unit.id === 'huang-zhong') ||
!fortyFirstAllies.some((unit) => unit.id === 'ma-liang') ||
!fortyFirstAllies.some((unit) => unit.id === 'fa-zheng') ||
!fortyFirstAllies.some((unit) => unit.id === 'zhao-yun')
) {
throw new Error(`Expected forty-first battle to use Fan Castle siege map, Cao Ren objective, selected allied officers, and mixed siege AI: ${JSON.stringify(fortyFirstBattleState)}`);
}
await page.evaluate(() => window.__HEROS_DEBUG__?.forceBattleOutcome('victory'));
await page.waitForFunction(() => {
const state = window.__HEROS_DEBUG__?.battle();
return state?.battleOutcome === 'victory' && state?.phase === 'resolved' && state?.resultVisible === true;
});
await page.mouse.click(738, 642);
await page.waitForFunction(() => {
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
return activeScenes.includes('CampScene');
});
const fortyFirstCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
fortyFirstCampState?.campBattleId !== 'forty-first-battle-fan-castle-siege' ||
fortyFirstCampState.campTitle !== '번성 공성전 후 군영' ||
fortyFirstCampState.availableDialogueIds?.length !== 3 ||
!fortyFirstCampState.availableDialogueIds.every((id) => id.endsWith('fan-siege')) ||
fortyFirstCampState.availableVisitIds?.length !== 2 ||
!fortyFirstCampState.availableVisitIds.every((id) => id.includes('fan-siege')) ||
fortyFirstCampState.rosterCollection?.total < 22
) {
throw new Error(`Expected forty-first camp to expose Fan Castle siege dialogue/visit sets and preserve the full officer roster: ${JSON.stringify(fortyFirstCampState)}`);
}
await page.screenshot({ path: 'dist/verification-fan-siege-camp.png', fullPage: true });
await page.mouse.click(966, 38);
await page.waitForTimeout(180);
const postFanSiegeProgressState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
if (
postFanSiegeProgressState?.activeTab !== 'progress' ||
postFanSiegeProgressState.campaignProgress?.completedKnown !== 41 ||
postFanSiegeProgressState.campaignProgress?.totalKnown !== 41 ||
postFanSiegeProgressState.campaignProgress?.latestBattleTitle !== '번성 공성전' ||
postFanSiegeProgressState.campaignProgress?.nextBattleTitle !== '준비 중'
) {
throw new Error(`Expected post-Fan Castle siege progress tab to complete the forty-first battle and leave Jing Province crisis as the next prepared slice: ${JSON.stringify(postFanSiegeProgressState?.campaignProgress)}`);
}
await page.screenshot({ path: 'dist/verification-post-fan-siege-progress.png', fullPage: true });
await page.evaluate(() => {
const game = window.__HEROS_GAME__;
game?.scene.stop('CampScene');
@@ -5307,10 +5461,10 @@ try {
camp: window.__HEROS_DEBUG__?.camp?.() ?? null
}));
if (!titleContinueState.activeScenes.includes('CampScene')) {
throw new Error(`Expected title continue to reopen the latest camp after Han River flood: ${JSON.stringify(titleContinueState)}`);
throw new Error(`Expected title continue to reopen the latest camp after Fan Castle siege: ${JSON.stringify(titleContinueState)}`);
}
console.log(`Verified title-to-fortieth-battle flow, recruited officer sortie selection, Ma Liang, Yi Ji, Gong Zhi, Huang Zhong, Wei Yan, Pang Tong, Fa Zheng, Wu Yi, Yan Yan, Li Yan, Huang Quan, Ma Chao, Ma Dai, Wang Ping joins, Luofeng, Luo main gate, Mianzhu, Chengdu surrender, Jiameng, Yangping, Dingjun, Hanzhong decisive battle, King of Hanzhong council, Shu-Han foundation state, Jing Province defense vanguard, Fan Castle vanguard, and Han River flood state at ${targetUrl}`);
console.log(`Verified title-to-forty-first-battle flow, recruited officer sortie selection, Ma Liang, Yi Ji, Gong Zhi, Huang Zhong, Wei Yan, Pang Tong, Fa Zheng, Wu Yi, Yan Yan, Li Yan, Huang Quan, Ma Chao, Ma Dai, Wang Ping joins, Luofeng, Luo main gate, Mianzhu, Chengdu surrender, Jiameng, Yangping, Dingjun, Hanzhong decisive battle, King of Hanzhong council, Shu-Han foundation state, Jing Province defense vanguard, Fan Castle vanguard, Han River flood, and Fan Castle siege state at ${targetUrl}`);
} finally {
await browser?.close();
if (serverProcess && !serverProcess.killed) {