1import { describe, expect, it } from "vite-plus/test";
2import type { TestSpecification, Vitest } from "vite-plus/test/node";
3
4import shardWeights from "./shardWeights.json" with { type: "json" };
5import { WeightedShardSequencer } from "./weightedShardSequencer.ts";
6
7const root = "/repo/apps/server";
8const recordedSeconds: Readonly<Record<string, number>> = shardWeights;
9const recorded = Object.keys(recordedSeconds);
10const files = [...recorded, ...Array.from({ length: 300 }, (_, i) => `src/fast${i}.test.ts`)];
11const specs = files.map((file) => ({ moduleId: `${root}/${file}` }) as TestSpecification);
12
13const shardModuleIds = (count: number) =>
14 Promise.all(
15 Array.from({ length: count }, async (_, i) => {
16 const ctx = { config: { root, shard: { index: i + 1, count } } } as unknown as Vitest;
17 const shard = await new WeightedShardSequencer(ctx).shard(specs);
18 return shard.map((spec) => spec.moduleId);
19 }),
20 );
21
22describe("WeightedShardSequencer", () => {
23 it("runs every file in exactly one shard", async () => {
24 const shards = await shardModuleIds(6);
25
26 expect(shards.flat().toSorted()).toEqual(specs.map((spec) => spec.moduleId).toSorted());
27 });
28
29 it("puts each of the slowest files in a different shard", async () => {
30 const slowest = new Set(
31 recorded
32 .toSorted((a, b) => (recordedSeconds[b] ?? 0) - (recordedSeconds[a] ?? 0))
33 .slice(0, 6)
34 .map((file) => `${root}/${file}`),
35 );
36 const shards = await shardModuleIds(6);
37
38 for (const shard of shards) {
39 expect(shard.filter((moduleId) => slowest.has(moduleId))).toHaveLength(1);
40 }
41 });
42});