npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

toofast

v2.0.0

Published

The Node.js performance testing tool with unit-test-like API.

Downloads

84

Readme

TooFast ⚡️ build

The Node.js performance testing tool with unit-test-like API.

  • Runs each test in a separate process;
  • Measures execution time using performance;
  • Runs test functions in multiple batches to reduce garbage collection interference;
  • Warms up test functions;
  • Measures memory consumption using process.memoryUsage.
npm install toofast --save-dev

Usage

Let's write a performance test for a function that computes a factorial.

Create a file factorial.perf.js:

function factorial(x) {
  return x === 0 ? 1 : x * factorial(x - 1);
}

describe('factorial', () => {

  test('of 33', measure => {
    measure(() => {
      factorial(33);
    });
  });

  test('of 42', measure => {
    measure(() => {
      factorial(42);
    });
  });
});

Call toofast in the same directory with this file:

npx toofast

CLI options

toofast [options] ...files

The list of glob patterns of included test files. If config file was not found, then files that match **/*.perf.js are included.

The configuration file path.

The name glob pattern of describe and test blocks that should be run. If specified multiple times then blocks that match any of the patterns are run.

Test API

🔎 Programmatic API documentation is available here.

TooFast injects several global callbacks in test files that register lifecycle hooks and trigger test execution.

test

The minimum setup that you need in a test file is the test callback which runs a test. For example, let's say there's a function factorial() which performance must be measured. Your whole test could be:

test('factorial of 33', measure => {
  measure(() => {
    factorial(33);
  });
});

The measure callback starts the performance measurement. It can be invoked multiple times inside a test block to collect a data population from which an average results are derived.

test('factorial of 33 and 42', measure => {

  measure(() => {
    factorial(33);
  });

  measure(() => {
    factorial(42);
  });
});

The measure callback returns a promise that is resolved as soon as performance measurement is completed.

Test lifecycle is initiated for each test block and run in a separate process.

describe

Creates a block that groups together several related tests.

describe('factorial', () => {

  test('of 42', measure => {
    measure(() => {
      factorial(42);
    });
  });
});

describe blocks can be nested:

describe('Math', () => {

  describe('factorial', () => {
    // Tests go here
  });
});

Lifecycle hooks

There are several global functions injected by TooFast that register hooks. Hooks are invoked at different phases of the performance test suite lifecycle: beforeEach, afterEach, afterWarmup, beforeBatch, afterBatch, beforeIteration, and afterIteration.

The chart below demonstrates when they are called.

flowchart TD

describe --> testLifecycle

subgraph testLifecycle [Test lifecycle]
    direction LR

    subgraph warmup [Warmup]
        direction TB
        warmupBeforeBatch(beforeBatch) -->
        warmupBeforeIteration(beforeIteration) -->
        warmupMeasure[measure] -->
        warmupAfterWarmup(afterWarmup) -->
        warmupAfterIteration(afterIteration) -->
        warmupAfterBatch(afterBatch)
    end

    subgraph batch [Batch]
        direction TB
        testBeforeBatch(beforeBatch) -->
        testBeforeIteration(beforeIteration) -->
        testMeasure[measure] -->
        testAfterIteration(afterIteration) -->
        testAfterBatch(afterBatch)
    end

    beforeEach(beforeEach) -->
    test -->
    warmup -->
    batch -->
    afterEach(afterEach)
end

Hooks can be registered at root level, or inside a describe or test block. Registered hooks affect measure calls that are nested in the same enclosing block.

Hooks are always registered before any measurements are started, so the code below would first register beforeEach and beforeIteration hooks and only after that would run measure.

describe('factorial', () => {

  beforeEach(() => {
    // Runs before each test
  });

  test('of 42', measure => {
    measure(() => {
      factorial(42);
    });

    beforeIteration(() => {
      // Runs before each measurement iteration
    });
  });
});

Test options

Provide test options to test, describe and measure functions. Options of nested blocks are merged.

describe('factorial', { batchTimeout: 500 }, () => {

  test('of 42', { targetRme: 0.2 }, measure => {

    measure({ warmupIterationCount: 5 }, () => {
      factorial(42);
    });
  });
});

The maximum measure duration in milliseconds. Doesn't include the duration of warmup iterations. Defaults to 10_000.

The maximum relative margin of error that must be reached for each measurement [0, 1]. Defaults to 0.01.

The maximum number of warmup iterations that are run before each measurement. Defaults to 1. Set to 0 to disable warmup.

The maximum number of iterations in a batch. Unlimited by default.

The maximum duration of batched measurements in milliseconds. Defaults to 1_000.

The delay between batched measurements in milliseconds. VM is expected to run garbage collector during this delay. Defaults to 200.

You can also register hooks specific for a particular measure call.

test('factorial', measure => {
  measure(
    {
      beforeBatch() {
        gc();
      }
    },
    () => {
      factorial(42);
    }
  );
});

Configuration

By default, TooFast searches for .toofastrc, toofast.json, or toofast.config.js in the current directory.

Configuration file should export the object that satisfies the Config interface:

The default test options used for all tests.

The array of glob patterns of included test files. File paths are resolved relative to the config file.

The array of glob patters of files that are evaluated in the test environment before any test suites are run. File paths are resolved relative to the config file.