zerospikes

API reference

import { test, expect } from "zerospikes";

test is Playwright's, with the zs fixture. The types (MeasureOptions, ScenarioResult, ZeroSpikesOptions…) are exported too.

zs.measure(name, act, options?)

Runs act warmup + runs times and checks the median of each metric against its limits. A scenario over them fails the test when it ends, like expect.soft, after one more CPU-profiled run. Returns the ScenarioResult.

OptionDefault
runs5Measured runs
warmup1Unmeasured runs first, for JIT and caches
beforeBefore every run, unmeasured: the starting state
afterAfter every run, unmeasured: undo what act did
settleMs300Keep recording after act, so debounced work counts
limitsFixed limits, such as { "frame.max": 50 }
profileOnFailtrueCPU-profile a run when a limit is missed. Chromium only

name must be unique within the test.

zs.cycles(name, cycle, options?)

Runs warmup cycles, then cycles more, and checks what stayed behind in memory. Chromium only: elsewhere it returns null.

OptionDefault
cycles5Measured cycles
warmup1Cycles before the baseline
limitsFixed limits, such as { "memory.nodes": 0 }

zs.drag(from, to, { steps? })

Presses at from, moves to to in steps (default 20), one pointermove per frame, and releases.

zs.frame()

Resolves on the page's next animation frame.

Config options

Option
zsIgnoreErrorsErrors the page may log without failing the scenario. See Limits
ZS_ALLOW_WORSE=1Environment variable: with -u, save the limits even when slower

Desktop apps (experimental)

To measure a running Tauri (Windows) or Electron app, import test from zerospikes/app and point the project at the app's DevTools port. page is then the app's window, the same one in every test: put it back in its starting state in beforeEach.

playwright.config.ts
import { defineConfig } from "@playwright/test";
import type { ZeroSpikesAppOptions } from "zerospikes/app";

export default defineConfig<ZeroSpikesAppOptions>({
  workers: 1, // the app has one window
  projects: [{ name: "tauri", use: { zsConnect: "http://127.0.0.1:9222" } }],
  webServer: {
    command: "npx tauri dev",
    env: { WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS: "--remote-debugging-port=9222" },
    url: "http://127.0.0.1:9222/json/version",
    reuseExistingServer: true,
  },
});

Start Electron with --remote-debugging-port=9222. macOS and Linux webviews have no DevTools port: measure the frontend in a browser there. zerospikes compare doesn't work with apps.