Skip to content
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

feat: provide worker id to envelope message #2085

Merged
merged 14 commits into from
Nov 14, 2022
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CONTRIBUTING.md) on how to contribute to Cucumber.

## [Unreleased]
## Changed
### Changed
- Add `workerId` property to `testCaseStarted` message ([#2085](https://github.com/cucumber/cucumber-js/pull/2085))
- Handle stack traces without V8-specific modification ([#2119](https://github.com/cucumber/cucumber-js/pull/2119))

## [8.7.0] - 2022-10-17
Expand Down
62 changes: 48 additions & 14 deletions docs/parallel.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ The number you provide is the number of workers that will run scenarios in paral

Each worker receives the following env variables (as well as a copy of `process.env` from the coordinator process):

* `CUCUMBER_PARALLEL` - set to 'true'
* `CUCUMBER_TOTAL_WORKERS` - set to the number of workers
* `CUCUMBER_WORKER_ID` - ID for worker ('0', '1', '2', etc.)
- `CUCUMBER_PARALLEL` - set to 'true'
- `CUCUMBER_TOTAL_WORKERS` - set to the number of workers
- `CUCUMBER_WORKER_ID` - ID for worker ('0', '1', '2', etc.)

### Timing

Expand All @@ -32,36 +32,70 @@ When using parallel mode, any `BeforeAll` and `AfterAll` hooks you have defined
If you would like to prevent specific sets of scenarios from running in parallel you can use `setParallelCanAssign`.

Example:

```javascript
setParallelCanAssign(function(pickleInQuestion, picklesInProgress) {
setParallelCanAssign(function (pickleInQuestion, picklesInProgress) {
// Only one pickle with the word example in the name can run at a time
if (pickleInQuestion.name.includes("example")) {
return picklesInProgress.every(p => !p.name.includes("example"));
if (pickleInQuestion.name.includes('example')) {
return picklesInProgress.every((p) => !p.name.includes('example'))
}
// No other restrictions
return true;
return true
})
```

For convenience, the following helpers exist to build a `canAssignFn`:

```javascript
import { setParallelCanAssign, parallelCanAssignHelpers } from '@cucumber/cucumber'
import {
setParallelCanAssign,
parallelCanAssignHelpers,
} from '@cucumber/cucumber'

const { atMostOnePicklePerTag } = parallelCanAssignHelpers
const myTagRule = atMostOnePicklePerTag(["@tag1", "@tag2"]);
const myTagRule = atMostOnePicklePerTag(['@tag1', '@tag2'])

// Only one pickle with @tag1 can run at a time
// AND only one pickle with @tag2 can run at a time
setParallelCanAssign(myTagRule)

// If you want to join a tag rule with other rules you can compose them like so:
const myCustomRule = function(pickleInQuestion, picklesInProgress) {
const myCustomRule = function (pickleInQuestion, picklesInProgress) {
// ...
};
}

setParallelCanAssign(function(pickleInQuestion, picklesInProgress) {
return myCustomRule(pickleInQuestion, picklesInProgress) &&
myTagRule(pickleInQuestion, picklesInProgress);
setParallelCanAssign(function (pickleInQuestion, picklesInProgress) {
return (
myCustomRule(pickleInQuestion, picklesInProgress) &&
myTagRule(pickleInQuestion, picklesInProgress)
)
})
```

### Formatting

You can access `workerId` property in `testCaseStarted` envelope object:

```javascript
const { Formatter } = require('@cucumber/cucumber')

class ExampleFormatter extends Formatter {
constructor(options) {
options.eventBroadcaster.on('envelope', (envelope) => {
if (envelope.testCaseStarted) {
if (envelope.testCaseStarted.workerId) {
console.log(
`the event has been fired from a worker with id ${envelope.testCaseStarted.workerId}`
)
} else {
console.log('the event has been sent from the main thread')
}
}
})

super(options)
}
}

module.exports = ExampleFormatter
```
22 changes: 22 additions & 0 deletions features/parallel.feature
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,25 @@ Feature: Running scenarios in parallel
my error
"""
Then it fails

Scenario: `testCaseStarted` envelope from workers contains `workerId` parameter
Given a file named "features/step_definitions/cucumber_steps.js" with:
"""
const {Given} = require('@cucumber/cucumber')

Given(/^a slow step$/, function(callback) {
setTimeout(callback, 1000)
})
"""
And a file named "features/a.feature" with:
"""
Feature: slow
Scenario: a
Given a slow step

Scenario: b
Given a slow step
"""
When I run cucumber-js with `--parallel 2`
Then it passes
And `testCaseStarted` envelope has `workerId`
8 changes: 8 additions & 0 deletions features/step_definitions/parallel_steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,11 @@ Then(
expect(actualSets).to.eql(expectedSets)
}
)

Then('`testCaseStarted` envelope has `workerId`', function (this: World) {
const testCaseStartedEnvelope = this.lastRun.envelopes.find(
(envelope) => envelope.testCaseStarted
)

expect(testCaseStartedEnvelope.testCaseStarted).to.ownProperty('workerId')
})
Loading