Skip to content

Commit 80d446d

Browse files
feat: add @codspeed/playwright package to bench electron apps
Introduce a @codspeed/playwright package exposing a Playwright-style `bench(name, fn, options)` API. The benchmark function receives a `{ page }` fixture mirroring Playwright's `test`, and a minimal options argument carrying the number of rounds and Electron launch config. Refs COD-2721 Co-Authored-By: Claude <noreply@anthropic.com>
1 parent ed6274a commit 80d446d

6 files changed

Lines changed: 498 additions & 6 deletions

File tree

packages/playwright/README.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<div align="center">
2+
<h1><code>@codspeed/playwright</code></h1>
3+
4+
[Playwright](https://playwright.dev) integration for [CodSpeed](https://codspeed.io), to benchmark [Electron](https://www.electronjs.org) apps end-to-end
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/playwright)](https://www.npmjs.com/package/@codspeed/playwright)
8+
[![Discord](https://img.shields.io/badge/chat%20on-discord-7289da.svg)](https://discord.com/invite/MxpaCfKSqF)
9+
[![CodSpeed Badge](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/CodSpeedHQ/codspeed-node)
10+
11+
</div>
12+
13+
## Documentation
14+
15+
Check out the [documentation](https://docs.codspeed.io/benchmarks/nodejs) for complete integration instructions.
16+
17+
## Installation
18+
19+
Install the plugin [`@codspeed/playwright`](https://www.npmjs.com/package/@codspeed/playwright) alongside `playwright` and your `electron` app dependency:
20+
21+
```sh
22+
npm install --save-dev @codspeed/playwright playwright electron
23+
```
24+
25+
or with `yarn`:
26+
27+
```sh
28+
yarn add --dev @codspeed/playwright playwright electron
29+
```
30+
31+
or with `pnpm`:
32+
33+
```sh
34+
pnpm add --save-dev @codspeed/playwright playwright electron
35+
```
36+
37+
## Usage
38+
39+
This integration measures an Electron app driven through Playwright. Build your
40+
app first so the Electron main entrypoint exists (e.g. `out/main/index.js`),
41+
then write a benchmark with the `bench` function.
42+
43+
`bench` launches the app once per round, drives it through the provided
44+
function, and reports the time spent inside that function to CodSpeed:
45+
46+
```ts title="bench/inbox.bench.ts"
47+
import { bench } from "@codspeed/playwright";
48+
import path from "node:path";
49+
50+
bench(
51+
"inbox-search",
52+
async ({ page }) => {
53+
await page.fill("#search", "quarterly report");
54+
await page.waitForSelector("#results");
55+
},
56+
{
57+
appPath: path.resolve("out/main/index.js"),
58+
// Bring the app to a steady state before each measured round (not measured).
59+
setup: async ({ page }) => {
60+
await page.waitForSelector("#main:not(.loading)");
61+
},
62+
rounds: 5,
63+
},
64+
);
65+
```
66+
67+
### Options
68+
69+
| Option | Type | Default | Description |
70+
| ------------------------ | ------------------------------------- | ------------------- | ----------------------------------------------------------------------------------------- |
71+
| `appPath` | `string` | _(required)_ | Absolute path to the Electron main entrypoint (e.g. `out/main/index.js`). |
72+
| `rounds` | `number` | `1` | Number of measurement rounds. Overridable via the `CODSPEED_ROUNDS` environment variable. |
73+
| `electronArgs` | `string[]` | `[]` | Extra CLI flags forwarded to Electron. |
74+
| `cwd` | `string` | `process.cwd()` | Working directory for the Electron process. Also where `electron` is resolved from. |
75+
| `electronExecutablePath` | `string` | resolved `electron` | Absolute path to the Electron binary. Set only to override the default resolution. |
76+
| `setup` | `({ page }) => void \| Promise<void>` || Runs before each round, after the window opens. Not measured. |
77+
| `teardown` | `({ page }) => void \| Promise<void>` || Runs after each round, before the app closes. Not measured. |
78+
79+
The function receives a Playwright [`Page`](https://playwright.dev/docs/api/class-page) for the Electron window as `page`.
80+
81+
## Running the benchmarks
82+
83+
Run your benchmark file with Node (or `tsx` for TypeScript):
84+
85+
```bash
86+
$ node bench/inbox.bench.ts
87+
[CodSpeed] [round 1/5] 42.13 ms
88+
...
89+
```
90+
91+
Locally this simply runs the app and prints per-round timings. Instrumentation
92+
and uploads to CodSpeed only happen in the
93+
[CI environment](https://docs.codspeed.io/benchmarks/nodejs#running-the-benchmarks-in-your-ci),
94+
where the CodSpeed runner picks up the results.

packages/playwright/package.json

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"name": "@codspeed/playwright",
3+
"version": "5.4.0",
4+
"description": "Playwright benchmarking integration for CodSpeed",
5+
"keywords": [
6+
"codspeed",
7+
"benchmark",
8+
"playwright",
9+
"electron",
10+
"performance"
11+
],
12+
"main": "dist/index.cjs",
13+
"module": "dist/index.es5.js",
14+
"types": "dist/index.d.ts",
15+
"type": "module",
16+
"exports": {
17+
"types": "./dist/index.d.ts",
18+
"import": "./dist/index.es5.js",
19+
"require": "./dist/index.cjs"
20+
},
21+
"files": [
22+
"dist"
23+
],
24+
"scripts": {
25+
"build": "NODE_NO_WARNINGS=1 rollup -c rollup.config.ts --configPlugin typescript",
26+
"test": "echo 'no tests'",
27+
"test/integ": "echo 'no integ tests'",
28+
"lint": "eslint .",
29+
"typecheck": "tsc --noEmit --pretty",
30+
"format": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --check .",
31+
"fix-format": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --write .",
32+
"clean": "rm -rf dist"
33+
},
34+
"author": "Guillaume Lagrange <guillaume@codspeed.io>",
35+
"repository": "https://github.com/CodSpeedHQ/codspeed-node",
36+
"homepage": "https://codspeed.io",
37+
"license": "Apache-2.0",
38+
"devDependencies": {
39+
"playwright": "^1.48.0",
40+
"playwright-core": "^1.48.0",
41+
"vitest": "^3.2.4"
42+
},
43+
"dependencies": {
44+
"@codspeed/core": "workspace:^5.4.0"
45+
},
46+
"peerDependencies": {
47+
"playwright": ">=1.40.0"
48+
}
49+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { defineConfig } from "rollup";
2+
import { declarationsPlugin, jsPlugins } from "../../rollup.options";
3+
import pkg from "./package.json" assert { type: "json" };
4+
5+
const entrypoint = "src/index.ts";
6+
7+
export default defineConfig([
8+
{
9+
input: entrypoint,
10+
output: [
11+
{
12+
file: pkg.types,
13+
format: "es",
14+
sourcemap: true,
15+
},
16+
],
17+
plugins: declarationsPlugin({ compilerOptions: { composite: false } }),
18+
},
19+
{
20+
input: entrypoint,
21+
output: [
22+
{
23+
file: pkg.main,
24+
format: "cjs",
25+
sourcemap: true,
26+
},
27+
{ file: pkg.module, format: "es", sourcemap: true },
28+
],
29+
plugins: jsPlugins(pkg.version),
30+
external: ["@codspeed/core", "playwright", "playwright-core"],
31+
},
32+
]);

0 commit comments

Comments
 (0)