Skip to content

Commit 56710b1

Browse files
committed
--wip-- [skip ci]
1 parent 52b8163 commit 56710b1

File tree

7 files changed

+571
-163
lines changed

7 files changed

+571
-163
lines changed

packages/vitest-plugin/benches/hooks.bench.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,17 @@ beforeEach(() => {
1818
count += 1;
1919
});
2020

21-
// the count is multiplied by 2 because the bench function is called twice with codspeed (once for the optimization and once for the actual measurement)
2221
bench("one", () => {
23-
expect(count).toBe(1 * 2);
22+
expect(count).toBe(1);
2423
});
2524

2625
describe("level1", () => {
2726
bench("two", () => {
28-
expect(count).toBe(2 * 2);
27+
expect(count).toBe(2);
2928
});
3029

3130
bench("three", () => {
32-
expect(count).toBe(3 * 2);
31+
expect(count).toBe(3);
3332
});
3433

3534
describe("level 2", () => {
@@ -38,12 +37,12 @@ describe("level1", () => {
3837
});
3938

4039
bench("five", () => {
41-
expect(count).toBe(5 * 2);
40+
expect(count).toBe(5);
4241
});
4342

4443
describe("level 3", () => {
4544
bench("seven", () => {
46-
expect(count).toBe(7 * 2);
45+
expect(count).toBe(7);
4746
});
4847
});
4948
});
@@ -54,12 +53,12 @@ describe("level1", () => {
5453
});
5554

5655
bench("one", () => {
57-
expect(count).toBe(1 * 2);
56+
expect(count).toBe(1);
5857
});
5958
});
6059

6160
bench("two", () => {
62-
expect(count).toBe(2 * 2);
61+
expect(count).toBe(2);
6362
});
6463
});
6564

packages/vitest-plugin/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,6 @@
3838
"@total-typescript/shoehorn": "^0.1.1",
3939
"execa": "^8.0.1",
4040
"vite": "^5.0.0",
41-
"vitest": "^1.2.2"
41+
"vitest": "^3.2.4"
4242
}
4343
}

packages/vitest-plugin/src/common.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import { getGitDir } from "@codspeed/core";
22
import path from "path";
3-
import { Suite, Task } from "vitest";
3+
import { type RunnerTask, type RunnerTestSuite } from "vitest";
44
import { getHooks } from "vitest/suite";
55

66
type SuiteHooks = ReturnType<typeof getHooks>;
77

