Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions lib/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
48 changes: 48 additions & 0 deletions test/unit/pause_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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([
Expand Down Expand Up @@ -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)
})
})
Loading