diff --git a/scripts/smoke-secondary-journeys.js b/scripts/smoke-secondary-journeys.js index e8158268..1864a164 100644 --- a/scripts/smoke-secondary-journeys.js +++ b/scripts/smoke-secondary-journeys.js @@ -2440,11 +2440,7 @@ async function smokeLevel(session, route, sceneName, exceptions, { scene?.levelStarted || scene?.gameStarted ), - mobileControls: Boolean( - scene?.mobileControls || - scene?.platformerMobileControls || - scene?.mobileControlElements?.length - ), + mobileControls: scene?.platformerControlsVisible === true, interactiveCount: scene?.input?._list?.length || 0, displayCount: scene?.children?.list?.length || 0, enemyCount: scene?.enemies?.getChildren?.() @@ -2772,6 +2768,9 @@ async function smokeLevel(session, route, sceneName, exceptions, { if (!state.entryAccepted) { throw new Error(`${sceneName} did not accept entry input: ${JSON.stringify(state)}`); } + if (!state.mobileControls) { + throw new Error(`${sceneName} entered gameplay without touch controls: ${JSON.stringify(state)}`); + } if (!state.canvasWidth || !state.canvasHeight) { throw new Error(`${sceneName} rendered a blank-sized canvas`); } diff --git a/src/__tests__/ExpeditionControlLifecycle.test.js b/src/__tests__/ExpeditionControlLifecycle.test.js index 06577a35..8fe94eae 100644 --- a/src/__tests__/ExpeditionControlLifecycle.test.js +++ b/src/__tests__/ExpeditionControlLifecycle.test.js @@ -10,19 +10,34 @@ const LEVEL_FILES = [ 'FinalVoidLevel.js' ]; +const readLevel = fileName => fs.readFileSync( + path.join(__dirname, '../scenes/levels', fileName), + 'utf8' +); + describe('expedition control lifecycle', () => { test.each(LEVEL_FILES)( '%s restores touch controls after its entry overlay', (fileName) => { - const source = fs.readFileSync( - path.join(__dirname, '../scenes/levels', fileName), - 'utf8' - ); + const source = readLevel(fileName); expect(source).toContain('this.showPlatformerMobileControls()'); } ); + test.each(LEVEL_FILES)( + '%s exposes touch controls in its direct boss QA route', + (fileName) => { + const source = readLevel(fileName); + const methodStart = source.indexOf('startTestMode() {'); + const methodEnd = source.indexOf('\n }', methodStart); + const method = source.slice(methodStart, methodEnd); + + expect(methodStart).toBeGreaterThan(-1); + expect(method).toContain('this.showPlatformerMobileControls()'); + } + ); + test('local level-entry previews can force the real touch-control layout', () => { const gameSource = fs.readFileSync( path.join(__dirname, '../game.js'), @@ -63,4 +78,18 @@ describe('expedition control lifecycle', () => { /hidePauseMenu\(\)[\s\S]*this\.showPlatformerMobileControls\(\)/ ); }); + + test('release interaction smoke requires visible touch controls in every level', () => { + const smokeSource = fs.readFileSync( + path.join(__dirname, '../../scripts/smoke-secondary-journeys.js'), + 'utf8' + ); + + expect(smokeSource).toContain( + 'mobileControls: scene?.platformerControlsVisible === true' + ); + expect(smokeSource).toContain( + 'entered gameplay without touch controls' + ); + }); }); diff --git a/src/scenes/levels/CrystalCavesLevel.js b/src/scenes/levels/CrystalCavesLevel.js index 11880e98..d4a19caa 100644 --- a/src/scenes/levels/CrystalCavesLevel.js +++ b/src/scenes/levels/CrystalCavesLevel.js @@ -329,6 +329,8 @@ class CrystalCavesLevel extends PlatformerLevelScene { this.player.setPosition(this.levelWidth - 900, this.levelHeight - 200); } + this.showPlatformerMobileControls(); + this.time.delayedCall(300, () => { this.crystalCoreFound = true; this.startBossFight(); diff --git a/src/scenes/levels/FinalVoidLevel.js b/src/scenes/levels/FinalVoidLevel.js index af097d75..c226b59d 100644 --- a/src/scenes/levels/FinalVoidLevel.js +++ b/src/scenes/levels/FinalVoidLevel.js @@ -315,6 +315,8 @@ class FinalVoidLevel extends PlatformerLevelScene { ); } + this.showPlatformerMobileControls(); + this.time.delayedCall(500, () => this.startBossFight()); if (this.highPowerPreview) { diff --git a/src/scenes/levels/ReefLevel.js b/src/scenes/levels/ReefLevel.js index 8fc17e04..d26000b9 100644 --- a/src/scenes/levels/ReefLevel.js +++ b/src/scenes/levels/ReefLevel.js @@ -311,6 +311,8 @@ class ReefLevel extends PlatformerLevelScene { this.player.setPosition(this.levelWidth - 900, this.levelHeight - 200); } + this.showPlatformerMobileControls(); + this.time.delayedCall(300, () => { this.startBossFight(); });