Files
heros_web/scripts/verify-battle-result-persistence-retry.mjs

162 lines
4.6 KiB
JavaScript

import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
const [battleSource, campaignSource] = await Promise.all([
readFile(
new URL(
'../src/game/scenes/BattleScene.ts',
import.meta.url
),
'utf8'
),
readFile(
new URL(
'../src/game/state/campaignState.ts',
import.meta.url
),
'utf8'
)
]);
const publishStart = battleSource.indexOf(
'private publishFirstBattleReport('
);
const publishEnd = battleSource.indexOf(
'\n private resultSubtitle(',
publishStart
);
assert(
publishStart >= 0 && publishEnd > publishStart,
'BattleScene must retain a bounded result-persistence method.'
);
const publishSource = battleSource.slice(
publishStart,
publishEnd
);
assert(
publishSource.includes(
'persistedReport = setFirstBattleReport('
),
'BattleScene must persist its complete battle report through the atomic campaign writer.'
);
assert(
publishSource.includes(
"this.resultReportPersistenceStatus =\n 'failed';"
) &&
publishSource.includes('return false;'),
'A failed campaign write must leave the result screen in an explicit retry state.'
);
assert(
publishSource.includes(
"this.resultReportPersistenceStatus =\n 'complete';"
) &&
publishSource.includes('return true;'),
'A successful campaign write must mark the result report complete.'
);
const continueStart = battleSource.indexOf(
'private handleResultContinue()'
);
const continueEnd = battleSource.indexOf(
'\n private hideBattleResult(',
continueStart
);
assert(
continueStart >= 0 && continueEnd > continueStart,
'BattleScene must retain a bounded result continuation handler.'
);
const continueSource = battleSource.slice(
continueStart,
continueEnd
);
assert(
continueSource.includes(
"this.resultReportPersistenceStatus ===\n 'failed'"
) &&
continueSource.includes(
'!this.publishFirstBattleReport(outcome)'
) &&
continueSource.includes(
'this.showBattleResult(outcome);'
),
'The result CTA must retry persistence in place and redraw the result only after recovery.'
);
assert(
battleSource.includes("return '저장 다시 시도';"),
'The failed result CTA must clearly say “저장 다시 시도”.'
);
assert(
battleSource.includes(
"outcome === 'victory' ||\n this.resultReportPersistenceStatus === 'failed'"
),
'Defeat results with an unsaved report must also expose the persistence retry CTA.'
);
assert(
battleSource.includes(
'const retryButton = this.addResultButton('
) &&
battleSource.includes(
'const titleButton = this.addResultButton('
) &&
battleSource.includes(
'this.setResultButtonEnabled(\n retryButton,\n false'
) &&
battleSource.includes(
'this.setResultButtonEnabled(\n titleButton,\n false'
),
'Normal retry and title navigation must be visibly disabled while result persistence has failed.'
);
assert(
battleSource.includes(
'this.resultNavigationPending ||\n this.blockResultNavigationWhilePersistenceFailed()'
),
'All result navigation must retain a persistence-failure guard even if a disabled button is invoked indirectly.'
);
assert(
battleSource.includes(
"const improvementEnabled =\n this.resultReportPersistenceStatus !==\n 'failed';"
) &&
battleSource.includes(
"improvementEnabled,\n false,\n () => this.openResultSortieImprovement(outcome)"
),
'Result-screen formation improvement must remain disabled until the battle report is durable.'
);
assert(
battleSource.includes(
'reportPersistence:\n this.resultReportPersistenceStatus'
),
'The result persistence state must remain observable to the browser regression.'
);
const persistenceStart = campaignSource.indexOf(
'function persistCampaignState('
);
const persistenceEnd = campaignSource.indexOf(
'\nfunction tryStorage()',
persistenceStart
);
assert(
persistenceStart >= 0 &&
persistenceEnd > persistenceStart,
'Campaign persistence must retain a bounded writer.'
);
const persistenceSource = campaignSource.slice(
persistenceStart,
persistenceEnd
);
const canonicalWrite = persistenceSource.indexOf(
'campaignSaveSlotKey(state.activeSaveSlot)'
);
const compatibilityWrite = persistenceSource.indexOf(
'storage.setItem(campaignStorageKey, serialized)'
);
assert(
canonicalWrite >= 0 &&
compatibilityWrite > canonicalWrite,
'The canonical campaign slot must be written before the compatibility mirror.'
);
console.log(
'Verified battle-result persistence failure/retry UI, debug observability, and canonical-slot-first atomic write contract.'
);