Cucumber supports running scenarios in parallel. The main process becomes a "coordinator" and spins up several separate Node.js processes to be the "workers". You can enable this with the parallel
configuration option:
- In a configuration file
{ parallel: 3 }
- On the CLI
$ cucumber-js --parallel 3
The number you provide is the number of workers that will run scenarios in parallel.
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 workersCUCUMBER_WORKER_ID
- ID for worker ('0', '1', '2', etc.)
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:
73 scenarios (73 passed)
512 steps (512 passed)
0m51.627s (executing steps: 4m51.228s)
When using parallel mode, any BeforeAll
and AfterAll
hooks you have defined will run once per worker.
If you would like to prevent specific sets of scenarios from running in parallel you can use setParallelCanAssign
.
Example:
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'))
}
// No other restrictions
return true
})
For convenience, the following helpers exist to build a canAssignFn
:
import {
setParallelCanAssign,
parallelCanAssignHelpers,
} from '@cucumber/cucumber'
const { atMostOnePicklePerTag } = parallelCanAssignHelpers
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) {
// ...
}
setParallelCanAssign(function (pickleInQuestion, picklesInProgress) {
return (
myCustomRule(pickleInQuestion, picklesInProgress) &&
myTagRule(pickleInQuestion, picklesInProgress)
)
})
You can access workerId
property in testCaseStarted
envelope object:
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