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

mocaron

v1.1.0

Published

Simple express mock server with a flexible API inspired by fetch-mock

Downloads

754

Readme



Installation

# npm
npm install -D mocaron

# yarn
yarn add -D mocaron

# pnpm
pnpm add -D mocaron

Quick Start

import { MockServer } from "mocaron";

const mockServer = new MockServer({ port: 3000 });

await mockServer.start();

mockServer.get("/test", { status: 200, body: { message: "Hello World" } });

const response = await fetch("http://localhost:3000/test");

console.log(response.status); // 200
console.log(await response.json()); // { message: "Hello World" }

await mockServer.stop();

Usage

Starting and stopping the mock server

See constructor() start() stop()

import { MockServer } from "mocaron";

const mockServer = new MockServer({ port: 3000 });

await mockServer.start();

// ...

await mockServer.stop();

Registering a mock

Register a mock using mock().

mockServer.mock(
  { path: "/test", method: "GET" },
  { status: 200, body: { message: "Hello World" } },
);

const response = await fetch("http://localhost:3000/test");

console.log(response.status); // 200
console.log(await response.json()); // { message: "Hello World" }

Method specific mocks

You can also register mocks that only match a specific HTTP method.

See get() post() put() patch() delete()

mockServer
  .get("/test", { status: 200, body: { message: "Hello World" } })
  .post("/test", { status: 201, body: { message: "Created" } })
  .put("/test", { status: 200, body: { message: "Replaced" } })
  .patch("/test", { status: 200, body: { message: "Updated" } })
  .delete("/test", { status: 204 });

Unmatched requests

If a request does not match any of the registered mocks the server will respond with a 404 status code.

const response = await fetch("http://localhost:3000/test");

console.log(response.status); // 404

Ambiguous mocks

If two or more mocks match the same request the server will respond with a 404 status code.

mockServer.mock({ path: "/foo" }, "foo").mock({ path: "/foo" }, "bar");

const response = await fetch("http://localhost:3000/foo");

console.log(response.status); // 404

You can override this behavior by passing the overwrite option to the last matching mock.

mockServer
  .mock({ path: "/foo" }, "foo")
  .mock({ path: "/foo" }, "bar", { overwrite: true });

const response = await fetch("http://localhost:3000/foo");

console.log(response.status); // 200
console.log(await response.text()); // bar

Resetting the mock server

Calling reset() will reset the mock server to its initial state.

mockServer.get("/test", { status: 200 });

let response = await fetch("http://localhost:3000/test");
console.log(response.status); // 200

mockServer.reset();

response = await fetch("http://localhost:3000/test");
console.log(response.status); // 404

Testing

Set up the mock server for each test using start(), stop() and reset().

import { MockServer } from "mocaron";
import { beforeAll, afterAll, beforeEach, test, assert } from "my-test-library";

const mockServer = new MockServer({ port: 3000 });

beforeAll(() => mockServer.start());
afterAll(() => mockServer.stop());
beforeEach(() => mockServer.reset());

Test that a mock has been called using hasBeenCalledWith().

test("mock has been called", async () => {
  mockServer.get("/test", { status: 200 });

  await fetch("http://localhost:3000/test");

  assert(mockServer.hasBeenCalledWith({ path: "/test" }));
});

Test that a mock has been called a specific number of times using hasBeenCalledTimes().

test("mock has been called 3 times", async () => {
  mockServer.get("/test", { status: 200 });

  await fetch("http://localhost:3000/test");
  await fetch("http://localhost:3000/test");
  await fetch("http://localhost:3000/test");

  assert(mockServer.hasBeenCalledTimes(3, { path: "/test" }));
});

Custom assertions using calls().

test("custom assertion", async () => {
  mockServer.get("/test", { status: 200 });

  await fetch("http://localhost:3000/test");

  assert(mockServer.calls().length === 1);
  assert(mockServer.calls()[0].request.path === "/test");
});

API

MockServer

