Skip to content

Commit c48683e

Browse files
--wip-- [skip ci]
1 parent 1999ec9 commit c48683e

19 files changed

Lines changed: 1149 additions & 567 deletions

packages/vitest-plugin/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@
4141
"peerDependencies": {
4242
"tinybench": ">=2.9.0",
4343
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0",
44-
"vitest": "^3.2 || ^4"
44+
"vitest": "^3.2 || ^4 || ^5.0.0-beta"
4545
},
4646
"devDependencies": {
4747
"@total-typescript/shoehorn": "^0.1.1",
4848
"execa": "^8.0.1",
4949
"tinybench": "^2.9.0",
5050
"vite": "^7.0.0",
51-
"vitest": "^4.0.18"
51+
"vitest": "5.0.0-beta.5"
5252
}
5353
}

packages/vitest-plugin/rollup.config.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,24 @@ export default defineConfig([
2020
plugins: jsPlugins(pkg.version),
2121
external: ["@codspeed/core", /^vitest/],
2222
},
23+
// The built layout mirrors the source layout (dist/legacy/*, dist/v5/*) so the
24+
// plugin resolves the seam files with one path rule in both dev and prod.
2325
{
24-
input: "src/analysis.ts",
25-
output: { file: "dist/analysis.mjs", format: "es" },
26+
input: "src/legacy/analysis.ts",
27+
output: { file: "dist/legacy/analysis.mjs", format: "es" },
2628
plugins: jsPlugins(pkg.version),
2729
external: ["@codspeed/core", /^vitest/],
2830
},
2931
{
30-
input: "src/walltime/index.ts",
31-
output: { file: "dist/walltime.mjs", format: "es" },
32+
input: "src/legacy/walltime.ts",
33+
output: { file: "dist/legacy/walltime.mjs", format: "es" },
3234
plugins: jsPlugins(pkg.version),
3335
external: ["@codspeed/core", /^vitest/],
3436
},
37+
{
38+
input: "src/v5/setup.ts",
39+
output: { file: "dist/v5/setup.mjs", format: "es" },
40+
plugins: jsPlugins(pkg.version),
41+
external: ["@codspeed/core", /^vitest/, "tinybench"],
42+
},
3543
]);

packages/vitest-plugin/src/__tests__/index.test.ts

