Skip to content

Commit 571c940

Browse files
authored
fix: distribute rest files over shards (#13476)
1 parent 57d103f commit 571c940

File tree

3 files changed

+48
-4
lines changed

3 files changed

+48
-4
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Fixes
66

7+
- `[@jest/test-sequencer]` Make sure sharding does not produce empty groups ([#13476](https://github.com/facebook/jest/pull/13476))
8+
79
### Chore & Maintenance
810

911
### Performance

packages/jest-test-sequencer/src/__tests__/test_sequencer.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,23 @@ test('returns expected 100/8 shards', async () => {
368368
);
369369

370370
expect(shards.map(shard => shard.length)).toEqual([
371-
13, 13, 13, 13, 13, 13, 13, 9,
371+
13, 13, 13, 13, 12, 12, 12, 12,
372+
]);
373+
});
374+
375+
test('returns expected 55/12 shards', async () => {
376+
const allTests = toTests(new Array(55).fill(true).map((_, i) => `/${i}.js`));
377+
378+
const shards = await Promise.all(
379+
new Array(12).fill(true).map((_, i) =>
380+
sequencer.shard(allTests, {
381+
shardCount: 12,
382+
shardIndex: i + 1,
383+
}),
384+
),
385+
);
386+
387+
expect(shards.map(shard => shard.length)).toEqual([
388+
5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4,
372389
]);
373390
});

packages/jest-test-sequencer/src/index.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ export type ShardOptions = {
2424
shardCount: number;
2525
};
2626

27+
type ShardPositionOptions = ShardOptions & {
28+
suiteLength: number;
29+
};
30+
2731
/**
2832
* The TestSequencer will ultimately decide which tests should run first.
2933
* It is responsible for storing and reading from a local cache
@@ -72,6 +76,19 @@ export default class TestSequencer {
7276
return cache;
7377
}
7478

79+
private _shardPosition(options: ShardPositionOptions): number {
80+
const shardRest = options.suiteLength % options.shardCount;
81+
const ratio = options.suiteLength / options.shardCount;
82+
83+
return new Array(options.shardIndex)
84+
.fill(true)
85+
.reduce<number>((acc, _, shardIndex) => {
86+
const dangles = shardIndex < shardRest;
87+
const shardSize = dangles ? Math.ceil(ratio) : Math.floor(ratio);
88+
return acc + shardSize;
89+
}, 0);
90+
}
91+
7592
/**
7693
* Select tests for shard requested via --shard=shardIndex/shardCount
7794
* Sharding is applied before sorting
@@ -97,9 +114,17 @@ export default class TestSequencer {
97114
tests: Array<Test>,
98115
options: ShardOptions,
99116
): Array<Test> | Promise<Array<Test>> {
100-
const shardSize = Math.ceil(tests.length / options.shardCount);
101-
const shardStart = shardSize * (options.shardIndex - 1);
102-
const shardEnd = shardSize * options.shardIndex;
117+
const shardStart = this._shardPosition({
118+
shardCount: options.shardCount,
119+
shardIndex: options.shardIndex - 1,
120+
suiteLength: tests.length,
121+
});
122+
123+
const shardEnd = this._shardPosition({
124+
shardCount: options.shardCount,
125+
shardIndex: options.shardIndex,
126+
suiteLength: tests.length,
127+
});
103128

104129
return tests
105130
.map(test => {

0 commit comments

Comments
 (0)