Fix BDD step definitions to wait for recorder promise chain by fijijavis · Pull Request #5445 · codeceptjs/CodeceptJS
Motivation/Description of the PR
Problem
BDD step definitions require explicit await on all I.* method calls, even when the return value isn't needed. Without await, actions execute out of order because the step function completes before queued recorder actions finish.
This contradicts the documented behavior and differs from how regular CodeceptJS scenarios work, where the recorder handles promise chaining automatically.
Minimal Reproducible Example
Feature File
Feature: BDD Promise Chain Bug Demo Demonstrates that I.say() output appears out of order without await Scenario: Output appears in wrong order Given I am on the CodeceptJS homepage When I click on the Quickstart link Then I should see the Quickstart page And I verify the page title
Stepdef
const { I } = inject(); Given('I am on the CodeceptJS homepage', () => { I.amOnPage('https://codecept.io'); I.say('Step 1: Navigated to homepage'); }); When('I click on the Quickstart link', () => { I.click('Quickstart'); I.say('Step 2: Clicked Quickstart'); }); Then('I should see the Quickstart page', () => { I.see('Quickstart'); I.say('Step 3: Verified Quickstart visible'); }); Then('I verify the page title', () => { I.seeInTitle('CodeceptJS'); I.say('Step 4: Verified title'); });
Actual Output (npx codeceptjs run --features --steps)
> npx codeceptjs run --steps --features CodeceptJS v3.7.6 #StandWithUkraine Using test root "/Users/******/repos/codecept-sandbox" BDD Promise Chain Bug Demo -- /Users/******/repos/codecept-sandbox/features/codecept.feature Demonstrates that I.say() output appears out of order without await Output appears in wrong order Scenario() Given I am on the CodeceptJS homepage "" When I click on the Quickstart link "" Then I should see the Quickstart page "" And I verify the page title "" Step 1: Navigated to homepage Step 2: Clicked Quickstart Step 3: Verified Quickstart visible Step 4: Verified title ✔ OK in 3218ms
Expected Output
> npx codeceptjs run --steps --features CodeceptJS v3.7.6 #StandWithUkraine Using test root "/Users/******/repos/codecept-sandbox" BDD Promise Chain Bug Demo -- /Users/******/repos/codecept-sandbox/features/codecept.feature Demonstrates that I.say() output appears out of order without await Output appears in wrong order Scenario() Given I am on the CodeceptJS homepage "" Step 1: Navigated to homepage When I click on the Quickstart link "" Step 2: Clicked Quickstart Then I should see the Quickstart page "" Step 3: Verified Quickstart visible And I verify the page title "" Step 4: Verified title ✔ OK in 10297ms
Root Cause
In gherkin.js function awaits the step function but doesn't wait for the recorder promise chain to complete:
await fn(...fn.params) // Recorder actions are still queued and executing... step.status = 'passed' // Step marked complete too early
Solution
After awaiting the step function, also await recorder.promise() to ensure all queued actions complete before the step finishes. This aligns BDD step execution with how hooks in asyncWrapper.js already handle the recorder (see injectHook which returns recorder.promise()).
After this fix:
awaitis only needed when you need the return value (e.g.,await I.grabTextFrom())- Actions without return values work correctly without await
- Output appears in the correct order
- Behavior matches the documentation examples which don't use await
Related Documentation
From https://codecept.io/bdd/#step-definitions - the examples show step definitions without await
Given(/I have product with \$(\d+) price/, (price) => { I.amOnPage('/products'); productPage.create({ price }); I.click('Add to cart'); });
Applicable helpers: None
Applicable plugins: None
Type of change
- 🔥 Breaking changes
- 🚀 New functionality
- 🐛 Bug fix
- 🧹 Chore
- 📋 Documentation changes/updates
- ♨️ Hot fix
- 🔨 Markdown files fix - not related to source code
- 💅 Polish code
Checklist:
- Tests have been added
- Documentation has been added (Run
npm run docs) - Lint checking (Run
npm run lint) - Local tests are passed (Run
npm test)