constructor(options): MockServer

Create a new MockServer instance.

| Param | Type | Default | | ------- | --------------------- | ------- | | options | Options | - |

Example

const mockServer = new MockServer({ port: 3000 });

start(): Promise<void>

Start the mock server.

Example

await mockServer.start();

stop(): Promise<void>

Stop the mock server.

Example

await mockServer.stop();

port(): number

Get the port the mock server is running on.

Example

const port = mockServer.port();
console.log(port); // 3000

mock(matcher, response, options): MockServer

Register a mock.

| Param | Type | Default | | -------- | ----------------------------------------------- | ------- | | matcher | string | RegExp | Matcher | - | | response | string | number | Response | - | | options | MockOptions | {} |

If matcher is a string or RegExp, it will be used to match the request path.
If response is a string, it will be used as the response body.
If response is a number, it will be used as the response status code.

Returns the MockServer instance.

Example

mockServer.mock({ path: "/test" }, { status: 204 });

const response = await fetch("http://localhost:3000/test");

console.log(response.status); // 204

get(matcher, response, options): MockServer

Register a mock that only responds to requests using the HTTP GET method.

| Param | Type | Default | | -------- | --------------------------------------------------- | ------- | | matcher | string | RegExp | MatcherObj | - | | response | string | number | Response | - | | options | MockOptions | {} |

If matcher is a string or RegExp, it will be used to match the request path.
If response is a string, it will be used as the response body.
If response is a number, it will be used as the response status code.

Returns the MockServer instance.

Example

mockServer.get("/test", {
  status: 200,
  body: { message: "Hello World" },
});

const response = await fetch("http://localhost:3000/test");

console.log(response.status); // 200
console.log(await response.json()); // { message: "Hello World" }

post(matcher, response, options): MockServer

Register a mock that only responds to requests using the HTTP POST method.

| Param | Type | Default | | -------- | --------------------------------------------------- | ------- | | matcher | string | RegExp | MatcherObj | - | | response | string | number | Response | - | | options | MockOptions | {} |

If matcher is a string or RegExp, it will be used to match the request path.
If response is a string, it will be used as the response body.
If response is a number, it will be used as the response status code.

Returns the MockServer instance.

Example

mockServer.post("/test", {
  status: 201,
  body: { message: "Hello World" },
});

const response = await fetch("http://localhost:3000/test", {
  method: "POST",
  body: JSON.stringify({ message: "Hello World" }),
});

console.log(response.status); // 201
console.log(await response.json()); // { message: "Hello World" }

put(matcher, response, options): MockServer

Register a mock that only responds to requests using the HTTP PUT method.

| Param | Type | Default | | -------- | --------------------------------------------------- | ------- | | matcher | string | RegExp | MatcherObj | - | | response | string | number | Response | - | | options | MockOptions | {} |

If matcher is a string or RegExp, it will be used to match the request path.
If response is a string, it will be used as the response body.
If response is a number, it will be used as the response status code.

Returns the MockServer instance.

Example

mockServer.put("/test", {
  status: 200,
  body: { message: "Hello World" },
});

const response = await fetch("http://localhost:3000/test", {
  method: "PUT",
  body: JSON.stringify({ message: "Hello World" }),
});

console.log(response.status); // 200
console.log(await response.json()); // { message: "Hello World" }

patch(matcher, response, options): MockServer

Register a mock that only responds to requests using the HTTP PATCH method.

| Param | Type | Default | | -------- | --------------------------------------------------- | ------- | | matcher | string | RegExp | MatcherObj | - | | response | string | number | Response | - | | options | MockOptions | {} |

If matcher is a string or RegExp, it will be used to match the request path.
If response is a string, it will be used as the response body.
If response is a number, it will be used as the response status code.

Returns the MockServer instance.

Example

mockServer.patch("/test", {
  status: 200,
  body: { message: "Hello World" },
});

