cucumber-js
cucumber-js copied to clipboard
CustomWorld Context Retention between Steps of the same Scenario: (JS Only) Backwards Compatibility (Known to be affected 8.11.1-9.6.0) && 10.8.0 with TS 5.4.5
👓 What did you see?
Given I am using a CustomWorld
And I have an empty array of drivers that could be used from the CustomWorld
And I can push a driver to this array through a CustomWorld Method within my Before Hook for use in all scenarios
When I have a Scenario where I set up the driver in the Before hook
And I navigate to a page using the this context's driver successfully in my first Given step
Then the second step no longer sees the driver in the this context that once contained the CustomWorld array
✅ What did you expect to see?
Given I am using a Custom World
And I have an empty array of drivers that could be used from the Custom World
And I can push a driver to this array through a Custom World Method within my Before Hook for use in all scenarios
When I have a Scenario where I set up the driver in the Before hook
And I navigate to a page using the this context's driver successfully in my first Given step
Then the second step should still see the driver in the this context that once contained the Custom World array
📦 Which tool/library version are you using?
@cucumber/cucumber 9.6.0, 9.4.0, 8.11.1 node 22.7.2 - Pure JS, No TypeScript
🔬 How could we reproduce it?
const selenium = require("selenium-webdriver")
class Driver {
constructor(type) {
this.type = type
this.driver = this.new()
}
async new() {
return new selenium.Builder().forBrowser(selenium.Browser.CHROME)
}
}
const {World, setWorldConstructor} = require("@cucumber/cucumber")
class CustomWorld extends World {
active = []
constructor(options) {
super(options)
}
get driver() {
let context = this
return {
new: async function () {
context.active.push((await new Driver().new()).build())
return context.active[context.active.length - 1]
},
active: function (order) {
return context.active[order]
}
}
}
}
setWorldConstructor(CustomWorld)
const {Before, Given} = require("@cucumber/cucumber")
Before(async function () {
await this.driver.new()
let driver = this.driver.active(0)
await driver.manage().window().maximize()
return await driver.get("http://www.google.com")
})
Given("I go to the {site} {string}", async function (site, page) {
const nav = new Navigation(await this.driver.active(0)) // Assigns stated driver to nav.driver within the constructor
nav.site = site.toLowerCase().replaceAll(/\s/g, "")
return await nav.go(page) // Finds page key in object, so we can reference only the page title in the feature file for clear context
})
Given("I log into the {site} as {string}", async function (site, username) {
let login = new Login(await this.driver.active(0))
let password
// Do some stuff here to assign the password via a switch based on username
return await (await login.details(username, password)).via('Submit') // Fills in the details, returns this within login so that we can choose submission method (click, enter or tab from last input and subsequently enter)
})
Previously this allowed for await this.driver.new() and await this.driver.active(0), within any step, as the active list was also brought forward in the world context between steps within the same scenario (browser setup and teardown within the suite was always done in Before and After hooks), but it currently allows for one step to utilise await this.driver.active(0) before losing its CustomWorld context (from what I can gather)
I also tried fixing this by moving the new and active methods out of the getter, just in case context wasn't pushing to this.active correctly, but this didn't do the trick either (it's a shame there isn't an async getter)
This was seen to be working last week.
If arrow functions have been messed around with recently (I've seen in 10.8.0 that arrow functions may have been touched) then this change may have caused a backwards compatibility issue
📚 Any additional context?
I just completed the upgrade to both 10.8.0 and to TypeScript 5.4.5, and this is still an issue (this time it's using .js files instead of .ts, which is at least a plus)
This was occurring up until TypeScript converting from the .cts format (.cjs on conversion), this was because of two forEach loops that were in the format of an arrow function rather than including a const context = this outside of a regular function
The this context is delicate, and when the test runner was consuming tests to run, it was unable to maintain the context
This doesn't happen with 10.8.0 on TS 5.4.5 when you are compiling to ES6.
tsconfig.json that solved, for anyone that is struggling with this too:
{
"compilerOptions": {
"target": "es6",
"lib": ["es6"],
"esModuleInterop": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"moduleResolution": "node",
"types": ["@types/node", "@types/selenium-webdriver", "@types/chai"],
"module": "commonjs"
},
"include": ["./features/**/*", "./support/**/*"],
"exclude": ["./node_modules/"]
}
cucumber.config.cjs used:
const { DEFAULT_THEME } = require('@cucumber/pretty-formatter')
module.exports = {
default: {
parallel: 1,
format: ["html:cucumber-report.html", "@cucumber/pretty-formatter"],
formatOptions: {
theme: {
...DEFAULT_THEME
},
paths: ["./features/**/*.feature"],
},
import: ['./support/**/*.cjs', './features/step_definitions/**/*.cjs']
}
}
Just reran the old JavaScript branch and ran a test to check whether it had been fixed for pure JS implementation - this does need resolving, but a full conversion to TypeScript as outlined above is currently the workaround
This was seen to be working last week.
What changed to go from working to not working?
You have talked here about whether your world retains context correctly. But the errors you have screenshotted suggest a misalignment of step definitions parameters.
Can you post a minimum reproducible example repo?
It's a mix of both - the context of this goes walkabout, is what it boiled down to, and it was trying to use typescript files in a pure js context to begin with
I'll do my best to figure out what the minimum replicable is and produce a repo, it may take a bit of time (I'll likely have one up over the next couple of days)
This issue is stale because it has been open for 3 weeks with no activity. Remove the stale label or comment or this will be closed in another 5 days.
This issue was closed because it has been stalled for 5 days with no activity.