diff --git a/lib/globals.js b/lib/globals.js index 4ebdd4bf7..816cfc40a 100644 --- a/lib/globals.js +++ b/lib/globals.js @@ -30,10 +30,8 @@ export async function initCodeceptGlobals(dir, config, container) { // pause/inject/share stay global even under noGlobals — they're the everyday // debugging/wiring entry points and have no useful import alternative for // page-object code that runs before the container is available. - global.pause = async (...args) => { - const pauseModule = await import('./pause.js') - return (pauseModule.default || pauseModule)(...args) - } + const pauseModule = await import('./pause.js') + global.pause = pauseModule.default || pauseModule global.inject = () => container.support() global.share = container.share diff --git a/test/unit/pause_test.js b/test/unit/pause_test.js index 50a0b44db..7f91b079a 100644 --- a/test/unit/pause_test.js +++ b/test/unit/pause_test.js @@ -4,6 +4,7 @@ import pause, { setPauseHandler, pauseNow } from '../../lib/pause.js' import recorder from '../../lib/recorder.js' import event from '../../lib/event.js' import store from '../../lib/store.js' +import { initCodeceptGlobals } from '../../lib/globals.js' const settles = (promise, ms = 2000) => Promise.race([ @@ -100,3 +101,50 @@ describe('pause listener lifecycle', () => { expect(recorder.getCurrentSessionId()).to.equal(null) }) }) + +describe('global pause() queue ordering (issue #5652)', () => { + let savedPause + let savedNoGlobals + + beforeEach(async () => { + savedPause = global.pause + savedNoGlobals = store.noGlobals + store.dryRun = false + setPauseHandler(() => Promise.resolve()) + recorder.reset() + recorder.stop() + await initCodeceptGlobals(process.cwd(), { output: 'output', noGlobals: true }, { support() {}, share() {} }) + }) + + afterEach(() => { + setPauseHandler(null) + event.dispatcher.emit(event.test.finished) + recorder.reset() + global.pause = savedPause + store.noGlobals = savedNoGlobals + }) + + it('global.pause is a synchronous function, not an async wrapper', () => { + expect(global.pause).to.equal(pause) + expect(global.pause.constructor.name).to.equal('Function') + }) + + it('queues the pause step between the steps surrounding it in the test body', () => { + // Mirrors a scenario body that runs synchronously to build the recorder queue: + // I.amOnPage(...); pause(); I.see(...); + // The pause step must land *before* `see`, not after the rest of the body. + recorder.start() + recorder.add('amOnPage', () => {}) + global.pause() + recorder.add('see', () => {}) + + const order = recorder.scheduled().split('\n') + const amOnPageIdx = order.indexOf('amOnPage') + const pauseIdx = order.indexOf('Start new session') + const seeIdx = order.indexOf('see') + + expect(pauseIdx, 'pause step must be queued synchronously').to.be.greaterThan(-1) + expect(pauseIdx, 'pause must be queued after the preceding step').to.be.greaterThan(amOnPageIdx) + expect(pauseIdx, 'pause must be queued before the following step').to.be.lessThan(seeIdx) + }) +})