@lynxwall/cucumber-tsflow 5.1.3 → 6.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +546 -544
  2. package/bin/cucumber-tsflow +1 -1
  3. package/lib/behave.d.ts +1 -1
  4. package/lib/behave.js +27 -27
  5. package/lib/cli/argv-parser.d.ts +24 -24
  6. package/lib/cli/argv-parser.js +103 -103
  7. package/lib/cli/index.d.ts +22 -22
  8. package/lib/cli/index.js +101 -96
  9. package/lib/cli/load-configuration.d.ts +20 -20
  10. package/lib/cli/load-configuration.js +92 -92
  11. package/lib/cli/run.d.ts +1 -1
  12. package/lib/cli/run.js +49 -44
  13. package/lib/cucumber/binding-decorator.d.ts +10 -10
  14. package/lib/cucumber/binding-decorator.js +180 -180
  15. package/lib/cucumber/binding-registry.d.ts +82 -82
  16. package/lib/cucumber/binding-registry.js +216 -218
  17. package/lib/cucumber/hook-decorators.d.ts +46 -46
  18. package/lib/cucumber/hook-decorators.js +102 -102
  19. package/lib/cucumber/managed-scenario-context.d.ts +21 -21
  20. package/lib/cucumber/managed-scenario-context.js +96 -95
  21. package/lib/cucumber/message-collector.d.ts +81 -80
  22. package/lib/cucumber/message-collector.js +251 -241
  23. package/lib/cucumber/parallel/coordinator.d.ts +79 -78
  24. package/lib/cucumber/parallel/coordinator.js +247 -228
  25. package/lib/cucumber/parallel/run-worker.d.ts +1 -1
  26. package/lib/cucumber/parallel/run-worker.js +31 -31
  27. package/lib/cucumber/parallel/worker.d.ts +30 -31
  28. package/lib/cucumber/parallel/worker.js +104 -104
  29. package/lib/cucumber/run-cucumber.d.ts +14 -14
  30. package/lib/cucumber/run-cucumber.js +117 -117
  31. package/lib/cucumber/runtime.d.ts +25 -25
  32. package/lib/cucumber/runtime.js +39 -39
  33. package/lib/cucumber/step-definition-decorators.d.ts +24 -24
  34. package/lib/cucumber/step-definition-decorators.js +91 -91
  35. package/lib/cucumber/utils.d.ts +16 -16
  36. package/lib/cucumber/utils.js +77 -77
  37. package/lib/esnode.js +19 -19
  38. package/lib/esvue.d.ts +1 -1
  39. package/lib/esvue.js +41 -41
  40. package/lib/formatters/behave-json-formatter.d.ts +49 -49
  41. package/lib/formatters/behave-json-formatter.js +75 -75
  42. package/lib/formatters/tsflow-snippet-syntax.d.ts +9 -9
  43. package/lib/formatters/tsflow-snippet-syntax.js +90 -93
  44. package/lib/gherkin/configuration.d.ts +30 -30
  45. package/lib/gherkin/configuration.js +26 -26
  46. package/lib/gherkin/gherkin-feature.d.ts +28 -28
  47. package/lib/gherkin/gherkin-feature.js +333 -335
  48. package/lib/gherkin/gherkin-manager.d.ts +29 -29
  49. package/lib/gherkin/gherkin-manager.js +114 -113
  50. package/lib/gherkin/models.d.ts +45 -45
  51. package/lib/gherkin/models.js +2 -2
  52. package/lib/index.d.ts +4 -4
  53. package/lib/index.js +22 -22
  54. package/lib/snippet.d.ts +1 -1
  55. package/lib/snippet.js +27 -27
  56. package/lib/transpilers/esbuild-transpiler.d.ts +4 -4
  57. package/lib/transpilers/esbuild-transpiler.js +19 -21
  58. package/lib/transpilers/esbuild.d.ts +12 -12
  59. package/lib/transpilers/esbuild.js +54 -54
  60. package/lib/transpilers/vue-sfc/compiler.d.ts +7 -7
  61. package/lib/transpilers/vue-sfc/compiler.js +21 -21
  62. package/lib/transpilers/vue-sfc/index.d.ts +23 -23
  63. package/lib/transpilers/vue-sfc/index.js +47 -45
  64. package/lib/transpilers/vue-sfc/main.d.ts +8 -8
  65. package/lib/transpilers/vue-sfc/main.js +248 -248
  66. package/lib/transpilers/vue-sfc/script.d.ts +5 -5
  67. package/lib/transpilers/vue-sfc/script.js +41 -41
  68. package/lib/transpilers/vue-sfc/template.d.ts +8 -8
  69. package/lib/transpilers/vue-sfc/template.js +101 -101
  70. package/lib/transpilers/vue-sfc/types.d.ts +55 -55
  71. package/lib/transpilers/vue-sfc/types.js +2 -2
  72. package/lib/transpilers/vue-sfc/utils/descriptorCache.d.ts +13 -13
  73. package/lib/transpilers/vue-sfc/utils/descriptorCache.js +67 -67
  74. package/lib/transpilers/vue-sfc/utils/error.d.ts +3 -3
  75. package/lib/transpilers/vue-sfc/utils/error.js +22 -22
  76. package/lib/transpilers/vue-sfc/utils/query.d.ts +13 -13
  77. package/lib/transpilers/vue-sfc/utils/query.js +35 -35
  78. package/lib/tsnode.js +17 -17
  79. package/lib/tsvue.d.ts +1 -1
  80. package/lib/tsvue.js +39 -39
  81. package/lib/types/scenario-context.d.ts +16 -16
  82. package/lib/types/scenario-context.js +17 -17
  83. package/lib/types/scenario-info.d.ts +16 -16
  84. package/lib/types/scenario-info.js +23 -21
  85. package/lib/types/step-binding-flags.d.ts +53 -53
  86. package/lib/types/step-binding-flags.js +58 -58
  87. package/lib/types/step-binding.d.ts +50 -50
  88. package/lib/types/step-binding.js +17 -17
  89. package/lib/types/types.d.ts +21 -21
  90. package/lib/types/types.js +2 -2
  91. package/lib/utils/helpers.d.ts +6 -6
  92. package/lib/utils/helpers.js +17 -17
  93. package/lib/utils/logger.d.ts +3 -3
  94. package/lib/utils/logger.js +29 -29
  95. package/lib/utils/our-callsite.d.ts +27 -27
  96. package/lib/utils/our-callsite.js +73 -71
  97. package/lib/version.d.ts +1 -1
  98. package/lib/version.js +5 -5
  99. package/package.json +58 -58
