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 🙏

© 2026 – Pkg Stats / Ryan Hefner

apiunit

v5.0.0

Published

Unit testing framework for API

Downloads

8,004

Readme

Apiunit

Apiunit is an awesome api unit testing framework! It allows creation of http requests and responses to create unit tests.

Commands

--input (-i): path to directory containing inputs (/requests is default) --diff (-d): path to directory containing expected output (/responses is default) --parameter (-p): path to the parameter .json file --prefix (-x): prefix of request(input) files to run --cmd (-c): command to be run between scenarios --scn (-s): The scenario or comma separated scenarios to run.

Parameter file example

Parameter files should be JSON format. Here is an example:

In this example we are running two scenarios named scn1 and scn2 on the folder(group) of "assets/testSuite". In each scenario, the PARAM1 and PARAM2 variables will be replaced with the values in the scenarios.

Request / Response file examples

Request files should end with .req, .msg, or .ws extension. Response files end with .resp (for .req), or .wsresp (for .ws). Every request should have a matching response with the same name minus extension. Response files can also use regular expressions to match expected responses.

Request files also allow the parameter APIUNIT-RETRY which can be set to any value, but default is 15000ms. APIUNIT-RETRY will retry the request until it matches the associated response or fails within the given timeframe.

Response files also allow the header apiunit-ignore-array-order which use a JSONPath expression to allow arrays to be unordered. Use path1,path2 where the value is a comma separated list of expressions to allow. Any array can be represented with $.., or a more explicit path can be specified. For example, targeting values in only key1 in the following json structure would look like data[*].key1.values.

{
   "data": [
      {
         "key1": {
            "values": [1,2,3]
         },
         "key2": {
            "values": [4,5,6]
         }
      },
      {
         "key1": {
            "values": [1,2,3]
         },
         "key2": {
            "values": [4,5,6]
         }
      }
   ]
}

Example request:

Example response:

WebSocket tests (.ws)

WebSocket requests use the .ws extension and pair with a .wsresp expected-response file.

All .ws files within the same suite (folder) share a single WebSocket connection per endpoint URL, so a CONNECT followed by one or more SEND requests reuse the same socket. Because the flow is stateful, .ws files in a suite are executed in filename order — name them accordingly (e.g. 01_connect.ws, 02_prompt.ws). The shared connection(s) are closed when the suite finishes.