const response = await fetch("http://localhost:3000/test", {
  method: "PATCH",
  body: JSON.stringify({ message: "Hello World" }),
});

console.log(response.status); // 200
console.log(await response.json()); // { message: "Hello World" }

delete(matcher, response, options): MockServer

Register a mock that only responds to requests using the HTTP DELETE method.

| Param | Type | Default | | -------- | --------------------------------------------------- | ------- | | matcher | string | RegExp | MatcherObj | - | | response | string | number | Response | - | | options | MockOptions | {} |

If matcher is a string or RegExp, it will be used to match the request path.
If response is a string, it will be used as the response body.
If response is a number, it will be used as the response status code.

Returns the MockServer instance.

Example

mockServer.delete("/test", { status: 204 });

const response = await fetch("http://localhost:3000/test", {
  method: "DELETE",
});

console.log(response.status); // 204

mocks(): readonly Mock[]

Get all registered mocks.

Returns an array of Mock objects.

Example

mockServer.mock({ path: "/test" }, { status: 204 });

const mocks = mockServer.mocks();

console.log(mocks);
// [{ matcher: { path: "/test" }, response: { status: 204 } }]

calls(): readonly Call[]

Get all registered calls.

Returns an array of Call objects.

Example

mockServer.mock({ path: "/test" }, { status: 204 });
await fetch("http://localhost:3000/test");

const calls = mockServer.calls();

console.log(calls);
// [{ matcher: { path: "/test" }, request: <express.Request> }]

hasBeenCalledWith(matcher): boolean

Check if the route has been called with the given matcher.

| Param | Type | Default | | ------- | --------------------------------------------- | ------- | | matcher | string | RegExp | Matcher | - |

If matcher is a string or RegExp, it will be used to match the request path.

Returns true if the route has been called with the given matcher, false otherwise.

Example

mockServer.get("/test", { status: 200 });

console.log(mockServer.hasBeenCalledWith({ path: "/test" })); // false

await fetch("http://localhost:3000/test");

console.log(mockServer.hasBeenCalledWith({ path: "/test" })); // true

hasBeenCalledTimes(times, matcher): boolean

Check if the route has been called a certain number of times with the given matcher.

| Param | Type | Default | | ------- | --------------------------------------------- | ------- | | times | number | - | | matcher | string | RegExp | Matcher | - |

If matcher is a string or RegExp, it will be used to match the request path.

Returns true if the route has been called times times with the given matcher, false otherwise.

Example

mockServer.get("/test", { status: 200 });

console.log(mockServer.hasBeenCalledTimes(0, { path: "/test" })); // true
console.log(mockServer.hasBeenCalledTimes(1, { path: "/test" })); // false

await fetch("http://localhost:3000/test");

console.log(mockServer.hasBeenCalledTimes(0, { path: "/test" })); // false
console.log(mockServer.hasBeenCalledTimes(1, { path: "/test" })); // true

countCalls(matcher): number

Count the number of times the server was called with the given matcher.

| Param | Type | Default | | ------- | --------------------------------------------- | ------- | | matcher | string | RegExp | Matcher | - |

If matcher is a string or RegExp, it will be used to match the request path.

Returns the number of times the server has been called with the given matcher.

Example

mockServer.get("/test", { status: 200 });

console.log(mockServer.countCalls({ path: "/test" })); // 0

await fetch("http://localhost:3000/test");

console.log(mockServer.countCalls({ path: "/test" })); // 1

reset(): void

Reset all mocks and calls.

Example

mockServer.get("/test", { status: 200 });
await fetch("http://localhost:3000/test");

console.log(mockServer.mocks());
// [{ matcher: { path: "/test", method: "GET" }, response: { status: 200 } }]

console.log(mockServer.calls());
// [{ matcher: { path: "/test", method: "GET" }, request: <express.Request> }]

mockServer.reset();

console.log(mockServer.mocks()); // []
console.log(mockServer.calls()); // []

resetMocks(): void

Reset all mocks.

Example

