Skip to content

Commit b613ccb

Browse files
committed
Add support for execution sharding
1 parent aac018c commit b613ccb

File tree

13 files changed

+127
-0
lines changed

13 files changed

+127
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Please see [CONTRIBUTING.md](./CONTRIBUTING.md) on how to contribute to Cucumber
1010
## [Unreleased]
1111
### Added
1212
- Export configuration types ([#2598](https://github.com/cucumber/cucumber-js/pull/2598))
13+
- Add support for execution sharding ([#2303](https://github.com/cucumber/cucumber-js/pull/2303))
1314

1415
## [12.1.0] - 2025-07-19
1516
### Added

compatibility/cck_spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ describe('Cucumber Compatibility Kit', () => {
3737
names: [],
3838
tagExpression: '',
3939
order: 'defined',
40+
shard: '',
4041
},
4142
support: {
4243
requireModules: ['ts-node/register'],

features/sharding.feature

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
Feature: Running scenarios using sharding
2+
As a developer running features
3+
I want an easy way to run specific scenarios by tag
4+
So that I don't waste time running my whole test suite when I don't need to
5+
6+
Background:
7+
Given a file named "features/a.feature" with:
8+
"""
9+
Feature: some feature
10+
@a
11+
Scenario: first scenario
12+
Given a step
13+
14+
@b
15+
Scenario Outline: second scenario - <ID>
16+
Given a step
17+
18+
@c
19+
Examples:
20+
| ID |
21+
| X |
22+
| Y |
23+
24+
@d
25+
Examples:
26+
| ID |
27+
| Z |
28+
"""
29+
And a file named "features/step_definitions/cucumber_steps.js" with:
30+
"""
31+
const {Given} = require('@cucumber/cucumber')
32+
33+
Given('a step', function() {})
34+
"""
35+
36+
Scenario: run a single scenario
37+
When I run cucumber-js with `--shard 1/5`
38+
Then it passes
39+
And it runs the scenario "first scenario"
40+
41+
Scenario: run every other scenario starting at 1
42+
When I run cucumber-js with `--shard 1/2`
43+
Then it passes
44+
And it runs the scenarios:
45+
| NAME |
46+
| first scenario |
47+
| second scenario - Y |
48+
49+
Scenario: run every 3rd scenario starting at 1
50+
When I run cucumber-js with `--shard 1/3`
51+
Then it passes
52+
And it runs the scenarios:
53+
| NAME |
54+
| first scenario |
55+
| second scenario - Z |
56+
57+
Scenario: run even scenarios
58+
When I run cucumber-js with `--shard 2/2`
59+
Then it passes
60+
And it runs the scenarios:
61+
| NAME |
62+
| second scenario - X |
63+
| second scenario - Z |
64+
65+
Scenario: no scenarios in shard
66+
When I run cucumber-js with `--shard 5/5`
67+
Then it passes
68+
And it runs 0 scenarios

src/api/convert_configuration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export async function convertConfiguration(
1919
names: flatConfiguration.name,
2020
tagExpression: flatConfiguration.tags,
2121
order: flatConfiguration.order,
22+
shard: flatConfiguration.shard,
2223
},
2324
support: {
2425
requireModules: flatConfiguration.requireModule,

src/api/convert_configuration_spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ describe('convertConfiguration', () => {
3636
order: 'defined',
3737
paths: [],
3838
tagExpression: '',
39+
shard: '',
3940
},
4041
support: {
4142
requireModules: [],

src/api/load_sources_spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ describe('loadSources', () => {
5151
paths: [],
5252
names: [],
5353
tagExpression: '',
54+
shard: '',
5455
},
5556
environment
5657
)
@@ -112,6 +113,7 @@ describe('loadSources', () => {
112113
paths: ['features/test.feature:8'],
113114
names: [],
114115
tagExpression: '',
116+
shard: '',
115117
},
116118
environment
117119
)
@@ -127,6 +129,7 @@ describe('loadSources', () => {
127129
paths: [],
128130
names: ['two'],
129131
tagExpression: '',
132+
shard: '',
130133
},
131134
environment
132135
)
@@ -142,6 +145,7 @@ describe('loadSources', () => {
142145
paths: [],
143146
names: [],
144147
tagExpression: '@tag2',
148+
shard: '',
145149
},
146150
environment
147151
)
@@ -157,6 +161,7 @@ describe('loadSources', () => {
157161
paths: ['@rerun.txt'],
158162
names: [],
159163
tagExpression: '',
164+
shard: '',
160165
},
161166
environment
162167
)

src/api/plugins.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { PluginManager } from '../plugin'
22
import publishPlugin from '../publish'
33
import filterPlugin from '../filter'
4+
import shardingPlugin from '../sharding'
45
import { UsableEnvironment } from '../environment'
56
import { IRunConfiguration, ISourcesCoordinates } from './types'
67

@@ -11,6 +12,11 @@ export async function initializeForLoadSources(
1112
// eventually we'll load plugin packages here
1213
const pluginManager = new PluginManager(environment)
1314
await pluginManager.initCoordinator('loadSources', filterPlugin, coordinates)
15+
await pluginManager.initCoordinator(
16+
'loadSources',
17+
shardingPlugin,
18+
coordinates
19+
)
1420
return pluginManager
1521
}
1622

@@ -37,5 +43,10 @@ export async function initializeForRunCucumber(
3743
filterPlugin,
3844
configuration.sources
3945
)
46+
await pluginManager.initCoordinator(
47+
'runCucumber',
48+
shardingPlugin,
49+
configuration.sources
50+
)
4051
return pluginManager
4152
}

src/api/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ export interface ISourcesCoordinates {
8080
* Run in the order defined, or in a random order
8181
*/
8282
order: IPickleOrder
83+
/**
84+
* Shard tests and execute only the selected shard, format `<index>/<total>`
85+
* @example 1/4
86+
* @remarks
87+
* Shards use 1-based numbering
88+
*/
89+
shard: string
8390
}
8491

8592
/**

src/configuration/argv_parser.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ const ArgvParser = {
123123
'--order <TYPE[:SEED]>',
124124
'run scenarios in the specified order. Type should be `defined` or `random`'
125125
)
126+
.option(
127+
'--shard <INDEX/TOTAL>',
128+
'run shard INDEX of TOTAL shards. The index starts at 1'
129+
)
126130
.option(
127131
'-p, --profile <NAME>',
128132
'specify the profile to use (repeatable)',

src/configuration/default_configuration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const DEFAULT_CONFIGURATION: IConfiguration = {
1919
requireModule: [],
2020
retry: 0,
2121
retryTagFilter: '',
22+
shard: '',
2223
strict: true,
2324
tags: '',
2425
worldParameters: {},

0 commit comments

Comments
 (0)