Verbs

  • CONNECT <wss-url> — Opens (or reuses) the connection and asserts the handshake. The response carries the handshake status code (101 on success, e.g. 403 when the server rejects the connection), so authentication can be tested explicitly. No body is read.
  • SEND <wss-url> — Reuses the suite connection, auto-connecting on demand if no CONNECT ran first (using this request's sec-websocket-protocol), then sends the request body and reads incoming frames until stream completion (or the read times out), bucketing them into { streams, others } — see "Chunk merge semantics" below.

A WebSocket subprotocol is negotiated only at connect time and cannot change on an open socket, so the token is fixed by whichever request first opens the connection to a URL. Reusing the connection with the same sec-websocket-protocol (or none) is fine; supplying a different protocol for a URL that is already connected is an error (it would otherwise be silently ignored). The normal flow — CONNECT with a token, then token-less SENDs — is unaffected. To assert an authentication rejection (e.g. 403), use CONNECT (which returns the handshake status), rather than relying on SEND's auto-connect (which surfaces a rejected handshake as a request error).

Authentication and headers

  • sec-websocket-protocol: sent as the WebSocket subprotocol(s) on the handshake (comma-separated for multiple). This is the generic way to pass an auth token.
  • apiunit-ws-merge-path: the path within each frame to the value that is bucketed/merged. Default is payload.body with a strict fallback: if a frame lacks that path, the whole frame is used for that frame. When set explicitly there is no fallback — a frame lacking the path contributes undefined. Use . (or $) to select the whole frame. See "Chunk merge semantics" below.
  • apiunit-ws-stream-id-header: the frame header whose value identifies a stream (default x-stream-id, the configurapi convention). Frames carrying this header are merged per id; frames without it are collected under others.
  • apiunit-ws-done-grace: after a done marker, how long (ms) to keep reading for trailing frames a server may emit after the stream completes (e.g. configurapi's sessionNameUpdated). Default 1000. Set to 0 to stop immediately on done.
  • APIUNIT-RETRY: for .ws this is the per-message idle read timeout in milliseconds — .ws requests are never re-sent (a streamed send is not idempotent), so unlike .req/.msg the header does not retry; it specifies how long to wait for the next frame before ending the stream. true maps to 15000, a number is used as-is, and absent falls back to 10000. This is the maximum wait between frames, not a total budget for the whole stream — the clock resets each time a frame arrives, so a steady stream never times out while a stalled one does.

Stream termination

A stream ends when a received frame carries the marker x-stream: done — checked first in a top-level headers object on the frame (the configurapi convention), and, if absent there, anywhere within the frame body (a generic fallback).

A done marker ends the stream, but a server may emit trailing frames after it (e.g. configurapi sends a sessionNameUpdated push once the answer is complete). So after done, apiunit keeps reading for a short grace window (apiunit-ws-done-grace, default 1000ms) to drain those trailing frames, then stops. Set the grace to 0 to stop immediately on done.

If no done ever arrives, the read ends on the per-message idle timeout (APIUNIT-RETRY): if no new frame arrives within that window, whatever has been received so far is bucketed and returned — a partial response (status code 0 if nothing arrived at all). This is not an error: the partial result is diffed against the .wsresp like any response, so an incomplete stream surfaces as a body-assertion mismatch rather than an exception.

Chunk merge semantics

A streamed response arrives as a non-deterministic number of frames, and it interleaves two different things: the streamed content (many chunks of one value) and discrete events (status, notifications). apiunit reconciles both by bucketing the frames into a single deterministic object:

  • streams — frames carrying a stream-id header (apiunit-ws-stream-id-header, default x-stream-id) are grouped by that id and merged into one value per id. Because merging collapses any number of chunks into one value, this is independent of the chunk count. Multiple concurrent stream ids are supported.
  • others — every frame without a stream id is collected in arrival order (not merged), so discrete events stay individually assertable. others is an array, so apiunit-ignore-array-order and per-element regexes apply.

From each frame the bucketed value is extracted at payload.body by default, falling back to the whole frame when that path is absent (strict: only when the key is missing, not when it is empty). Set apiunit-ws-merge-path to override (no fallback when set); . or $ selects the whole frame.

Within a stream bucket, values are merged in arrival order:

  • string + string → concatenation ("Hel" + "lo" → "Hello")
  • number + number → addition (2 + 4 → 6)
  • boolean + boolean → logical AND (true + false → false)
  • array + array → concatenation (["a","b"] + ["x"] → ["a","b","x"])
  • object + object → deep merge by key
  • a key present in only one frame is taken as-is
  • type mismatch → both values are stringified and concatenated (1 + true → "1true")

The asserted status code is that of the last non-done frame (the terminal done frame's status, e.g. 204, is ignored). The asserted response headers are the headers of the last frame received, verbatim; content-type defaults to application/json only when the last frame does not set one, so the bucketed body is diffed as JSON. As with .req/.msg, a .wsresp only asserts the headers it cares about — extra response headers are allowed.

Example .ws request (02_prompt.ws):

Example .wsresp for a configurapi stream (assembled answer under streams, discrete events under others; regexes supported):

Example Execution

To run a simple apiunit task just run the command "node ../node_modules/.bin/apiunit -i specs/requests -d specs/responses -p parameters.json -c "npm run add-some-data-or-something"".

Migration of v3 to v4

In 4.0.0 apiunit changed from using (json-path)[https://www.npmjs.com/package/json-path?activeTab=readme] to (jsonpath)[https://www.npmjs.com/package/jsonpath?activeTab=readme]. This is a breaking change, however, we attempted to support for the simple use case of /propertyName returning was preserved. In any other case the query needs to be re-written in the new supported notation (see jsonpath documentation).