mockServer.get("/test", { status: 200 });

console.log(mockServer.mocks());
// [{ matcher: { path: "/test", method: "GET" }, response: { status: 200 } }]

mockServer.resetMocks();

console.log(mockServer.mocks()); // []

resetCalls(): void

Reset all calls.

Example

mockServer.get("/test", { status: 200 });
await fetch("http://localhost:3000/test");

console.log(mockServer.calls());
// [{ matcher: { path: "/test", method: "GET" }, request: <express.Request> }]

mockServer.resetCalls();

console.log(mockServer.calls()); // []

ExpectationMessage

hasBeenCalledWith(mockServer, matcher): string

Format an expectation message for hasBeenCalledWith().

| Param | Type | Default | | ---------- | --------------------------- | ------- | | mockServer | MockServer | - | | matcher | Matcher | - |

Returns a string with the formatted expectation message.

Example

if (!mockServer.hasBeenCalledWith(matcher)) {
  throw new Error(ExpectationMessage.hasBeenCalledWith(mockServer, matcher));
}

hasBeenCalledTimes(mockServer, times, matcher): string

Format an expectation message for hasBeenCalledTimes().

| Param | Type | Default | | ---------- | --------------------------- | ------- | | mockServer | MockServer | - | | times | number | - | | matcher | Matcher | - |

Returns a string with the formatted expectation message.

Example

if (!mockServer.hasBeenCalledTimes(mockServer, 2, matcher)) {
  throw new Error(
    ExpectationMessage.hasBeenCalledTimes(mockServer, 2, matcher),
  );
}

Options

Object with the following properties:

| Property | Type | Description | | -------- | -------- | ------------------------------ | | port | number | port to run the mock server on |

Request

Type alias for express.Request with the body property typed as Buffer | undefined.

type Request = express.Request<{}, unknown, Buffer | undefined>;

Matcher

Type alias for MatcherObj | MatcherFn.

type Matcher = MatcherObj | MatcherFn;

MatcherObj

Object with the following properties:

| Property | Type | Description | | -------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | | method | string | undefined | HTTP method to match against | | path | string | RegExp | undefined | path to match against | | query | Request["query"] | undefined | query parameters to match against.Parameters explicitly set to undefined will not match when provided. | | headers | Record<string, string \| undefined> | undefined | headers to match against.Headers explicitly set to undefined will not match when provided. | | body | string | object | undefined | body to match against.If an object is given it will be compared to the request body parsed as JSON. |

MatcherFn

Function that takes a Request and returns whether the request should match.

type MatcherFn = (req: Request) => boolean;

Response

Type alias for ResponseObj | ResponseFn.

type Response = ResponseObj | ResponseFn;

ResponseObj

Object with the following properties:

| Property | Type | Description | | -------- | --------------------------------------- | ---------------------------------------------------------------------------------------- | | status | number | undefined | status code to respond with (defaults to 200) | | headers | Record<string, string> | undefined | headers to respond with | | body | string | object | undefined | body to respond with.If an object is given it will be converted to a JSON string. | | delay | number | undefined | delay in milliseconds before responding |

ResponseFn

Function or async function that takes a Request and returns a ResponseObj.

type ResponseFn = (req: Request) => ResponseObj | Promise<ResponseObj>;

MockOptions

Object with the following properties:

| Property | Type | Description | | --------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------ | | overwrite | boolean | undefined | when set to true,previous ambiguous mocks matching the same request will be overwritten |

Mock

Object with the following properties:

| Property | Type | Description | | -------- | ----------------------------- | -------------------------------------------------- | | matcher | Matcher | matcher to match against the request | | response | Response | response the server will respond with when matched | | options | MockOptions | see MockOptions |

Call

Object with the following properties:

| Property | Type | Description | | -------- | --------------------- | ----------------------------------- | | request | Request | request the server was called with | | matcher | Matcher | matcher the request matched against |

Changelog

CHANGELOG.md

License

MIT