Skip to content

Commit

Permalink
Merge pull request #29 from joshuajaco/add-response-delay
Browse files Browse the repository at this point in the history
Add optional delay to response
  • Loading branch information
joshuajaco authored Apr 18, 2024
2 parents 83f7ad0 + fcf5b56 commit 6794e42
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 45 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -786,13 +786,14 @@ Object with the following properties:
| 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.<br/>If an `object` is given it will be converted to a JSON string. |
| delay | `number` \| `undefined` | delay in milliseconds before responding |

## `ResponseFn`

Function that takes a [`Request`](#request) and returns a [`ResponseObj`](#responseobj).
Function or async function that takes a [`Request`](#request) and returns a [`ResponseObj`](#responseobj).

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

## `MockOptions`
Expand Down
99 changes: 56 additions & 43 deletions src/MockServer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type http from "node:http";
import { setTimeout } from "node:timers/promises";
import express from "express";
import bodyParser from "body-parser";
import { matchRequest } from "./matchRequest";
Expand All @@ -22,14 +23,19 @@ export type ResponseObj = {
* @see [Documentation]{@link https://github.com/joshuajaco/mocaron#responseobj}
*/
body?: string | object;
/**
* delay in milliseconds before responding
* @see [Documentation]{@link https://github.com/joshuajaco/mocaron#responseobj}
*/
delay?: number;
};

/**
* @param {Request} req - request to match against
* @returns {ResponseObj} response the mock server should respond with
* @see [Documentation]{@link https://github.com/joshuajaco/mocaron#responsefn}
*/
export type ResponseFn = (req: Request) => ResponseObj;
export type ResponseFn = (req: Request) => ResponseObj | Promise<ResponseObj>;

/**
* response the mock server should respond with
Expand Down Expand Up @@ -114,50 +120,57 @@ export class MockServer {
});

// eslint-disable-next-line @typescript-eslint/ban-types
this.#app.all<"*", {}, unknown, Buffer | undefined>("*", (req, res) => {
const matches = this.#mocks.filter(({ matcher }) =>
matchRequest(matcher, req),
);

if (matches.length === 0) {
console.warn("Unmatched", req.method, req.path);
return res.status(404).end();
}

const match = matches.length === 1 ? matches[0] : matches.at(-1)!;

this.#calls.push({
request: req,
matcher: match.matcher,
});

if (matches.length > 1 && !match.options.overwrite) {
console.warn("Ambiguous", req.method, req.path);
console.warn("use overwrite: true");
return res.status(404).end();
}

const response =
typeof match.response === "function"
? match.response(req)
: match.response;

res.status(response.status ?? 200);

if (response.headers) {
Object.entries(response.headers).forEach(([k, v]) => res.header(k, v));
}

if (response.body) {
res.send(
typeof response.body === "string"
? response.body
: JSON.stringify(response.body),
this.#app.all<"*", {}, unknown, Buffer | undefined>(
"*",
async (req, res) => {
const matches = this.#mocks.filter(({ matcher }) =>
matchRequest(matcher, req),
);
}

res.end();
});
if (matches.length === 0) {
console.warn("Unmatched", req.method, req.path);
return res.status(404).end();
}

const match = matches.length === 1 ? matches[0] : matches.at(-1)!;

this.#calls.push({
request: req,
matcher: match.matcher,
});

if (matches.length > 1 && !match.options.overwrite) {
console.warn("Ambiguous", req.method, req.path);
console.warn("use overwrite: true");
return res.status(404).end();
}

const response =
typeof match.response === "function"
? await match.response(req)
: match.response;

if (response.delay) await setTimeout(response.delay);

res.status(response.status ?? 200);

if (response.headers) {
Object.entries(response.headers).forEach(([k, v]) =>
res.header(k, v),
);
}

if (response.body) {
res.send(
typeof response.body === "string"
? response.body
: JSON.stringify(response.body),
);
}

res.end();
},
);
}

/**
Expand Down
1 change: 1 addition & 0 deletions tests/MockServer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ describe("MockServer", () => {
mockServer.get("/test", {
body: "Hello World",
headers: { "Content-Type": "text/plain" },
delay: 1,
});

const response = await fetch(`${host}/test`);
Expand Down

0 comments on commit 6794e42

Please sign in to comment.