zerospikes

Tests that catchslow interactions.
The first run sets the limits. Later runs fail when a change goes over them.

Get started
npm install -D zerospikes

What it adds to Playwright

How it works

A Playwright test, with test imported from zerospikes. Here zs.measure types "mar" into the search box several times, clearing it before each, and keeps the median. Setup

perf/search.perf.ts
import { test } from "zerospikes";

test("filter as you type", async ({ page, zs }) => {
  await page.goto("/");
  const search = page.getByRole("searchbox");

  await zs.measure(
    "type 'mar'",
    () => search.pressSequentially("mar"),
    { before: () => search.fill("") },
  );
});

The first run passes and records a limit for each metric: its slowest time plus room for noise.

Terminal
$ npx playwright test
  PASS    filter as you type (4.1s)

  zerospikes  1 scenario · all within limits · 1 limits recorded
$ 

Later, a change to the search makes every key press scan all the rows. Each key now takes 212 ms against a limit of 64, and the test fails.

Terminal
$ npx playwright test
  FAIL    filter as you type (4.6s)

  zerospikes  1 scenario · 1 over limits
  FAIL   filter as you type › type 'mar'   input key 212 ms > 64, frame.max 205 ms > 58
$ 

In npx zerospikes, the failed scenario lists its numbers, limits and the functions that took the time. If the slowdown is on purpose, Press w to save it as the new limits.

npx zerospikes
  filter as you type › type 'mar'  FAIL

    Metric                 Last      Limit
    frame.max            205 ms      58 ms
    input.key            212 ms      64 ms

  Where the time went
       188 ms  filterRows  src/search.js:42
        14 ms  renderList  src/list.js:17

  Slower than its limits. On purpose? w save the last run as its limits

Questions

Why zerospikes?

Measuring an interaction in DevTools means recording a trace, reading it and remembering the number for next time. As a test, the measurement runs on every change, and CI fails on the pull request that makes the interaction slower.

Won't noise make tests fail for no reason?

Each scenario runs once to warm up and five more times, and the median is what gets checked. A recorded limit leaves room above the slowest run. A local machine busy with something heavy, can still go over. On hosted CI, zerospikes measures both builds in alternating sessions and fails only on a slowdown of 10% or more that isn't noise. Read more at Limits.

Which browsers and apps does it work with?

Frame and input times work in any Playwright browser. CPU time, long frames, memory checks and the profile of a failure need Chromium. It also measures Electron apps, and Tauri apps on Windows, through their DevTools port (experimental).

How is it different from a regular Playwright test?

A Playwright test checks that the interaction works, and passes whether it takes 20 ms or 500 ms. A zerospikes scenario is still a Playwright test, but it also fails when the interaction takes longer than its limits.