Skip to content

Commit 6b09896

Browse files
authored
refactor documentation (part 1) (#1699)
* add export of cli --help * dont need note about sync * update world docs * document retry * document profiles * start to trim stuff from cli * more on profiles * document parallel * add linsk to readmr
1 parent 6e60589 commit 6b09896

File tree

6 files changed

+136
-40
lines changed

6 files changed

+136
-40
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ The following documentation is for master. See below for documentation for older
6666
* [Data Table Interface](/docs/support_files/data_table_interface.md)
6767
* [Attachments](/docs/support_files/attachments.md)
6868
* [API Reference](/docs/support_files/api_reference.md)
69+
* Guides
70+
* [Running in parallel](./docs/parallel.md)
71+
* [Retrying failing scenarios](./docs/retry.md)
72+
* [Profiles](./docs/profiles.md)
6973
* [FAQ](/docs/faq.md)
7074

7175
#### Documentation for older versions

docs/cli.md

+4-25
Original file line numberDiff line numberDiff line change
@@ -122,25 +122,11 @@ Note that the rerun file parser can only work with the default separator for now
122122

123123
## Parallel
124124

125-
You can run your scenarios in parallel with `--parallel <NUMBER_OF_WORKERS>`. Each worker is run in a separate Node process and receives the following env variables (as well as a copy of `process.env` from the coordinator process):
126-
127-
* `CUCUMBER_PARALLEL` - set to 'true'
128-
* `CUCUMBER_TOTAL_WORKERS` - set to the number of workers
129-
* `CUCUMBER_WORKER_ID` - ID for worker ('0', '1', '2', etc.)
130-
131-
### Timing
132-
133-
When using parallel mode, the last line of the summary output differentiates between real time elapsed during the test run and aggregate time spent actually running steps:
134-
135-
```
136-
73 scenarios (73 passed)
137-
512 steps (512 passed)
138-
0m51.627s (executing steps: 4m51.228s)
139-
```
125+
See [Parallel](./parallel.md).
140126

141127
## Profiles
142128

143-
In order to store and reuse commonly used CLI options, you can add a `cucumber.js` file to your project root directory. The file should export an object where the key is the profile name and the value is a string of CLI options. The profile can be applied with `-p <NAME>` or `--profile <NAME>`. This will prepend the profile's CLI options to the ones provided by the command line. Multiple profiles can be specified at a time. If no profile is specified and a profile named `default` exists, it will be applied.
129+
See [Profiles](./profiles.md).
144130

145131
## Tags
146132

@@ -157,8 +143,7 @@ A note on using in conjunction with `--retry`: we consider a test case to have f
157143

158144
## Retry failing tests
159145

160-
Use `--retry <int>` to rerun tests that have been failing. This can be very helpful for flaky tests.
161-
To only retry failing tests in a subset of test use `--retry-tag-filter <EXPRESSION>` (use the same as in Use [Tags](#tags))
146+
See [Retry](./retry.md)
162147

163148
## Transpilation
164149

@@ -228,10 +213,4 @@ Note that the first `--require tests.setup.js` overrides the default require glo
228213

229214
## World Parameters
230215

231-
You can pass in parameters to pass to the world constructor with `--world-parameters <JSON>`. The JSON string must define an object. The parsed object will be passed as the `parameters` to the the world constructor. This option is repeatable and the objects will be merged with the last instance taking precedence.
232-
233-
Example:
234-
235-
```
236-
--world-parameters '{"fancySetting":true}'
237-
```
216+
See [World](./support_files/world.md).

docs/parallel.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Parallel
2+
3+
Cucumber supports running scenarios in parallel. The main process becomes a "coordinator" and spins up several separate Node processes to be the "workers". You can enable this with the `--parallel <NUMBER_OF_WORKERS>` CLI option:
4+
5+
```shell
6+
$ cucumber-js --parallel 3
7+
```
8+
9+
The number you provide is the number of workers that will run scenarios in parallel.
10+
11+
Each worker receives the following env variables (as well as a copy of `process.env` from the coordinator process):
12+
13+
* `CUCUMBER_PARALLEL` - set to 'true'
14+
* `CUCUMBER_TOTAL_WORKERS` - set to the number of workers
15+
* `CUCUMBER_WORKER_ID` - ID for worker ('0', '1', '2', etc.)
16+
17+
### Timing
18+
19+
When using parallel mode, the last line of the summary output differentiates between real time elapsed during the test run and aggregate time spent actually running steps:
20+
21+
```
22+
73 scenarios (73 passed)
23+
512 steps (512 passed)
24+
0m51.627s (executing steps: 4m51.228s)
25+
```
26+
27+
### Hooks
28+
29+
When using parallel mode, any `BeforeAll` and `AfterAll` hooks you have defined will run _once per worker_.

docs/profiles.md

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Profiles
2+
3+
If you have several permutations of running Cucumber with different CLI options in your project, it might be a bit cumbersome to manage. *Profiles* enable you to declare bundles of configuration and reference them with a single CLI option.
4+
5+
Let's take the common case of having some things a bit different locally vs in CI. Here's the command we've been running locally:
6+
7+
```shell
8+
$ cucumber-js --require-module ts-node/register --require 'support/**/*./ts' --world-parameters '{\"appUrl\":\"http://localhost:3000/\"}' --format progress-bar --format html:./cucumber-report.html
9+
```
10+
11+
For argument's sake, we'll want these changes in CI:
12+
13+
- The URL for the app (maybe dynamically provisioned?)
14+
- The formatters we want to use
15+
16+
To start using Profiles, we just need to create a `cucumber.js` file in our project's root. It's a simple JavaScript module that exports an object with profile names as keys and CLI options as values. We can lean on JavaScript to reduce duplication and grab things dynamically as needed. Here's what we might write to address the needs described above:
17+
18+
```javascript
19+
const worldParameters = {
20+
appUrl: process.env.MY_APP_URL || "http://localhost:3000/"
21+
}
22+
const common = `--require-module ts-node/register --require 'support/**/*./ts' --world-parameters '${JSON.stringify(worldParameters)}'`
23+
24+
module.exports = {
25+
'default': `${common} --format progress-bar --format html:./cucumber-report.html`,
26+
'ci': `${common} --format html:./cucumber-report.html --publish`
27+
}
28+
```
29+
30+
Now, if we just run `cucumber-js` with no arguments, it will pick up our profiles and use the `default` one.
31+
32+
In CI, we just need to change the command to specify the "ci" profile:
33+
34+
```shell
35+
$ cucumber-js --profile ci
36+
```
37+
38+
Some notes about how Profiles work:
39+
40+
- The `--profile` CLI option is repeatable, so you can apply multiple profiles at once.
41+
- You can still supply options directly on the command line when using profiles, they will be appended to whatever comes from profiles.

docs/retry.md

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Retry
2+
3+
If you have a flaky scenario (e.g. failing 10% of the time for some reason), you can use *Retry* to have Cucumber attempt it multiple times until either it passes or the maximum number of attempts is reached. You enable this via the `--retry <MAXIMUM_RETRIES>` CLI option, like this:
4+
5+
```shell
6+
$ cucumber-js --retry 1
7+
```
8+
9+
The number you provide is the number of retries that will be allowed after an initial failure.
10+
11+
*Note:* Retry isn't recommended for routine use, but can be a good trade-off in some situations where you have a scenario that's too valuable to remove, but it's either not possible or not worth the effort to fix the flakiness.
12+
13+
Some notes on how Retry works:
14+
15+
- Only relevant failing scenarios are retried, not the whole test run.
16+
- When a scenario is retried, it runs all hooks and steps again from the start with a fresh [World](./support_files/world.md) - nothing is retained from the failed attempt.
17+
- When a scenario passes on a retry, it's treated as a pass overall in the results, although the details of each attempt are emitted so formatters can access them.
18+
19+
20+
## Targeting scenarios
21+
22+
Using the `--retry` option alone would mean every scenario would be allowed multiple attempts - this almost certainly isn't what you want, assuming you have a small set of flaky scenarios. To target just the relevant scenarios, you can provide a [tag expression](https://cucumber.io/docs/cucumber/api/#tag-expressions) via the `--retry-tag-filter <TAG_EXPRESSION>` CLI option, like this:
23+
24+
```shell
25+
$ cucumber-js --retry 1 --retry-tag-filter @flaky
26+
```

docs/support_files/world.md

+32-15
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,41 @@
11
# World
22

3-
*World* is an isolated context for each scenario, exposed to the hooks and steps as `this`.
4-
The default world constructor is:
3+
*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:
54

65
```javascript
7-
class World {
8-
constructor({ attach, log, parameters }) {
9-
this.attach = attach
10-
this.log = log
11-
this.parameters = parameters
12-
}
13-
}
6+
const { When } = require('@cucumber/cucumber')
7+
8+
When('something happens', async function() {
9+
this.foo = 'bar'
10+
})
11+
```
12+
13+
As well as being able to have arbitrary state, you get some helpers preset on the World for you:
14+
15+
* `this.attach`: function used for adding [attachments](./attachments.md) to hooks/steps
16+
* `this.log`: function used for [logging](./attachments.md#logging) information from hooks/steps
17+
* `this.parameters`: object of parameters passed in via the [CLI](../cli.md#world-parameters)
18+
19+
Some notes on the scope of World:
20+
21+
- It's scoped to a single scenario only - not shared globally between scenarios. This reinforces a Cucumber principle: that scenarios should work entirely independently of one another.
22+
- If you're using [Retry](../retry.md), you'll get a fresh World for every attempt at your scenario, so state isn't retained between attempts.
23+
24+
## World Parameters
25+
26+
You might want to provide some configuration/environmental data to your World at runtime. You can provide this data as a JSON literal via the `--world-parameters` CLI option, like this:
27+
28+
```shell
29+
$ cucumber-js --world-parameters '{"appUrl":"http://localhost:3000/"}'
1430
```
1531

16-
* `attach`: function used for adding [attachments](./attachments.md) to hooks/steps
17-
* `log`: function used for [logging](./attachments.md#logging) information from hooks/steps
18-
* `parameters`: object of parameters passed in via the [CLI](../cli.md#world-parameters)
32+
This option is repeatable, so you can use it multiple times and the objects will be merged with the later ones taking precedence.
1933

20-
You can provide your own World class with its own properties and methods that help with your instrumentation. You can extend the built-in `World` with your own class and then call `setWorldConstructor` with it:
34+
This data is then available on `this.parameters` from your hooks and steps.
35+
36+
## Custom World
37+
38+
You might also want to have methods on your World that hooks and steps can access to keep their own code simple. To do this, you can provide your own World class with its own properties and methods that help with your instrumentation, and then call `setWorldConstructor` to tell Cucumber about it. You should extend the built-in `World` class:
2139

2240
```javascript
2341
const { setWorldConstructor, World } = require('@cucumber/cucumber')
@@ -29,6 +47,7 @@ class CustomWorld extends World {
2947
.build()
3048

3149
constructor(options) {
50+
// needed so `attach`, `log` and `parameters` are properly set
3251
super(options)
3352
}
3453

@@ -41,5 +60,3 @@ class CustomWorld extends World {
4160

4261
setWorldConstructor(CustomWorld)
4362
```
44-
45-
**Note:** The World constructor was made strictly synchronous in *[v0.8.0](https://github.com/cucumber/cucumber-js/releases/tag/v0.8.0)*.

0 commit comments

Comments
 (0)