-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add world and context proxies for use in arrow functions #2402
Conversation
Just discussed this with @mpkorstanje who pointed out that an even nicer pattern would be like: const { Given, world } = require('@cucumber/cucumber')
Given('a step', () => {
world.log(world.parameters.foo)
}) This could be achievable by using proxies - I'm going to experiment a bit on this branch and see if it looks viable in reality. TypeScript typing would be one potential challenge. But I like it enough to put some time into it! |
One last thought. To make API evolution easier, maybe don't put methods like And if world is backed by a thread local and passed to another thread (some async call back) what happens? |
Agreed, we should be able to make
The scope in which the proxy works wraps the whole of the hook/step execution and explicitly supports async operations happening within it. Once the hook/step execution has finished that world instance is discarded - everything the Cucumber owns that it pushes in is cloned first. You could I suppose siphon off a reference to it outside of your support code and prevent it being garbage collected. But that's kind of the case anyway with |
🤔 What's changed?
This PR adds two new public exports:
world
which you can reference from a step definition or hook to get the Worldcontext
which you can reference from aBeforeAll
orAfterAll
hook to get the context containing the world parametersI've added this to the docs, but assuming this is successful with early adopters I will raise a follow up PR to switch all our code examples over to use it too, and mark it stable (currently it's beta).
⚡️ What's your motivation?
This provides a solution for the long-standing conflict between wanting to access the "World" instance which has always been bound to
this
, and wanting to use modern JavaScript syntax with arrow functions that don't honour such a binding.You can now write step definitions with arrow functions and use the World like this:
Fixes #2004.
🏷️ What kind of change is this?
♻️ Anything particular you want feedback on?
The exported
world
object is aProxy
which dynamically forwards to the World for the currently-executing test case, which in turn is provided by a Node.jsAsyncLocalStorage
which works very similarly to React context in that we can have a piece of state scoped to the running of some code, and reachable from within that code without passing directly.There are a couple of things to bear in mind with this approach:
AsyncLocalStorage
here is behind a generic facade and does not leak externally.📋 Checklist:
This text was originally generated from a template, then edited by hand. You can modify the template here.