8-
function getSuiteHooks(suite: Suite, name: keyof SuiteHooks) {
8+
function getSuiteHooks(suite: RunnerTestSuite, name: keyof SuiteHooks) {
99
return getHooks(suite)?.[name] ?? [];
1010
}
1111

1212
export async function callSuiteHook<T extends keyof SuiteHooks>(
13-
suite: Suite,
14-
currentTask: Task,
13+
suite: RunnerTestSuite,
14+
currentTask: RunnerTask,
1515
name: T
1616
): Promise<void> {
1717
if (name === "beforeEach" && suite?.suite) {
@@ -20,20 +20,18 @@ export async function callSuiteHook<T extends keyof SuiteHooks>(
2020

2121
const hooks = getSuiteHooks(suite, name);
2222

23+
// @ts-expect-error TODO: add support for hooks parameters
2324
await Promise.all(hooks.map((fn) => fn()));
2425

2526
if (name === "afterEach" && suite?.suite) {
2627
await callSuiteHook(suite.suite, currentTask, name);
2728
}
2829
}
2930

30-
export function patchRootSuiteWithFullFilePath(suite: Suite) {
31-
if (suite.filepath === undefined) {
32-
throw new Error("filepath is undefined is the root suite");
33-
}
34-
const gitDir = getGitDir(suite.filepath);
31+
export function patchRootSuiteWithFullFilePath(suite: RunnerTestSuite) {
32+
const gitDir = getGitDir(suite.file.filepath);
3533
if (gitDir === undefined) {
3634
throw new Error("Could not find a git repository");
3735
}
38-
suite.name = path.relative(gitDir, suite.filepath);
36+
suite.name = path.relative(gitDir, suite.file.filepath);
3937
}

packages/vitest-plugin/src/index.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
} from "@codspeed/core";
99
import { join } from "path";
1010
import { Plugin } from "vite";
11-
import { UserConfig } from "vitest/config";
11+
import { type ViteUserConfig } from "vitest/config";
1212

1313
// get this file's directory path from import.meta.url
1414
const __dirname = new URL(".", import.meta.url).pathname;
@@ -45,9 +45,11 @@ export default function codspeedPlugin(): Plugin {
4545
return true;
4646
},
4747
enforce: "post",
48-
config(): UserConfig {
48+
config(): ViteUserConfig {
4949
const runnerFile = getRunnerFile();
50-
const config: UserConfig = {
50+
const runnerMode = getCodspeedRunnerMode();
51+
52+
const config: ViteUserConfig = {
5153
test: {
5254
pool: "forks",
5355
poolOptions: {
@@ -56,14 +58,17 @@ export default function codspeedPlugin(): Plugin {
5658
},
5759
},
5860
globalSetup: [getCodSpeedFileFromName("globalSetup")],
61+
...(runnerFile && {
62+
runner: runnerFile,
63+
}),
64+
...(runnerMode === "walltime" && {
65+
benchmark: {
66+
includeSamples: true,
67+
},
68+
}),
5969
},
6070
};
6171

62-
// Only set custom runner when CODSPEED_ENV is set
63-
if (runnerFile) {
64-
config.test!.runner = runnerFile;
65-
}
66-
6772
return config;
6873
},
6974
};

packages/vitest-plugin/src/instrumented.ts

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
setupCore,
77
teardownCore,
88
} from "@codspeed/core";
9-
import { Benchmark, chai, Suite } from "vitest";
9+
import { Benchmark, type RunnerTestSuite } from "vitest";
1010
import { NodeBenchmarkRunner } from "vitest/runners";
1111
import { getBenchFn } from "vitest/suite";
1212
import { callSuiteHook, patchRootSuiteWithFullFilePath } from "./common";
@@ -32,20 +32,19 @@ async function runInstrumentedBench(
3232
const uri = `${currentSuiteName}::${benchmark.name}`;
3333
const fn = getBenchFn(benchmark);
3434

35-
await callSuiteHook(benchmark.suite, benchmark, "beforeEach");
36-
try {
37-
await optimizeFunction(fn);
38-
} catch (e) {
39-
// if the error is not an assertion error, we want to fail the run
40-
// we allow assertion errors because we want to be able to use `expect` in the benchmark to allow for better authoring
41-
// assertions are allowed to fail in the optimization phase since it might be linked to stateful code
42-
if (!(e instanceof chai.AssertionError)) {
43-
throw e;
35+
await optimizeFunction(async () => {
36+
if (benchmark.suite) {
37+
await callSuiteHook(benchmark.suite, benchmark, "beforeEach");
4438
}
45-
}
46-
await callSuiteHook(benchmark.suite, benchmark, "afterEach");
39+
await fn();
40+
if (benchmark.suite) {
41+
await callSuiteHook(benchmark.suite, benchmark, "afterEach");
42+
}
43+
});
4744

48-
await callSuiteHook(benchmark.suite, benchmark, "beforeEach");
45+
if (benchmark.suite) {
46+
await callSuiteHook(benchmark.suite, benchmark, "beforeEach");
47+
}
4948
await mongoMeasurement.start(uri);
5049
global.gc?.();
5150
await (async function __codspeed_root_frame__() {
@@ -55,24 +54,22 @@ async function runInstrumentedBench(
5554
Measurement.stopInstrumentation(uri);
5655
})();
5756
await mongoMeasurement.stop(uri);
58-
await callSuiteHook(benchmark.suite, benchmark, "afterEach");
57+
if (benchmark.suite) {
58+
await callSuiteHook(benchmark.suite, benchmark, "afterEach");
59+
}
5960

6061
logCodSpeed(`${uri} done`);
6162
}
6263

6364
async function runInstrumentedBenchmarkSuite(
64-
suite: Suite,
65+
suite: RunnerTestSuite,
6566
parentSuiteName?: string
6667
) {
6768
const currentSuiteName = parentSuiteName
6869
? parentSuiteName + "::" + suite.name
6970
: suite.name;
7071

71-
// do not call `beforeAll` if we are in the root suite, since it is already called by vitest
72-
// see https://github.com/vitest-dev/vitest/blob/1fee63f2598edc228017f18eca325f85ee54aee0/packages/runner/src/run.ts#L293
73-
if (parentSuiteName !== undefined) {
74-
await callSuiteHook(suite, suite, "beforeAll");
75-
}
72+
await callSuiteHook(suite, suite, "beforeAll");
7673

7774
for (const task of suite.tasks) {
7875
if (task.mode !== "run") continue;
@@ -84,15 +81,11 @@ async function runInstrumentedBenchmarkSuite(
8481
}
8582
}
8683

87-
// do not call `afterAll` if we are in the root suite, since it is already called by vitest
88-
// see https://github.com/vitest-dev/vitest/blob/1fee63f2598edc228017f18eca325f85ee54aee0/packages/runner/src/run.ts#L324
89-
if (parentSuiteName !== undefined) {
90-
await callSuiteHook(suite, suite, "afterAll");
91-
}
84+
await callSuiteHook(suite, suite, "afterAll");
9285
}
9386

9487
export class InstrumentedRunner extends NodeBenchmarkRunner {
95-
async runSuite(suite: Suite): Promise<void> {
88+
async runSuite(suite: RunnerTestSuite): Promise<void> {
9689
logDebug(`PROCESS PID: ${process.pid} in ${currentFileName}`);
9790
setupCore();
9891

packages/vitest-plugin/src/walltime.ts

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,28 @@ import {
66
type Benchmark,
77
type BenchmarkStats,
88
} from "@codspeed/core";
9-
import { BenchTaskResult, Suite, type Custom } from "vitest";
9+
import {
10+
type Benchmark as VitestBenchmark,
11+
type RunnerTask,
12+
type RunnerTaskResult,
13+
type RunnerTestSuite,
14+
} from "vitest";
1015
import { NodeBenchmarkRunner } from "vitest/runners";
1116
import { getBenchOptions } from "vitest/suite";
1217
import { patchRootSuiteWithFullFilePath } from "./common";
1318

1419
declare const __VERSION__: string;
1520

16-
// Vitest's task result structure extends Tinybench with additional properties
17-
interface VitestTaskResult {
18-
state: "pass" | "fail" | "skip" | "todo";
19-
startTime: number;
20-
duration?: number;
21-
benchmark?: BenchTaskResult;
21+
function isVitestTaskBenchmark(task: RunnerTask): task is VitestBenchmark {
22+
return task.type === "test" && task.meta.benchmark === true;
2223
}
2324

2425
/**
2526
* WalltimeRunner uses Vitest's default benchmark execution
2627
* and extracts results from the suite after completion
2728
*/
2829
export class WalltimeRunner extends NodeBenchmarkRunner {
29-
async runSuite(suite: Suite): Promise<void> {
30+
async runSuite(suite: RunnerTestSuite): Promise<void> {
3031
patchRootSuiteWithFullFilePath(suite);
3132

3233
console.log(
@@ -52,7 +53,7 @@ export class WalltimeRunner extends NodeBenchmarkRunner {
5253
}
5354

5455
private async extractBenchmarkResults(
55-
suite: Suite,
56+
suite: RunnerTestSuite,
5657
parentPath = ""
5758
): Promise<Benchmark[]> {
5859
const benchmarks: Benchmark[] = [];
@@ -61,11 +62,7 @@ export class WalltimeRunner extends NodeBenchmarkRunner {
6162
: suite.name;
6263

6364
for (const task of suite.tasks) {
64-
if (
65-
task.meta.benchmark &&
66-
task.type === "custom" &&
67-
task.result?.state === "pass"
68-
) {
65+
if (isVitestTaskBenchmark(task) && task.result?.state === "pass") {
6966
const benchmark = await this.processBenchmarkTask(task, currentPath);
7067
if (benchmark) {
7168
benchmarks.push(benchmark);
@@ -83,7 +80,7 @@ export class WalltimeRunner extends NodeBenchmarkRunner {
8380
}
8481

8582
private async processBenchmarkTask(
86-
task: Custom,
83+
task: VitestBenchmark,
8784
suitePath: string
8885
): Promise<Benchmark | null> {
8986
const uri = `${suitePath}::${task.name}`;
@@ -99,7 +96,7 @@ export class WalltimeRunner extends NodeBenchmarkRunner {
9996
const benchOptions = getBenchOptions(task);
10097

10198
const stats = this.convertVitestResultToBenchmarkStats(
102-
result as VitestTaskResult,
99+
result,
103100
benchOptions
104101
);
105102

@@ -135,7 +132,7 @@ export class WalltimeRunner extends NodeBenchmarkRunner {
135132
}
136133

137134
private convertVitestResultToBenchmarkStats(
138-
result: VitestTaskResult,
135+
result: RunnerTaskResult,
139136
benchOptions: {
140137
time?: number;
141138
warmupTime?: number;

0 commit comments

Comments
 (0)