diff --git a/docs/faq.md b/docs/faq.md index 21f00b2a2..530a6602d 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -2,12 +2,16 @@ ## The world instance isn’t available in my hooks or step definitions. -This has frequently been caused by the use of ES6 arrow functions. -If you are using the world instance (which is bound to `this`) in a step definition, then you cannot use ES6 arrow functions for step definitions or hooks because they bind `this` to the current context which prevents the world instance from being injected. +If you are referencing the world instance (which is bound to `this`) in a step definition or hook, then you cannot use ES6 arrow functions. + +Cucumber uses [apply](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) internally to call your [step definition](./support_files/step_definitions.md) and +[hook](./support_files/hooks.md) functions using the world object as `this`. + +Using `apply` [does not work with arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#call_apply_and_bind), so if you need to reference the world, use a regular `function`. ## Why do my definition patterns need to be globally unique instead of unique only within `Given`, `When`, `Then`? -To encourage a ubiquitous, non-ambiguous domain language. +To encourage a ubiquitous, non-ambiguous domain language. Using the same language to mean different things is basically the definition of ambiguous. If you have similar `Given` and `Then` patterns, try adding the word “should” to `Then` patterns. diff --git a/docs/support_files/api_reference.md b/docs/support_files/api_reference.md index 8a98404b3..6ad0f6360 100644 --- a/docs/support_files/api_reference.md +++ b/docs/support_files/api_reference.md @@ -2,7 +2,7 @@ ## API Reference -Each method can be destructed from the object returned by `require('@cucumber/cucumber')`. +Each method can be destructed from the object returned by `require('@cucumber/cucumber')`. --- @@ -14,7 +14,9 @@ Define a new parameter type and optionally convert an output parameter into some * `regexp`: A regular expression (or array of regular expressions) that match the parameter. * `transformer`: An optional function which transforms the captured argument from a string into what is passed to the step definition. If no transform function is specified, the captured argument is left as a string. - The function can be synchronous or return a `Promise` of the transformed value. The value of `this` is the current world, so the function can delegate to world functions. World delegation does not work with arrow functions. + The function can be synchronous or return a `Promise` of the transformed value. The value of `this` is the current world, so the function can delegate to world functions. + Note that your transformer functions cannot reference the [world](./world.md) as `this` if you use + arrow functions. See [FAQ](../faq.md) for details. * `useForSnippets`: Defaults to `true`. That means this parameter type will be used to generate snippets for undefined steps. If the `regexp` frequently matches text you don't intend to be used as arguments, disable its use for snippets with `false`. * `preferForRegexpMatch`: Defaults to `false`. Set to `true` if you use regular expressions and you want this parameter type's `regexp` to take precedence over others during a match. diff --git a/docs/support_files/hooks.md b/docs/support_files/hooks.md index 448585664..df9e25a63 100644 --- a/docs/support_files/hooks.md +++ b/docs/support_files/hooks.md @@ -2,6 +2,9 @@ Hooks are used for setup and teardown the environment before and after each scenario. See the [API reference](./api_reference.md) for the specification of the first argument passed to hooks. Multiple *Before* hooks are executed in the order that they were defined. Multiple *After* hooks are executed in the **reverse** order that they were defined. +Note that your hook functions cannot reference the [world](./world.md) as `this` if you use +arrow functions. See [FAQ](../faq.md) for details. + ```javascript var {After, Before} = require('@cucumber/cucumber'); @@ -121,4 +124,3 @@ AfterStep( function ({result}) { } }); ``` - diff --git a/docs/support_files/step_definitions.md b/docs/support_files/step_definitions.md index 15d116f96..ddcfd9060 100644 --- a/docs/support_files/step_definitions.md +++ b/docs/support_files/step_definitions.md @@ -1,6 +1,6 @@ # Step Definitions -Step definitions (`Given`, `When`, `Then`) are the glue between features written in Gherkin and the actual tests implemenation. +Step definitions (`Given`, `When`, `Then`) are the glue between features written in Gherkin and the actual tests implementation. Cucumber supports two types of expressions: @@ -25,6 +25,9 @@ Given('I have {int} cucumbers in my belly', function (cucumberCount) { }); ``` +Note that your step definition functions cannot reference the [world](./world.md) as `this` if you use +arrow functions. See [FAQ](../faq.md) for details. + ## Regular expressions Matching groups in the regular expression are passed as parameters to the step definition. diff --git a/docs/support_files/world.md b/docs/support_files/world.md index baff7fe17..3d7066575 100644 --- a/docs/support_files/world.md +++ b/docs/support_files/world.md @@ -1,6 +1,11 @@ # World -*World* is an isolated context for each scenario, exposed to the hooks and steps as `this`, enabling you to set and recall some state across the lifecycle of your scenario. A simple example: +*World* is an isolated context for each scenario, exposed to the hooks and steps as `this`, enabling you to set and recall some state across the lifecycle of your scenario. + +Note that your hooks and step definition functions cannot reference the world as `this` if you use +arrow functions. See [FAQ](../faq.md) for details. + +A simple example: ```javascript const { When } = require('@cucumber/cucumber') @@ -45,12 +50,12 @@ class CustomWorld extends World { driver = new seleniumWebdriver.Builder() .forBrowser('firefox') .build() - + constructor(options) { // needed so `attach`, `log` and `parameters` are properly set super(options) } - + // Returns a promise that resolves to the element async waitForElement(locator) { const condition = seleniumWebdriver.until.elementLocated(locator)