Lines changed: 98 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,19 @@ vi.mock("fs", () => {
4343

4444
console.warn = vi.fn();
4545

46+
const EXPECTED_EXEC_ARGV = [
47+
"--interpreted-frames-native-stack",
48+
"--allow-natives-syntax",
49+
"--hash-seed=1",
50+
"--random-seed=1",
51+
"--no-opt",
52+
"--predictable",
53+
"--predictable-gc-schedule",
54+
"--expose-gc",
55+
"--no-concurrent-sweeping",
56+
"--max-old-space-size=4096",
57+
];
58+
4659
describe("codSpeedPlugin", () => {
4760
beforeAll(() => {
4861
// Set environment variables to trigger instrumented mode
@@ -54,6 +67,7 @@ describe("codSpeedPlugin", () => {
5467
// Clean up environment variables
5568
delete process.env.CODSPEED_ENV;
5669
delete process.env.CODSPEED_RUNNER_MODE;
70+
fsMocks.setMockVersion("4.0.18");
5771
});
5872

5973
it("should have a name", async () => {
@@ -65,7 +79,9 @@ describe("codSpeedPlugin", () => {
6579
});
6680

6781
describe("apply", () => {
68-
it("should not apply the plugin when the mode is not benchmark", async () => {
82+
it("should not apply the plugin when the mode is not benchmark (v3/v4)", async () => {
83+
fsMocks.setMockVersion("4.0.18");
84+
6985
const applyPlugin = applyPluginFunction(
7086
{},
7187
fromPartial({ mode: "test" }),
@@ -74,7 +90,8 @@ describe("codSpeedPlugin", () => {
7490
expect(applyPlugin).toBe(false);
7591
});
7692

77-
it("should apply the plugin when there is no instrumentation", async () => {
93+
it("should apply the plugin when there is no instrumentation (v3/v4)", async () => {
94+
fsMocks.setMockVersion("4.0.18");
7895
coreMocks.InstrumentHooks.isInstrumented.mockReturnValue(false);
7996

8097
const applyPlugin = applyPluginFunction(
@@ -88,7 +105,8 @@ describe("codSpeedPlugin", () => {
88105
expect(applyPlugin).toBe(true);
89106
});
90107

91-
it("should apply the plugin when there is instrumentation", async () => {
108+
it("should apply the plugin when there is instrumentation (v3/v4)", async () => {
109+
fsMocks.setMockVersion("4.0.18");
92110
coreMocks.InstrumentHooks.isInstrumented.mockReturnValue(true);
93111

94112
const applyPlugin = applyPluginFunction(
@@ -98,51 +116,60 @@ describe("codSpeedPlugin", () => {
98116

99117
expect(applyPlugin).toBe(true);
100118
});
119+
120+
it("should stay active regardless of mode on v5 (benchmark gating happens in config)", async () => {
121+
fsMocks.setMockVersion("5.0.0-beta.5");
122+
coreMocks.InstrumentHooks.isInstrumented.mockReturnValue(true);
123+
124+
const applyPlugin = applyPluginFunction(
125+
{},
126+
fromPartial({ mode: "test" }),
127+
);
128+
129+
expect(applyPlugin).toBe(true);
130+
fsMocks.setMockVersion("4.0.18");
131+
});
101132
});
102133

103134
it("should apply the codspeed config for v4", () => {
135+
fsMocks.setMockVersion("4.0.18");
104136
const config = resolvedCodSpeedPlugin.config;
105137
if (typeof config !== "function")
106138
throw new Error("config is not a function");
107139

108-
const result = config.call({} as never, {}, fromPartial({}));
140+
const result = config.call(
141+
{} as never,
142+
{},
143+
fromPartial({ mode: "benchmark" }),
144+
);
109145

110146
expect(result).toStrictEqual({
111147
test: {
112148
globalSetup: [
113149
expect.stringContaining("packages/vitest-plugin/src/globalSetup.ts"),
114150
],
115151
pool: "forks",
116-
execArgv: [
117-
"--interpreted-frames-native-stack",
118-
"--allow-natives-syntax",
119-
"--hash-seed=1",
120-
"--random-seed=1",
121-
"--no-opt",
122-
"--predictable",
123-
"--predictable-gc-schedule",
124-
"--expose-gc",
125-
"--no-concurrent-sweeping",
126-
"--max-old-space-size=4096",
127-
],
152+
execArgv: EXPECTED_EXEC_ARGV,
128153
runner: expect.stringContaining(
129-
"packages/vitest-plugin/src/analysis.ts",
154+
"packages/vitest-plugin/src/legacy/analysis.ts",
130155
),
131156
},
132157
});
133158
});
134159

135160
it("should apply the codspeed config for v3 with poolOptions", () => {
136-
// Set mock version to v3
137161
fsMocks.setMockVersion("3.2.0");
138162

139-
// Create a new plugin instance to pick up the mocked version
140163
const v3Plugin = codspeedPlugin();
141164
const config = v3Plugin.config;
142165
if (typeof config !== "function")
143166
throw new Error("config is not a function");
144167

145-
const result = config.call({} as never, {}, fromPartial({}));
168+
const result = config.call(
169+
{} as never,
170+
{},
171+
fromPartial({ mode: "benchmark" }),
172+
);
146173

147174
expect(result).toStrictEqual({
148175
test: {
@@ -152,27 +179,64 @@ describe("codSpeedPlugin", () => {
152179
pool: "forks",
153180
poolOptions: {
154181
forks: {
155-
execArgv: [
156-
"--interpreted-frames-native-stack",
157-
"--allow-natives-syntax",
158-
"--hash-seed=1",
159-
"--random-seed=1",
160-
"--no-opt",
161-
"--predictable",
162-
"--predictable-gc-schedule",
163-
"--expose-gc",
164-
"--no-concurrent-sweeping",
165-
"--max-old-space-size=4096",
166-
],
182+
execArgv: EXPECTED_EXEC_ARGV,
167183
},
168184
},
169185
runner: expect.stringContaining(
170-
"packages/vitest-plugin/src/analysis.ts",
186+
"packages/vitest-plugin/src/legacy/analysis.ts",
171187
),
172188
},
173189
});
174190

175-
// Reset mock version back to v4
176191
fsMocks.setMockVersion("4.0.18");
177192
});
193+
194+
describe("v5 config", () => {
195+
it("should not inject config when benchmarks are not enabled", () => {
196+
fsMocks.setMockVersion("5.0.0-beta.5");
197+
const v5Plugin = codspeedPlugin();
198+
const config = v5Plugin.config;
199+
if (typeof config !== "function")
200+
throw new Error("config is not a function");
201+
202+
const result = config.call({} as never, {}, fromPartial({ mode: "test" }));
203+
204+
expect(result).toBeUndefined();
205+
fsMocks.setMockVersion("4.0.18");
206+
});
207+
208+
it("should inject the v5 setup file (not a runner) when benchmarks are enabled", () => {
209+
fsMocks.setMockVersion("5.0.0-beta.5");
210+
const v5Plugin = codspeedPlugin();
211+
const config = v5Plugin.config;
212+
if (typeof config !== "function")
213+
throw new Error("config is not a function");
214+
215+
const result = config.call(
216+
{} as never,
217+
// `benchmark.enabled` is a Vitest 5 config field the v3/4 typings (which
218+
// this file may be compiled against) don't expose.
219+
{ test: { benchmark: { enabled: true } } } as never,
220+
fromPartial({ mode: "test" }),
221+
);
222+
223+
expect(result).toStrictEqual({
224+
test: {
225+
globalSetup: [
226+
expect.stringContaining(
227+
"packages/vitest-plugin/src/globalSetup.ts",
228+
),
229+
],
230+
pool: "forks",
231+
execArgv: EXPECTED_EXEC_ARGV,
232+
setupFiles: [
233+
expect.stringContaining("packages/vitest-plugin/src/v5/setup.ts"),
234+
],
235+
},
236+
});
237+
// The v5 path must not set a custom runner.
238+
expect((result as { test?: { runner?: unknown } })?.test?.runner).toBeUndefined();
239+
fsMocks.setMockVersion("4.0.18");
240+
});
241+
});
178242
});

packages/vitest-plugin/src/__tests__/instrumented.test.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
import { fromPartial } from "@total-typescript/shoehorn";
22
import { describe, expect, it, vi, type RunnerTestSuite } from "vitest";
3+
// `vitest/suite` only exists on Vitest 3/4; this file is excluded from the test
4+
// run under v5+ (see vitest.config.ts).
5+
// eslint-disable-next-line import/no-unresolved
36
import { getBenchFn } from "vitest/suite";
4-
import { AnalysisRunner as CodSpeedRunner } from "../analysis";
7+
import { AnalysisRunner as CodSpeedRunner } from "../legacy/analysis";
8+
9+
// The legacy AnalysisRunner targets the Vitest 3/4 benchmark backend
10+
// (`NodeBenchmarkRunner`, `vitest/suite`), which Vitest 5 removed. This whole
11+
// file is excluded from the test run under v5+ (see vitest.config.ts); the v5
12+
// path is covered separately.
513

614
const coreMocks = vi.hoisted(() => {
715
return {

0 commit comments

Comments
 (0)