162 lines
4.6 KiB
JavaScript
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.'
|
|
);
|