Simple express mock server with a flexible API inspired by fetch-mock
Installation
npm install -D mocaron
yarn add -D mocaron
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);
console.log(await response.json());
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);
console.log(await response.json());
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);
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);
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);
console.log(await response.text());
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);
mockServer.reset();
response = await fetch("http://localhost:3000/test");
console.log(response.status);
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.
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);
mock(matcher, response, options): MockServer
Register a mock.
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);
get(matcher, response, options): MockServer
Register a mock that only responds to requests using the HTTP GET
method.
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);
console.log(await response.json());
post(matcher, response, options): MockServer
Register a mock that only responds to requests using the HTTP POST
method.
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);
console.log(await response.json());
put(matcher, response, options): MockServer
Register a mock that only responds to requests using the HTTP PUT
method.
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);
console.log(await response.json());
patch(matcher, response, options): MockServer
Register a mock that only responds to requests using the HTTP PATCH
method.
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);
console.log(await response.json());
delete(matcher, response, options): MockServer
Register a mock that only responds to requests using the HTTP DELETE
method.
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);
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);
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);
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" }));
await fetch("http://localhost:3000/test");
console.log(mockServer.hasBeenCalledWith({ path: "/test" }));
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" }));
console.log(mockServer.hasBeenCalledTimes(1, { path: "/test" }));
await fetch("http://localhost:3000/test");
console.log(mockServer.hasBeenCalledTimes(0, { path: "/test" }));
console.log(mockServer.hasBeenCalledTimes(1, { path: "/test" }));
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" }));
await fetch("http://localhost:3000/test");
console.log(mockServer.countCalls({ path: "/test" }));
reset(): void
Reset all mocks and calls.
Example
mockServer.get("/test", { status: 200 });
await fetch("http://localhost:3000/test");
console.log(mockServer.mocks());
console.log(mockServer.calls());
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());
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());
mockServer.resetCalls();
console.log(mockServer.calls());
ExpectationMessage
hasBeenCalledWith(mockServer, matcher): string
Format an expectation message for hasBeenCalledWith()
.
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()
.
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:
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