Socket
Socket
Sign inDemoInstall

mocaron

Package Overview
Dependencies
123
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    mocaron

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


Version published
Weekly downloads
222
decreased by-46.12%
Maintainers
1
Created
Weekly downloads
 

Changelog

Source

[v1.1.0] - 2024-04-18

  • Added ExpectationMessage for formatting expectation messages
  • Added delay option to response object
  • Added support for async functions as response handlers

Readme

Source

mocaron

npm downloads Coverage Status code style: prettier

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



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.

ParamTypeDefault
optionsOptions-
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.

ParamTypeDefault
matcherstring | RegExp | Matcher-
responsestring | number | Response-
optionsMockOptions{}

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.

ParamTypeDefault
matcherstring | RegExp | MatcherObj-
responsestring | number | Response-
optionsMockOptions{}

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.

ParamTypeDefault
matcherstring | RegExp | MatcherObj-
responsestring | number | Response-
optionsMockOptions{}

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.

ParamTypeDefault
matcherstring | RegExp | MatcherObj-
responsestring | number | Response-
optionsMockOptions{}

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.

ParamTypeDefault
matcherstring | RegExp | MatcherObj-
responsestring | number | Response-
optionsMockOptions{}

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.

ParamTypeDefault
matcherstring | RegExp | MatcherObj-
responsestring | number | Response-
optionsMockOptions{}

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.

ParamTypeDefault
matcherstring | 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.

ParamTypeDefault
timesnumber-
matcherstring | 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.

ParamTypeDefault
matcherstring | 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().

ParamTypeDefault
mockServerMockServer-
matcherMatcher-

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().

ParamTypeDefault
mockServerMockServer-
timesnumber-
matcherMatcher-

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:

PropertyTypeDescription
portnumberport 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:

PropertyTypeDescription
methodstring | undefinedHTTP method to match against
pathstring | RegExp | undefinedpath to match against
queryRequest["query"] | undefinedquery parameters to match against.
Parameters explicitly set to undefined will not match when provided.
headersRecord<string, string | undefined> | undefinedheaders to match against.
Headers explicitly set to undefined will not match when provided.
bodystring | object | undefinedbody 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:

PropertyTypeDescription
statusnumber | undefinedstatus code to respond with (defaults to 200)
headersRecord<string, string> | undefinedheaders to respond with
bodystring | object | undefinedbody to respond with.
If an object is given it will be converted to a JSON string.
delaynumber | undefineddelay 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:

PropertyTypeDescription
overwriteboolean | undefinedwhen set to true,
previous ambiguous mocks matching the same request will be overwritten

Mock

Object with the following properties:

PropertyTypeDescription
matcherMatchermatcher to match against the request
responseResponseresponse the server will respond with when matched
optionsMockOptionssee MockOptions

Call

Object with the following properties:

PropertyTypeDescription
requestRequestrequest the server was called with
matcherMatchermatcher the request matched against

Changelog

CHANGELOG.md

License

MIT

Keywords

FAQs

Last updated on 18 Apr 2024

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc