cucumber / cucumber-js

Cucumber for JavaScript
https://cucumber.io
MIT License
5.01k stars 1.09k forks source link

worldParameters not modifiable using Before and After hooks after updating to the latest versions after v10.0.1 #2395

Open xenbartolokath opened 2 months ago

xenbartolokath commented 2 months ago

πŸ‘“ What did you see?

Hello! I've been relying on worldParameters to store environment data since it's labelled as repeatable, as stated in here and here, and it can be modifiable using hooks. However, after upgrading from v10.0.1 to a more latest version, seems like it's not repeatable and modifiable with any steps or hooks anymore, but rather only modifiable using BeforeAll hook.

βœ… What did you expect to see?

I am still able to modify world parameters using any available hooks (Before, After) in v10.0.1. However after v10.1.0 was released (coincidentally the feature worldParameters can be added to BeforeAll hooks), the ability to store worldParameters on Before and After hooks are gone.

πŸ“¦ Which tool/library version are you using?

node v21.5.0 and @cucumber/cucumber v10.0.1

πŸ”¬ How could we reproduce it?

  1. Install v10.0.1
  2. Set any key-value pair on cucumber.js > worldParameters, preferrably a JSON object
  3. Print the parameters on the first Before or After hook to check the update
  4. Modify the key-value pair on any Before and After hook after the first Before or After hook
  5. You will see that it's updating when tests are ran.
  6. Install v10.1.0 or any latest version
  7. Rerun the test and it's not modifying anymore, it's back to its original state after running the next scenario.
  8. Add BeforeAll hook and modify the key value pair
  9. The modification from BeforeAll hook is visible

πŸ“š Any additional context?

Would appreciate if we can fix this as there are a lot of several important states I need to store in between tests using Before and After hooks. If collectively decided to take the new route, would also appreciate an explanation and also a workaround for this.

xenbartolokath commented 2 months ago

I backtracked and saw this: https://github.com/cucumber/cucumber-js/pull/2362, which is understandable. However in my case, I'm using the worldParameters to modify states that are being used across the feature files executed. One use case for this is when I create a test case, where its information is dependent of the previous test cases (chaining). If I merge the test cases into one to avoid chaining, the test case will become super long and will be hard to maintain, and a possibility of pushing huge updates on my current tests. Another one would be the possibility of temporarily changing base URL set in world parameter in the middle of test execution.

Is there a way for me to store a mutable world parameter that stores and modifies state of tests without it being cleared after the next scenario?

xenbartolokath commented 2 months ago

Tagging @davidjgoss here since you made the changes for this. Thank you πŸ™

xenbartolokath commented 2 months ago

Sorry another small issue I saw regarding documentation here:

The world is not available to the hooks BeforeAll or AfterAll as each of these executes outside any particular scenario.

Which is not true anymore after the changes were released in v10.1.0 right?

davidjgoss commented 2 months ago

Sorry for the late reply @xenbartolokath.

As you've noticed, the recent changes were to prevent world parameters being mutable and those changes leaking across scenarios which was considered a bug. When each scenario starts, the world parameters should be reset to what they were after the last BeforeAll hook was run. One of Cucumber's core best practises is that scenarios should be independent and so having state that's effectively global is not something we support in a first-class way. That said, you could look at something like Node.js AsyncLocalStorage to create some state in a BeforeAll that you can access for the rest of the test run.

The world is not available to the hooks BeforeAll or AfterAll as each of these executes outside any particular scenario.

The above statement is still true as it refers to the "world" which is a class instance that lives and dies with the scenario. The world parameters are passed to the world and can be modified in BeforeAll hooks but this is not the same as the world itself.