Skip to content

Commit ebd23ca

Browse files
committed
feat(vitest-runner): add vitest-runner
1 parent 7acb19f commit ebd23ca

File tree

17 files changed

+4325
-6381
lines changed

17 files changed

+4325
-6381
lines changed

packages/vitest-runner/README.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<div align="center">
2+
<h1><code>@codspeed/vitest-runner</code></h1>
3+
4+
Custom [Vitest](https://vitest.dev) runner for [CodSpeed](https://codspeed.io)
5+
6+
[![CI](https://github.com/CodSpeedHQ/codspeed-node/actions/workflows/ci.yml/badge.svg)](https://github.com/CodSpeedHQ/codspeed-node/actions/workflows/ci.yml)
7+
[![npm (scoped)](https://img.shields.io/npm/v/@codspeed/tinybench-plugin)](https://www.npmjs.com/package/@codspeed/tinybench-plugin)
8+
[![Discord](https://img.shields.io/badge/chat%20on-discord-7289da.svg)](https://discord.com/invite/MxpaCfKSqF)
9+
10+
</div>
11+
12+
## Documentation
13+
14+
Check out the [documentation](https://docs.codspeed.io/benchmarks/nodejs) for complete integration instructions.
15+
16+
## Installation
17+
18+
First install the plugin [`@codspeed/vitest-runner`](https://www.npmjs.com/package/@codspeed/vitest-runner) and `vitest` (if not already installed):
19+
20+
```sh
21+
npm install --save-dev @codspeed/vitest-runner vitest
22+
```
23+
24+
or with `yarn`:
25+
26+
```sh
27+
yarn add --dev @codspeed/vitest-runner vitest
28+
```
29+
30+
or with `pnpm`:
31+
32+
```sh
33+
pnpm add --save-dev @codspeed/vitest-runner vitest
34+
```
35+
36+
## Usage
37+
38+
Let's create a fibonacci function and benchmark it with `vitest.bench`:
39+
40+
```ts title="benches/fibo.bench.ts"
41+
import { describe, bench } from "vitest";
42+
43+
function fibonacci(n: number): number {
44+
if (n < 2) {
45+
return n;
46+
}
47+
return fibonacci(n - 1) + fibonacci(n - 2);
48+
}
49+
50+
describe("fibonacci", () => {
51+
bench("fibonacci10", () => {
52+
fibonacci(10);
53+
});
54+
55+
bench("fibonacci15", () => {
56+
fibonacci(15);
57+
});
58+
});
59+
```
60+
61+
Create or update your `vitest.config.ts` file to use the CodSpeed runner:
62+
63+
```ts title="vitest.config.ts"
64+
import { defineConfig } from "vitest/config";
65+
import { withCodSpeed } from "@codspeed/vitest-runner";
66+
67+
export default withCodSpeed(
68+
defineConfig({
69+
// ...
70+
})
71+
);
72+
```
73+
74+
Finally, run your benchmarks (here with `pnpm`):
75+
76+
```bash
77+
$ pnpm vitest bench --run
78+
[CodSpeed] bench detected but no instrumentation found, falling back to default vitest runner
79+
80+
... Regular `vitest bench` output
81+
```
82+
83+
And... Congrats🎉, CodSpeed is installed in your benchmarking suite! Locally, CodSpeed will fallback to vitest since the instrumentation is only available in the CI environment for now.
84+
85+
You can now [run those benchmark in your CI](https://docs.codspeed.io/benchmarks/nodejs#running-the-benchmarks-in-your-ci) to continuously get consistent performance measurements.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { bench, describe } from "vitest";
2+
import parsePr from "./parsePr";
3+
4+
const LONG_BODY =
5+
new Array(1_000)
6+
.fill(
7+
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Sunt, earum. Atque architecto vero veniam est tempora fugiat sint quo praesentium quia. Autem, veritatis omnis beatae iste delectus recusandae animi non."
8+
)
9+
.join("\n") + "fixes #123";
10+
11+
describe("parsePr", () => {
12+
bench("short body", () => {
13+
parsePr({ body: "fixes #123", title: "test-1", number: 1 });
14+
});
15+
16+
bench("long body", () => {
17+
parsePr({ body: LONG_BODY, title: "test-2", number: 2 });
18+
});
19+
});
20+
21+
function fibo(n: number): number {
22+
if (n < 2) return 1;
23+
return fibo(n - 1) + fibo(n - 2);
24+
}
25+
26+
describe("fibo", () => {
27+
bench("fibo 10", () => {
28+
fibo(10);
29+
});
30+
bench("fibo 15", () => {
31+
fibo(15);
32+
});
33+
});
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { bench, describe } from "vitest";
2+
import parsePr from "./parsePr";
3+
4+
const LONG_BODY =
5+
new Array(1_000)
6+
.fill(
7+
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Sunt, earum. Atque architecto vero veniam est tempora fugiat sint quo praesentium quia. Autem, veritatis omnis beatae iste delectus recusandae animi non."
8+
)
9+
.join("\n") + "fixes #123";
10+
11+
describe("parsePr", () => {
12+
bench("short body", () => {
13+
parsePr({ body: "fixes #123", title: "test", number: 124 });
14+
});
15+
16+
bench("long body", () => {
17+
parsePr({ body: LONG_BODY, title: "test", number: 124 });
18+
});
19+
20+
describe("nested suite", () => {
21+
bench("short body", () => {
22+
parsePr({ body: "fixes #123", title: "test", number: 124 });
23+
});
24+
25+
bench("long body", () => {
26+
parsePr({ body: LONG_BODY, title: "test", number: 124 });
27+
});
28+
29+
describe("deeply nested suite", () => {
30+
bench("short body", () => {
31+
parsePr({ body: "fixes #123", title: "test", number: 124 });
32+
});
33+
});
34+
});
35+
});
36+
37+
describe("another parsePr", () => {
38+
bench("short body", () => {
39+
parsePr({ body: "fixes #123", title: "test", number: 124 });
40+
});
41+
42+
bench("long body", () => {
43+
parsePr({ body: LONG_BODY, title: "test", number: 124 });
44+
});
45+
46+
describe("nested suite", () => {
47+
bench("short body", () => {
48+
parsePr({ body: "fixes #123", title: "test", number: 124 });
49+
});
50+
});
51+
});
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
interface PullRequest {
2+
number: number;
3+
title: string;
4+
body: string;
5+
}
6+
7+
function sendEvent(numberOfOperations: number): void {
8+
for (let i = 0; i < numberOfOperations; i++) {
9+
let a = i;
10+
a = a + 1;
11+
}
12+
}
13+
14+
function logMetrics(
15+
numberOfOperations: number,
16+
numberOfDeepOperations: number
17+
): void {
18+
for (let i = 0; i < numberOfOperations; i++) {
19+
for (let i = 0; i < numberOfOperations; i++) {
20+
let a = i;
21+
a = a + 1;
22+
a = a + 1;
23+
}
24+
sendEvent(numberOfDeepOperations);
25+
}
26+
}
27+
28+
function parseTitle(title: string): void {
29+
logMetrics(10, 10);
30+
modifyTitle(title);
31+
}
32+
33+
function modifyTitle(title: string): void {
34+
for (let i = 0; i < 100; i++) {
35+
let a = i;
36+
a = a + 1 + title.length;
37+
}
38+
}
39+
40+
function prepareParsingBody(body: string): void {
41+
for (let i = 0; i < 100; i++) {
42+
let a = i;
43+
a = a + 1;
44+
}
45+
parseBody(body);
46+
}
47+
48+
function parseBody(body: string): void {
49+
logMetrics(10, 10);
50+
for (let i = 0; i < 200; i++) {
51+
let a = i;
52+
a = a + 1;
53+
}
54+
parseIssueFixed(body);
55+
}
56+
57+
function parseIssueFixed(body: string): number | null {
58+
const prefix = "fixes #";
59+
const index = body.indexOf(prefix);
60+
if (index === -1) {
61+
return null;
62+
}
63+
64+
const start = index + prefix.length;
65+
let end = start;
66+
while (end < body.length && /\d/.test(body[end])) {
67+
end += 1;
68+
}
69+
return parseInt(body.slice(start, end));
70+
}
71+
72+
export default function parsePr(pullRequest: PullRequest): void {
73+
parseTitle(pullRequest.title);
74+
prepareParsingBody(pullRequest.body);
75+
}

packages/vitest-runner/moon.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
tasks:
2+
bench:
3+
command: vitest bench
4+
inputs:
5+
- "benches/**"
6+
local: true
7+
options:
8+
cache: false
9+
10+
test:
11+
command: vitest --run
12+
inputs:
13+
- "./vitest.config.ts"
14+
15+
test/integ:
16+
command: noop
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "@codspeed/vitest-runner",
3+
"version": "2.2.0",
4+
"description": "vitest runner for CodSpeed",
5+
"keywords": [
6+
"codspeed",
7+
"benchmark",
8+
"vitest",
9+
"performance"
10+
],
11+
"main": "dist/index.es5.js",
12+
"types": "dist/index.d.ts",
13+
"type": "module",
14+
"files": [
15+
"dist"
16+
],
17+
"author": "Adrien Cacciaguerra <adrien@codspeed.io>",
18+
"repository": "https://github.com/CodSpeedHQ/codspeed-node",
19+
"homepage": "https://codspeed.io",
20+
"license": "Apache-2.0",
21+
"scripts": {
22+
"bench": "vitest bench"
23+
},
24+
"dependencies": {
25+
"@codspeed/core": "workspace:^2.2.0"
26+
},
27+
"devDependencies": {
28+
"@total-typescript/shoehorn": "^0.1.1",
29+
"execa": "^8.0.1",
30+
"vitest": "1.0.0-beta.4"
31+
},
32+
"peerDependencies": {
33+
"vitest": "^1.0.0-beta.4"
34+
}
35+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { defineConfig } from "rollup";
2+
import { declarationsPlugin, jsPlugins } from "../../rollup.options";
3+
import pkg from "./package.json" assert { type: "json" };
4+
5+
export default defineConfig([
6+
{
7+
input: "src/index.ts",
8+
// for some reasons, vitest only wants to require the `main` entrypoint
9+
// but fails when its CJS since it cannot require `vitest/*` modules, as
10+
// they are ESM only 🤷
11+
// we can circumvent this by exposing the `main` entrypoint as ESM
12+
output: { file: pkg.main, format: "es" },
13+
plugins: jsPlugins(pkg.version),
14+
external: ["@codspeed/core", /^vitest/],
15+
},
16+
{
17+
input: "src/index.ts",
18+
output: { file: pkg.types, format: "es" },
19+
plugins: declarationsPlugin({ compilerOptions: { composite: false } }),
20+
},
21+
{
22+
input: "src/globalSetup.ts",
23+
output: { file: "dist/globalSetup.es5.js", format: "es" },
24+
plugins: jsPlugins(pkg.version),
25+
external: ["@codspeed/core", /^vitest/],
26+
},
27+
{
28+
input: "src/runner.ts",
29+
output: { file: "dist/runner.es5.js", format: "es" },
30+
plugins: jsPlugins(pkg.version),
31+
external: ["@codspeed/core", /^vitest/],
32+
},
33+
]);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { describe, expect, it, vi } from "vitest";
2+
import globalSetup from "../globalSetup";
3+
4+
console.log = vi.fn();
5+
6+
vi.stubGlobal("__VERSION__", "1.0.0");
7+
8+
describe("globalSetup", () => {
9+
it("should log the correct message on setup and teardown, and fail when teardown is called twice", async () => {
10+
const teardown = globalSetup();
11+
12+
expect(console.log).toHaveBeenCalledWith(
13+
"[CodSpeed] @codspeed/vitest-runner v1.0.0 - setup"
14+
);
15+
16+
teardown();
17+
18+
expect(console.log).toHaveBeenCalledWith(
19+
"[CodSpeed] @codspeed/vitest-runner v1.0.0 - teardown"
20+
);
21+
22+
expect(() => teardown()).toThrowError("teardown called twice");
23+
});
24+
});

0 commit comments

Comments
 (0)