package/README.md CHANGED
@@ -1,544 +1,546 @@
1
- ![CI](https://github.com/lynxwall/cucumber-js-tsflow/workflows/CI/badge.svg)
2
-
3
- # cucumber-tsflow
4
-
5
- Provides 'specflow' like bindings for CucumberJS 8.5.0+ in TypeScript 1.7+.
6
-
7
- Supports Vue3 files in cucumber tests.
8
-
9
- ## Fork description
10
- This is a detached fork of <https://github.com/timjroberts/cucumber-js-tsflow>. It has had the <https://github.com/wudong/cucumber-js-tsflow/tree/before_after_all_hooks> branch merged into it, which adds support for beforeAll and afterAll hooks.
11
-
12
- In addition, the following features have been added:
13
- - Test runner using the cucumber-tsflow command
14
- - Uses underlying cucumber api to run tests
15
- - Typescript and esbuild transpiler support
16
- - Vue3 transformer used to handle .vue files in tests
17
- - Timeout in step definitions and hooks
18
- - WrapperOptions in step definitions
19
- - BeforeStep and AfterStep Hooks
20
- - Boolean custom definition added to cucumber expressions
21
- - Support for Parallel execution of tests
22
- - A behave-json-formatter that fixes json so it can be used with Behave Pro
23
- - tsflow-snippet-syntax used to format snippet examples
24
- - snippets use the [Cucumber Expressions](https://github.com/cucumber/cucumber-expressions#readme) Syntax for parameters
25
-
26
- <div style="padding: 15px; border: 1px solid transparent; border-color: transparent; margin-bottom: 20px; border-radius: 4px; color: #8a6d3b;; background-color: #fcf8e3; border-color: #faebcc;">
27
- <strong>Note:</strong> With recent updates you must use the <strong>cucumber-tsflow</strong> command to execute tests. This command executes the same API calls that cucumber-js does and supports all of the options and features as cucumber-js along with new features listed above.
28
- </div>
29
-
30
- ## Quick Start
31
-
32
- cucumber-tsflow uses TypeScript Decorators to create SpecFlow like bindings for TypeScript classes and methods that allow those classes and methods to be used in your CucumberJS support files. As such, cucumber-tsflow has a dependency on CucumberJS and extends CucumberJS functionality. However, you can run your specifications using the cucumber-tsflow command line tool.
33
-
34
- ### Install @lynxwall/cucumber-tsflow
35
-
36
- #### npm
37
-
38
- ```bash
39
- npm install @lynxwall/cucumber-tsflow --save-dev
40
- ```
41
-
42
- #### yarn
43
-
44
- ```bash
45
- yarn add --dev @lynxwall/cucumber-tsflow
46
- ```
47
-
48
- **Note**: Latest updates with context management requires use of cucumber-tsflow to execute tests. As a result, you do not need to install @cucumber/cucumber. All necessary cucumber packages are installed as dependencies of cucumber-tsflow. If you do have @cucumber/cucumber in dependencies please remove the reference to avoid conflicts.
49
-
50
- ### Create .feature files to describe your specifications
51
-
52
- By default, CucumberJS looks for .feature files in a folder called 'features', so create that folder and then create a new file called 'my_feature.feature':
53
-
54
- ```gherkin
55
- # features/my_feature.feature
56
-
57
- Feature: Example Feature
58
- This is an example feature
59
-
60
- Scenario: Adding two numbers
61
- Given I enter 2 and 8
62
- When checking the results
63
- Then I receive the result 10
64
- ```
65
-
66
- ### Create the Support Files to support the Feature
67
-
68
- By default, CucumberJS looks for support files beneath the 'features' folder. You can override this on the cucumber-tsflow command line by specifying the '-r' option. However, let's work with the default and create our code in the default location. We need to write step definitions to support the three steps that we created above.
69
-
70
- Create a new 'ArithmeticSteps.ts' file:
71
-
72
- ```javascript
73
- // features/ArithmeticSteps.ts
74
-
75
- import { binding, given, then } from "@lynxwall/cucumber-tsflow";
76
-
77
- @binding()
78
- export default class ArithmeticSteps {
79
- private computedResult = 0;
80
-
81
- @given('I enter {int} and {int}')
82
- iEnterintAndint(int: number, int2: number): any {
83
- this.computedResult = int + int2;
84
- }
85
-
86
- @when('checking the results')
87
- checkingTheResults(): any {
88
- expect(this.computedResult).to.be.greaterThan(0);
89
- }
90
-
91
- @then('I receive the result {int}')
92
- iReceiveTheResultint(int: number): any {
93
- if (int !== this.computedResult) {
94
- throw new Error('Arithmetic Error');
95
- }
96
- }
97
- }
98
- ```
99
-
100
- **Note**: how the cucumber-tsflow Decorators are being used to bind the methods in the class. During runtime, these Decorators simply call the Cucumber code on your behalf in order to register callbacks with Given(), When(), Then(), etc. The callbacks that are being registered with Cucumber are wrappers around your bound class.
101
-
102
- ### Compiling your TypeScript Support Code
103
-
104
- If not using one of the [transpilers](#transpiler-and-vue3-supported) listed below you'll need a `tsconfig.json` file to compile your code. You'll also need to ensure that the `"moduleResolution": "node"` compiler option is set in order to bring in the typings that are shipped with cucumber-tsflow.
105
-
106
- Running the cucumber-tsflow command will execute your features along with the support code that you've created in the class.
107
-
108
- In this quick example test state is encapsulated directly in the class. As your test suite grows larger and step definitions get shared between multiple classes, you can begin using '[Context Injection](#context-injection)' to share state between running step definitions.
109
-
110
- ## Cucumber-tsflow Test Runner
111
-
112
- As mentioned previously, with recent updates cucumber-tsflow must be used to execute tests. The reason for this update was to replace before and after hooks previously used to manage context with a message handler. Executing tests with cucumber-tsflow uses the same API calls that cucumber-js does. The only differences are updates to support new configuration parameters along with updates to step definitions that set the correct location.
113
-
114
- The following example demonstrates executing cucumber-tsflow from the command line to execute tests:
115
-
116
- ```bash
117
- C:\GitHub\cucumber-js-tsflow (dev -> origin)
118
- λ npx cucumber-tsflow
119
- Loading configuration and step definitions...
120
-
121
- beforeAll was called
122
- ......@basic after hook is called.
123
- .......@basic after hook is called.
124
- .......@basic after hook is called.
125
- ...........@tags1 after hook is called.
126
- ......@tagging afterTag method is called
127
- .........<Suspense> is an experimental feature and its API will likely change.
128
- ..afterAll was called
129
-
130
- 8 scenarios (8 passed)
131
- 24 steps (24 passed)
132
- 0m00.076s (executing steps: 0m00.040s)
133
- ```
134
-
135
- To recap, cucumber-tsflow extends cucumber-js, which means that all options and features provided by cucumber-js are supported with cucumber-tsflow. In other words, when executing tests using cucumber-tsflow the underlying cucumber API is actually used to run the tests.
136
-
137
- ### Executing with script in package.json
138
-
139
- You can also add a script to package.json to execute the tests as shown below:
140
-
141
- ```json
142
- "scripts": {
143
- "test": "cucumber-tsflow -p default"
144
- }
145
- ```
146
-
147
- With this script in place you can execute the tests using npm or yarn,
148
-
149
- #### npm
150
-
151
- ```bash
152
- npm run test
153
- ```
154
-
155
- #### yarn
156
-
157
- ```bash
158
- yarn test
159
- ```
160
-
161
- ## New Configuration options
162
-
163
- As mentioned, when using cucumber-tsflow to execute tests all of the configuration options documented here are supported: <https://github.com/cucumber/cucumber-js/blob/v8.0.0/docs/configuration.md>
164
-
165
- In addition to cucumber configuration options the following two options have been added:
166
-
167
- | Name | Type | Repeatable | CLI Option | Description | Default |
168
- |-------------------|------------|------------|---------------------------|-------------------------------------------------------------------------------------------------------------------|---------|
169
- | `transpiler` | `string` | No | `--transpiler` | Name of the transpiler to use: esnode, esvue, tsnode or tsvue | esnode |
170
- | `debugFile` | `string` | No | `--debug-file` | Path to a file with steps for debugging | |
171
-
172
- #### Transpiler and Vue3 supported
173
-
174
- Using TypeScript with cucumberJs requires a couple of tsconfig.json parameters and the output needs to be commonJS as documented here: <https://github.com/cucumber/cucumber-js/blob/v8.0.0/docs/transpiling.md>
175
-
176
- As a result, cucumber-tsflow adds several configurations for transpiling TypeScript code using the recommended configuration. In addition, support has been added to transform .vue files during test execution allowing you to test Vue SFC components using cucumber.
177
-
178
- The following transpilers are provided:
179
- - **esnode**: Uses esbuild to transpile TypeScript code for node test execution.
180
- - **esvue**: Uses esbuild to transpile TypeScript code and adds a hook for .vue files, which transforms Vue SFC components into commonJS.
181
- - **jsdom** is also loaded globally to support loading and testing Vue SFC components.
182
- - **tsnode**: Uses typescript to transpile TypeScript code for node test execution.
183
- - **tsvue**: Uses typescript to transpile TypeScript code and adds a hook for .vue files, which transforms Vue SFC components into commonJS.
184
- - **jsdom** is also loaded globally to support loading and testing Vue SFC components.
185
-
186
- ##### Using the transpiler configuration option
187
-
188
- When configuring cucumber to execute tests you can specify which transpiler to use with the `transpiler` configuration option as shown below:
189
-
190
- ```json
191
- {
192
- "default": {
193
- "transpiler": "esvue",
194
- "publishQuiet": true
195
- }
196
- }
197
- ```
198
-
199
- ##### Alternate without using the transpiler option
200
-
201
- You can also use the `requireModule` parameter to configure a transpiler. The following example shows how to configure cucumber to use the `esvue` transpiler with the `requireModule` option.
202
-
203
- ```json
204
- {
205
- "default": {
206
- "requireModule": ["@lynxwall/cucumber-tsflow/lib/esvue"],
207
- "publishQuiet": true
208
- }
209
- }
210
- ```
211
-
212
- #### Debug File support
213
-
214
- The new `debugFile` configuration option allows you to specify a .ts file with step definitions that you want to debug. This will search for a matching feature and execute the tests in that feature. This option is helpful when debugging tests and you don't want to run all of the tests.
215
-
216
- If using VSCode to edit your project the following launch configurations can be used:
217
-
218
- ##### Debug All
219
-
220
- ```json
221
- {
222
- "name": "Debug All",
223
- "type": "node",
224
- "request": "launch",
225
- "program": "${workspaceRoot}/node_modules/@lynxwall/cucumber-tsflow/bin/cucumber-tsflow",
226
- "stopOnEntry": true,
227
- "args": ["-p", "default"],
228
- "cwd": "${workspaceRoot}",
229
- "runtimeExecutable": null,
230
- "runtimeArgs": ["--nolazy"],
231
- "env": {
232
- "NODE_ENV": "development"
233
- },
234
- "console": "integratedTerminal",
235
- "sourceMaps": true
236
- }
237
- ```
238
-
239
- ##### Debug Feature
240
-
241
- ```json
242
- {
243
- "name": "Debug Feature",
244
- "type": "node",
245
- "request": "launch",
246
- "program": "${workspaceRoot}/node_modules/@lynxwall/cucumber-tsflow/bin/cucumber-tsflow",
247
- "stopOnEntry": true,
248
- "args": ["--debug-file", "${file}", "-p", "default"],
249
- "cwd": "${workspaceRoot}",
250
- "runtimeExecutable": null,
251
- "runtimeArgs": ["--nolazy"],
252
- "env": {
253
- "NODE_ENV": "development"
254
- },
255
- "console": "integratedTerminal",
256
- "sourceMaps": true
257
- }
258
- ```
259
-
260
- **Note:** When using `Debug Feature` you'll need to have the step definition file open as the current file in VSCode. The current file path is passed into the debugger as the ${file} argument for --debug-file.
261
-
262
- ## Bindings
263
-
264
- Bindings provide the automation that connects a specification step in a Gherkin feature file to some code that
265
- executes for that step. When using Cucumber with TypeScript you can define this automation using a 'binding' class:
266
-
267
- ```javascript
268
- import { binding } from "@lynxwall/cucumber-tsflow";
269
-
270
- @binding()
271
- export default class MySteps {
272
- ...
273
- }
274
- ```
275
-
276
- ## Step Definitions
277
-
278
- Step definitions can be bound to automation code in a 'binding' class by implementing a public function that is
279
- bound with a 'given', 'when' or 'then' binding decorator:
280
-
281
- ```javascript
282
- import { binding, given, when, then } from "@lynxwall/cucumber-tsflow";
283
-
284
- @binding()
285
- export default class MySteps {
286
- ...
287
- @given('I perform a search using the value {string}')
288
- public givenAValueBasedSearch(searchValue: string): void {
289
- ...
290
- }
291
- ...
292
- }
293
- ```
294
-
295
- The function follows the same requirements of functions you would normally supply to Cucumber which means that the
296
- functions may be synchronous by returning nothing, use the callback, or return a `Promise<T>`. Additionally, the
297
- function may also be `async` following the TypeScript async semantics.
298
-
299
- ### Boolean Custom Parameter
300
-
301
- As mentioned, cucumber-tsflow uses Cucumber Expressions for snippet syntax, which provides different parameter types used in expressions. However, a boolean type is not provided by default.
302
-
303
- As a result, a new custom parameter type has been added for boolean matches. For example, when a scenario step contains the words `true` or `false` they will be replaced with the `{boolean}` parameter expression and passed into the step function.
304
-
305
- The following Scenario uses boolean values in the Given and Then statements:
306
-
307
- ```gherkin
308
- Scenario: Boolean type supported
309
- Given I pass true into a step
310
- When checking the boolean value
311
- Then we can see that true was passed in
312
- ```
313
-
314
- The associated step definition replaces `true` in this scenario with a `{boolean}` expression as shown below:
315
-
316
- ```javascript
317
- @given('I pass {boolean} into a step')
318
- iPassbooleanIntoAStep(boolean: boolean): any {
319
- this.boolValue = boolean;
320
- }
321
-
322
- @when('checking the boolean value')
323
- checkingTheBooleanValue(): any {
324
- expect(this.boolValue).not.to.be.undefined;
325
- }
326
-
327
- @then('we can see that {boolean} was passed in')
328
- weCanThatbooleanWasPassedIn(boolean: boolean): any {
329
- expect(this.boolValue).to.equal(boolean);
330
- }
331
- ```
332
-
333
- More information on Cucumber Expressions and Custom Parameter Types can be found here: <https://github.com/cucumber/cucumber-expressions#readme>
334
-
335
- ### Step Tags
336
-
337
- Step definitions can be conditionally selected for execution based on the tags of the scenario by supplying tags when using the binding
338
- decorators:
339
-
340
- ```javascript
341
- @given('I perform a search using the value {string}')
342
- public givenAValueBasedSearch(searchValue: string): void {
343
- ...
344
- // The default step definition
345
- ...
346
- }
347
-
348
- @given('I perform a search using the value {string}', "@tagName")
349
- public givenAValueBasedSearch(searchValue: string): void {
350
- ...
351
- // The step definition that will execute if the feature or
352
- // scenario has the @tagName defined on it
353
- ...
354
- }
355
- ```
356
-
357
- **Note**: Tags added to steps work the same as "Tagged Hooks" documented here: <https://github.com/cucumber/cucumber-js/blob/v8.0.0/docs/support_files/hooks.md>
358
-
359
- ## Hooks
360
-
361
- Hooks can be used to perform additional automation on specific events such as before or after scenario execution.
362
- Hooks can be restricted to run for only features or scenarios with a specific tag:
363
-
364
- ```typescript
365
- import { binding, beforeAll, before, beforeStep, afterStep, after, afterAll } from "@lynxwall/cucumber-tsflow";
366
-
367
- @binding()
368
- class MySteps {
369
- ...
370
- @beforeAll()
371
- public beforeAllTests(): void {
372
- ...
373
- }
374
-
375
- @before()
376
- public beforeAllScenarios(): void {
377
- ...
378
- }
379
-
380
- @before("@requireTempDir")
381
- public async beforeAllScenariosRequiringTempDirectory(): Promise<void> {
382
- let tempDirInfo = await this.createTemporaryDirectory();
383
-
384
- ...
385
- }
386
-
387
- @beforeStep('@addNumbers')
388
- public beforeStep() {
389
- ...
390
- }
391
-
392
- @afterStep('@addNumbers')
393
- public afterStep() {
394
- ...
395
- }
396
-
397
- @after()
398
- public afterAllScenarios(): void {
399
- ...
400
- }
401
-
402
- @after("@requireTmpDir")
403
- public afterAllScenarios(): void {
404
- ...
405
- }
406
-
407
- @afterAll()
408
- public afterAllTests(): void {
409
- ...
410
- }
411
- }
412
-
413
- export = MySteps;
414
- ```
415
-
416
- ### Timeout in step definition and hooks
417
-
418
- In step definition and hooks, we can set timeout. For example, to set the timeout for a step to be 20000ms, we can do:
419
-
420
- ```typescript
421
-
422
- @given('I perform a search using the value {string}', undefined, 20000)
423
- public givenAValueBasedSearch(searchValue: string): void {
424
- ...
425
- // this step will time tou in 20000ms.
426
- ...
427
- }
428
-
429
- ```
430
-
431
- tsflow currently doesn't have a way to define a global default step timeout,
432
-
433
- but it can be easily done through CucumberJS ```setDefaultTimeout``` function.
434
-
435
- ### Passing WrapperOptions
436
-
437
- In step definition, we can pass additional wrapper options to cucumber js. For example:
438
-
439
- ```typescript
440
-
441
- @given('I perform a search using the value {string}', undefined, undefined, {retry: 2})
442
- public givenAValueBasedSearch(searchValue: string): void {
443
- ...
444
- // this step will be retried by cucumber js
445
- ...
446
- }
447
-
448
- ```
449
-
450
- ### Using behave-json-formatter and tsflow-snippet-syntax
451
-
452
- Changing the formatter used for generating json along with changing the Snippet Syntax can be done through the CucumberJS configuration file.
453
-
454
- If it doesn't already exist, create a file named cucumber.json at the root of your project. This is where we can configure different options for CucumberJS.
455
-
456
- #### Using the behave json formatter
457
-
458
- The following example shows how to configure the behave formatter in cucumber.json. The tsflow-snippet-syntax module is configured as the default snippet syntax and does not require configuration. However, you can override the snippet syntax as documented here: <https://github.com/cucumber/cucumber-js/blob/v8.0.0/docs/custom_snippet_syntaxes.md>
459
-
460
- ```javascript
461
- {
462
- "default": {
463
- "format": [
464
- "behave:cucumber_report.json"
465
- ],
466
- "publishQuiet": true
467
- }
468
- }
469
- ```
470
-
471
- ## Sharing Data between Bindings
472
-
473
- ### Context Injection
474
-
475
- Like 'specflow', cucumber-tsflow supports a simple dependency injection framework that will instantitate and inject class instances into 'binding' classes for each execuing scenario.
476
-
477
- To use context injection:
478
-
479
- - Create simple classes representing the shared data (they *must* have default constructors)
480
- - Define a constructor on the 'binding' classes that will require the shared data that accepts the context objects as parameters
481
- - Update the `@binding()` decorator to indicate the types of context objects that are required by the 'binding' class
482
-
483
- ```javascript
484
- import { binding, given, when } from '@lynxwall/cucumber-tsflow';
485
- import { Workspace } from './workspace';
486
- import { expect } from 'chai';
487
-
488
- @binding([Workspace])
489
- export default class InjectionTestSteps1 {
490
- constructor(private workspace: Workspace) {}
491
-
492
- @given('The Workspace is available and valid')
493
- theWorkspaceIsAvailableAndValid() {
494
- expect(this.workspace).not.to.be.undefined;
495
- expect(this.workspace.world).not.to.be.undefined;
496
- }
497
-
498
- @when('I change the workspace in one step definition class')
499
- whenIChangeTheWorkspaceInOneStep() {
500
- this.workspace.someValue = 'value changed';
501
- }
502
- }
503
- ```
504
-
505
- ### Access to Cucumber.js World object
506
-
507
- The context object that you inject can also be configured to access the [World](https://github.com/cucumber/cucumber-js/blob/main/docs/support_files/world.md) object from Cucumber.js, which provides a method for adding attachments, a method for logging information from hooks/steps and an object of parameters passed in via configuration.
508
-
509
- The first step is to define a world property on the class that you're injecting:
510
-
511
- ```javascript
512
- import { World } from '@cucumber/cucumber';
513
-
514
- export class Workspace {
515
- public world!: World;
516
- public someValue = '';
517
- }
518
- ```
519
-
520
- Next you'll need to initialize the world property in a ***@before*** hook so that it's available to all steps in a scenario. My approach is to add a new file to the steps folder that is dedicated to initializing the class (Workspace in this example) in a ***@before*** hook.
521
-
522
- For this example I've added a file named world-context.ts with the following content:
523
-
524
- ```javascript
525
- import { binding, before } from '@lynxwall/cucumber-tsflow';
526
- import { Workspace } from './workspace';
527
- import { World } from '@cucumber/cucumber';
528
-
529
- @binding([Workspace])
530
- export default class WorldContext {
531
- _worldObj?: World;
532
-
533
- constructor(private workspace: Workspace) {}
534
-
535
- @before()
536
- beforeScenario() {
537
- this.workspace.world = this._worldObj as World;
538
- }
539
- }
540
- ```
541
-
542
- As described in the section on Hooks, the ***beforeScenario*** function will be executed before each scenario. We're accessing a member property that was bound to the class instance during creation of each step class, and initializing the world property.
543
-
544
- **NOTE:** Examples of this and other tests can be found in the GitHub repository.
1
+ ![CI](https://github.com/lynxwall/cucumber-js-tsflow/workflows/CI/badge.svg)
2
+
3
+ # cucumber-tsflow
4
+
5
+ Provides 'specflow' like bindings for CucumberJS 9.1.0+ in TypeScript 4.0+.
6
+
7
+ Supports Vue3 files in cucumber tests.
8
+
9
+ ## Fork description
10
+ This is a detached fork of <https://github.com/timjroberts/cucumber-js-tsflow>. It has had the <https://github.com/wudong/cucumber-js-tsflow/tree/before_after_all_hooks> branch merged into it, which adds support for beforeAll and afterAll hooks.
11
+
12
+ In addition, the following features have been added:
13
+ - Test runner using the cucumber-tsflow command.
14
+ - Uses underlying cucumber api to run tests.
15
+ - Returns three exit codes:
16
+ - **0** = all scenarios passing, **1** = implemented scenarios are passing but there are pending, undefined or unknown scenario steps, **2** = one or more scenario steps have failed.
17
+ - Typescript and esbuild transpiler support.
18
+ - Vue3 transformer used to handle .vue files in tests.
19
+ - Timeout in step definitions and hooks.
20
+ - WrapperOptions in step definitions.
21
+ - BeforeStep and AfterStep Hooks.
22
+ - Boolean custom definition added to cucumber expressions.
23
+ - Support for Parallel execution of tests.
24
+ - A behave-json-formatter that fixes json so it can be used with Behave Pro.
25
+ - tsflow-snippet-syntax used to format snippet examples.
26
+ - snippets use the [Cucumber Expressions](https://github.com/cucumber/cucumber-expressions#readme) Syntax for parameters.
27
+
28
+ <div style="padding: 15px; border: 1px solid transparent; border-color: transparent; margin-bottom: 20px; border-radius: 4px; color: #8a6d3b; background-color: #fcf8e3; border-color: #faebcc;">
29
+ <strong><span style="color: #000">Note:</span></strong> With recent updates you must use the <strong><span style="color: #000">cucumber-tsflow</span></strong> command to execute tests. This command executes the same API calls that cucumber-js does and supports all of the options and features as cucumber-js along with new features listed above.
30
+ </div>
31
+
32
+ ## Quick Start
33
+
34
+ cucumber-tsflow uses TypeScript Decorators to create SpecFlow like bindings for TypeScript classes and methods that allow those classes and methods to be used in your CucumberJS support files. As such, cucumber-tsflow has a dependency on CucumberJS and extends CucumberJS functionality. However, you run your specifications using the cucumber-tsflow command line tool.
35
+
36
+ ### Install @lynxwall/cucumber-tsflow
37
+
38
+ #### npm
39
+
40
+ ```bash
41
+ npm install @lynxwall/cucumber-tsflow --save-dev
42
+ ```
43
+
44
+ #### yarn
45
+
46
+ ```bash
47
+ yarn add --dev @lynxwall/cucumber-tsflow
48
+ ```
49
+
50
+ **Note**: Latest updates with context management requires use of cucumber-tsflow to execute tests. As a result, you do not need to install @cucumber/cucumber. All necessary cucumber packages are installed as dependencies of cucumber-tsflow. If you do have @cucumber/cucumber in dependencies please remove the reference to avoid conflicts.
51
+
52
+ ### Create .feature files to describe your specifications
53
+
54
+ By default, CucumberJS looks for .feature files in a folder called 'features', so create that folder and then create a new file called 'my_feature.feature':
55
+
56
+ ```gherkin
57
+ # features/my_feature.feature
58
+
59
+ Feature: Example Feature
60
+ This is an example feature
61
+
62
+ Scenario: Adding two numbers
63
+ Given I enter 2 and 8
64
+ When checking the results
65
+ Then I receive the result 10
66
+ ```
67
+
68
+ ### Create the Support Files to support the Feature
69
+
70
+ By default, CucumberJS looks for support files beneath the 'features' folder. You can override this on the cucumber-tsflow command line by specifying the '-r' option. However, let's work with the default and create our code in the default location. We need to write step definitions to support the three steps that we created above.
71
+
72
+ Create a new 'ArithmeticSteps.ts' file:
73
+
74
+ ```javascript
75
+ // features/ArithmeticSteps.ts
76
+
77
+ import { binding, given, then } from "@lynxwall/cucumber-tsflow";
78
+
79
+ @binding()
80
+ export default class ArithmeticSteps {
81
+ private computedResult = 0;
82
+
83
+ @given('I enter {int} and {int}')
84
+ iEnterintAndint(int: number, int2: number): any {
85
+ this.computedResult = int + int2;
86
+ }
87
+
88
+ @when('checking the results')
89
+ checkingTheResults(): any {
90
+ expect(this.computedResult).to.be.greaterThan(0);
91
+ }
92
+
93
+ @then('I receive the result {int}')
94
+ iReceiveTheResultint(int: number): any {
95
+ if (int !== this.computedResult) {
96
+ throw new Error('Arithmetic Error');
97
+ }
98
+ }
99
+ }
100
+ ```
101
+
102
+ **Note**: how the cucumber-tsflow Decorators are being used to bind the methods in the class. During runtime, these Decorators simply call the Cucumber code on your behalf in order to register callbacks with Given(), When(), Then(), etc. The callbacks that are being registered with Cucumber are wrappers around your bound class.
103
+
104
+ ### Compiling your TypeScript Support Code
105
+
106
+ If not using one of the [transpilers](#transpiler-and-vue3-supported) listed below you'll need a `tsconfig.json` file to compile your code. You'll also need to ensure that the `"moduleResolution": "node"` compiler option is set in order to bring in the typings that are shipped with cucumber-tsflow.
107
+
108
+ Running the cucumber-tsflow command will execute your features along with the support code that you've created in the class.
109
+
110
+ In this quick example test state is encapsulated directly in the class. As your test suite grows larger and step definitions get shared between multiple classes, you can begin using '[Context Injection](#context-injection)' to share state between running step definitions.
111
+
112
+ ## Cucumber-tsflow Test Runner
113
+
114
+ As mentioned previously, with recent updates cucumber-tsflow must be used to execute tests. The reason for this update was to replace before and after hooks previously used to manage context with a message handler. Executing tests with cucumber-tsflow uses the same API calls that cucumber-js does. The only differences are updates to support new configuration parameters along with updates to step definitions that set the correct location.
115
+
116
+ The following example demonstrates executing cucumber-tsflow from the command line to execute tests:
117
+
118
+ ```cmd
119
+ C:\GitHub\cucumber-js-tsflow (dev -> origin)
120
+ λ npx cucumber-tsflow
121
+ Loading configuration and step definitions...
122
+
123
+ beforeAll was called
124
+ ......@basic after hook is called.
125
+ .......@basic after hook is called.
126
+ .......@basic after hook is called.
127
+ ...........@tags1 after hook is called.
128
+ ......@tagging afterTag method is called
129
+ .........<Suspense> is an experimental feature and its API will likely change.
130
+ ..afterAll was called
131
+
132
+ 8 scenarios (8 passed)
133
+ 24 steps (24 passed)
134
+ 0m00.076s (executing steps: 0m00.040s)
135
+ ```
136
+
137
+ To recap, cucumber-tsflow extends cucumber-js, which means that all options and features provided by cucumber-js are supported with cucumber-tsflow. In other words, when executing tests using cucumber-tsflow the underlying cucumber API is actually used to run the tests.
138
+
139
+ ### Executing with script in package.json
140
+
141
+ You can also add a script to package.json to execute the tests as shown below:
142
+
143
+ ```json
144
+ "scripts": {
145
+ "test": "cucumber-tsflow -p default"
146
+ }
147
+ ```
148
+
149
+ With this script in place you can execute the tests using npm or yarn,
150
+
151
+ #### npm
152
+
153
+ ```bash
154
+ npm run test
155
+ ```
156
+
157
+ #### yarn
158
+
159
+ ```bash
160
+ yarn test
161
+ ```
162
+
163
+ ## New Configuration options
164
+
165
+ As mentioned, when using cucumber-tsflow to execute tests all of the configuration options documented here are supported: <https://github.com/cucumber/cucumber-js/blob/v8.0.0/docs/configuration.md>
166
+
167
+ In addition to cucumber configuration options the following two options have been added:
168
+
169
+ | Name | Type | Repeatable | CLI Option | Description | Default |
170
+ | ------------ | -------- | ---------- | -------------- | ------------------------------------------------------------ | ------- |
171
+ | `transpiler` | `string` | No | `--transpiler` | Name of the transpiler to use: esnode, esvue, tsnode or tsvue | esnode |
172
+ | `debugFile` | `string` | No | `--debug-file` | Path to a file with steps for debugging | |
173
+
174
+ #### Transpiler and Vue3 supported
175
+
176
+ Using TypeScript with cucumberJs requires a couple of tsconfig.json parameters as described here: [Transpiling](https://github.com/cucumber/cucumber-js/blob/v9.1.0/docs/transpiling.md)
177
+
178
+ As a result, cucumber-tsflow adds several configurations for transpiling TypeScript code using the recommended configuration. In addition, support has been added to transform .vue files during test execution allowing you to test Vue SFC components using cucumber.
179
+
180
+ The following transpilers are provided:
181
+ - **esnode**: Uses esbuild to transpile TypeScript code for node test execution.
182
+ - **esvue**: Uses esbuild to transpile TypeScript code and adds a hook for .vue files, which transforms Vue SFC components into commonJS.
183
+ - **jsdom** is also loaded globally to support loading and testing Vue SFC components.
184
+ - **tsnode**: Uses typescript to transpile TypeScript code for node test execution.
185
+ - **tsvue**: Uses typescript to transpile TypeScript code and adds a hook for .vue files, which transforms Vue SFC components into commonJS.
186
+ - **jsdom** is also loaded globally to support loading and testing Vue SFC components.
187
+
188
+ ##### Using the transpiler configuration option
189
+
190
+ When configuring cucumber to execute tests you can specify which transpiler to use with the `transpiler` configuration option as shown below:
191
+
192
+ ```json
193
+ {
194
+ "default": {
195
+ "transpiler": "esvue",
196
+ "publishQuiet": true
197
+ }
198
+ }
199
+ ```
200
+
201
+ ##### Alternate without using the transpiler option
202
+
203
+ You can also use the `requireModule` parameter to configure a transpiler. The following example shows how to configure cucumber to use the `esvue` transpiler with the `requireModule` option.
204
+
205
+ ```json
206
+ {
207
+ "default": {
208
+ "requireModule": ["@lynxwall/cucumber-tsflow/lib/esvue"],
209
+ "publishQuiet": true
210
+ }
211
+ }
212
+ ```
213
+
214
+ #### Debug File support
215
+
216
+ The new `debugFile` configuration option allows you to specify a .ts file with step definitions that you want to debug. This will search for a matching feature and execute the tests in that feature. This option is helpful when debugging tests and you don't want to run all of the tests.
217
+
218
+ If using VSCode to edit your project the following launch configurations can be used:
219
+
220
+ ##### Debug All
221
+
222
+ ```json
223
+ {
224
+ "name": "Debug All",
225
+ "type": "node",
226
+ "request": "launch",
227
+ "program": "${workspaceRoot}/node_modules/@lynxwall/cucumber-tsflow/bin/cucumber-tsflow",
228
+ "stopOnEntry": true,
229
+ "args": ["-p", "default"],
230
+ "cwd": "${workspaceRoot}",
231
+ "runtimeExecutable": null,
232
+ "runtimeArgs": ["--nolazy"],
233
+ "env": {
234
+ "NODE_ENV": "development"
235
+ },
236
+ "console": "integratedTerminal",
237
+ "sourceMaps": true
238
+ }
239
+ ```
240
+
241
+ ##### Debug Feature
242
+
243
+ ```json
244
+ {
245
+ "name": "Debug Feature",
246
+ "type": "node",
247
+ "request": "launch",
248
+ "program": "${workspaceRoot}/node_modules/@lynxwall/cucumber-tsflow/bin/cucumber-tsflow",
249
+ "stopOnEntry": true,
250
+ "args": ["--debug-file", "${file}", "-p", "default"],
251
+ "cwd": "${workspaceRoot}",
252
+ "runtimeExecutable": null,
253
+ "runtimeArgs": ["--nolazy"],
254
+ "env": {
255
+ "NODE_ENV": "development"
256
+ },
257
+ "console": "integratedTerminal",
258
+ "sourceMaps": true
259
+ }
260
+ ```
261
+
262
+ **Note:** When using `Debug Feature` you'll need to have the step definition file open as the current file in VSCode. The current file path is passed into the debugger as the ${file} argument for --debug-file.
263
+
264
+ ## Bindings
265
+
266
+ Bindings provide the automation that connects a specification step in a Gherkin feature file to some code that
267
+ executes for that step. When using Cucumber with TypeScript you can define this automation using a 'binding' class:
268
+
269
+ ```javascript
270
+ import { binding } from "@lynxwall/cucumber-tsflow";
271
+
272
+ @binding()
273
+ export default class MySteps {
274
+ ...
275
+ }
276
+ ```
277
+
278
+ ## Step Definitions
279
+
280
+ Step definitions can be bound to automation code in a 'binding' class by implementing a public function that is
281
+ bound with a 'given', 'when' or 'then' binding decorator:
282
+
283
+ ```javascript
284
+ import { binding, given, when, then } from "@lynxwall/cucumber-tsflow";
285
+
286
+ @binding()
287
+ export default class MySteps {
288
+ ...
289
+ @given('I perform a search using the value {string}')
290
+ public givenAValueBasedSearch(searchValue: string): void {
291
+ ...
292
+ }
293
+ ...
294
+ }
295
+ ```
296
+
297
+ The function follows the same requirements of functions you would normally supply to Cucumber which means that the
298
+ functions may be synchronous by returning nothing, use the callback, or return a `Promise<T>`. Additionally, the
299
+ function may also be `async` following the TypeScript async semantics.
300
+
301
+ ### Boolean Custom Parameter
302
+
303
+ As mentioned, cucumber-tsflow uses Cucumber Expressions for snippet syntax, which provides different parameter types used in expressions. However, a boolean type is not provided by default.
304
+
305
+ As a result, a new custom parameter type has been added for boolean matches. For example, when a scenario step contains the words `true` or `false` they will be replaced with the `{boolean}` parameter expression and passed into the step function.
306
+
307
+ The following Scenario uses boolean values in the Given and Then statements:
308
+
309
+ ```gherkin
310
+ Scenario: Boolean type supported
311
+ Given I pass true into a step
312
+ When checking the boolean value
313
+ Then we can see that true was passed in
314
+ ```
315
+
316
+ The associated step definition replaces `true` in this scenario with a `{boolean}` expression as shown below:
317
+
318
+ ```javascript
319
+ @given('I pass {boolean} into a step')
320
+ iPassbooleanIntoAStep(boolean: boolean): any {
321
+ this.boolValue = boolean;
322
+ }
323
+
324
+ @when('checking the boolean value')
325
+ checkingTheBooleanValue(): any {
326
+ expect(this.boolValue).not.to.be.undefined;
327
+ }
328
+
329
+ @then('we can see that {boolean} was passed in')
330
+ weCanThatbooleanWasPassedIn(boolean: boolean): any {
331
+ expect(this.boolValue).to.equal(boolean);
332
+ }
333
+ ```
334
+
335
+ More information on Cucumber Expressions and Custom Parameter Types can be found here: <https://github.com/cucumber/cucumber-expressions#readme>
336
+
337
+ ### Step Tags
338
+
339
+ Step definitions can be conditionally selected for execution based on the tags of the scenario by supplying tags when using the binding
340
+ decorators:
341
+
342
+ ```javascript
343
+ @given('I perform a search using the value {string}')
344
+ public givenAValueBasedSearch(searchValue: string): void {
345
+ ...
346
+ // The default step definition
347
+ ...
348
+ }
349
+
350
+ @given('I perform a search using the value {string}', "@tagName")
351
+ public givenAValueBasedSearch(searchValue: string): void {
352
+ ...
353
+ // The step definition that will execute if the feature or
354
+ // scenario has the @tagName defined on it
355
+ ...
356
+ }
357
+ ```
358
+
359
+ **Note**: Tags added to steps work the same as "Tagged Hooks" documented here: <https://github.com/cucumber/cucumber-js/blob/v8.0.0/docs/support_files/hooks.md>
360
+
361
+ ## Hooks
362
+
363
+ Hooks can be used to perform additional automation on specific events such as before or after scenario execution.
364
+ Hooks can be restricted to run for only features or scenarios with a specific tag:
365
+
366
+ ```typescript
367
+ import { binding, beforeAll, before, beforeStep, afterStep, after, afterAll } from "@lynxwall/cucumber-tsflow";
368
+
369
+ @binding()
370
+ class MySteps {
371
+ ...
372
+ @beforeAll()
373
+ public beforeAllTests(): void {
374
+ ...
375
+ }
376
+
377
+ @before()
378
+ public beforeAllScenarios(): void {
379
+ ...
380
+ }
381
+
382
+ @before("@requireTempDir")
383
+ public async beforeAllScenariosRequiringTempDirectory(): Promise<void> {
384
+ let tempDirInfo = await this.createTemporaryDirectory();
385
+
386
+ ...
387
+ }
388
+
389
+ @beforeStep('@addNumbers')
390
+ public beforeStep() {
391
+ ...
392
+ }
393
+
394
+ @afterStep('@addNumbers')
395
+ public afterStep() {
396
+ ...
397
+ }
398
+
399
+ @after()
400
+ public afterAllScenarios(): void {
401
+ ...
402
+ }
403
+
404
+ @after("@requireTmpDir")
405
+ public afterAllScenarios(): void {
406
+ ...
407
+ }
408
+
409
+ @afterAll()
410
+ public afterAllTests(): void {
411
+ ...
412
+ }
413
+ }
414
+
415
+ export = MySteps;
416
+ ```
417
+
418
+ ### Timeout in step definition and hooks
419
+
420
+ In step definition and hooks, we can set timeout. For example, to set the timeout for a step to be 20000ms, we can do:
421
+
422
+ ```typescript
423
+
424
+ @given('I perform a search using the value {string}', undefined, 20000)
425
+ public givenAValueBasedSearch(searchValue: string): void {
426
+ ...
427
+ // this step will time tou in 20000ms.
428
+ ...
429
+ }
430
+
431
+ ```
432
+
433
+ tsflow currently doesn't have a way to define a global default step timeout,
434
+
435
+ but it can be easily done through CucumberJS ```setDefaultTimeout``` function.
436
+
437
+ ### Passing WrapperOptions
438
+
439
+ In step definition, we can pass additional wrapper options to cucumber js. For example:
440
+
441
+ ```typescript
442
+
443
+ @given('I perform a search using the value {string}', undefined, undefined, {retry: 2})
444
+ public givenAValueBasedSearch(searchValue: string): void {
445
+ ...
446
+ // this step will be retried by cucumber js
447
+ ...
448
+ }
449
+
450
+ ```
451
+
452
+ ### Using behave-json-formatter and tsflow-snippet-syntax
453
+
454
+ Changing the formatter used for generating json along with changing the Snippet Syntax can be done through the CucumberJS configuration file.
455
+
456
+ If it doesn't already exist, create a file named cucumber.json at the root of your project. This is where we can configure different options for CucumberJS.
457
+
458
+ #### Using the behave json formatter
459
+
460
+ The following example shows how to configure the behave formatter in cucumber.json. The tsflow-snippet-syntax module is configured as the default snippet syntax and does not require configuration. However, you can override the snippet syntax as documented here: <https://github.com/cucumber/cucumber-js/blob/v8.0.0/docs/custom_snippet_syntaxes.md>
461
+
462
+ ```javascript
463
+ {
464
+ "default": {
465
+ "format": [
466
+ "behave:cucumber_report.json"
467
+ ],
468
+ "publishQuiet": true
469
+ }
470
+ }
471
+ ```
472
+
473
+ ## Sharing Data between Bindings
474
+
475
+ ### Context Injection
476
+
477
+ Like 'specflow', cucumber-tsflow supports a simple dependency injection framework that will instantitate and inject class instances into 'binding' classes for each execuing scenario.
478
+
479
+ To use context injection:
480
+
481
+ - Create simple classes representing the shared data (they *must* have default constructors)
482
+ - Define a constructor on the 'binding' classes that will require the shared data that accepts the context objects as parameters
483
+ - Update the `@binding()` decorator to indicate the types of context objects that are required by the 'binding' class
484
+
485
+ ```javascript
486
+ import { binding, given, when } from '@lynxwall/cucumber-tsflow';
487
+ import { Workspace } from './workspace';
488
+ import { expect } from 'chai';
489
+
490
+ @binding([Workspace])
491
+ export default class InjectionTestSteps1 {
492
+ constructor(private workspace: Workspace) {}
493
+
494
+ @given('The Workspace is available and valid')
495
+ theWorkspaceIsAvailableAndValid() {
496
+ expect(this.workspace).not.to.be.undefined;
497
+ expect(this.workspace.world).not.to.be.undefined;
498
+ }
499
+
500
+ @when('I change the workspace in one step definition class')
501
+ whenIChangeTheWorkspaceInOneStep() {
502
+ this.workspace.someValue = 'value changed';
503
+ }
504
+ }
505
+ ```
506
+
507
+ ### Access to Cucumber.js World object
508
+
509
+ The context object that you inject can also be configured to access the [World](https://github.com/cucumber/cucumber-js/blob/main/docs/support_files/world.md) object from Cucumber.js, which provides a method for adding attachments, a method for logging information from hooks/steps and an object of parameters passed in via configuration.
510
+
511
+ The first step is to define a world property on the class that you're injecting:
512
+
513
+ ```javascript
514
+ import { World } from '@cucumber/cucumber';
515
+
516
+ export class Workspace {
517
+ public world!: World;
518
+ public someValue = '';
519
+ }
520
+ ```
521
+
522
+ Next you'll need to initialize the world property in a ***@before*** hook so that it's available to all steps in a scenario. My approach is to add a new file to the steps folder that is dedicated to initializing the class (Workspace in this example) in a ***@before*** hook.
523
+
524
+ For this example I've added a file named world-context.ts with the following content:
525
+
526
+ ```javascript
527
+ import { binding, before } from '@lynxwall/cucumber-tsflow';
528
+ import { Workspace } from './workspace';
529
+ import { World } from '@cucumber/cucumber';
530
+
531
+ @binding([Workspace])
532
+ export default class WorldContext {
533
+ _worldObj?: World;
534
+
535
+ constructor(private workspace: Workspace) {}
536
+
537
+ @before()
538
+ beforeScenario() {
539
+ this.workspace.world = this._worldObj as World;
540
+ }
541
+ }
542
+ ```
543
+
544
+ As described in the section on Hooks, the ***beforeScenario*** function will be executed before each scenario. We're accessing a member property that was bound to the class instance during creation of each step class, and initializing the world property.
545
+
546
+ **NOTE:** Examples of this and other tests can be found in the GitHub repository.