Skip to content

Commit

Permalink
Merge pull request #285 from thefrontside/foundation-delay
Browse files Browse the repository at this point in the history
foundation simulator delay response API
  • Loading branch information
jbolda authored Sep 13, 2024
2 parents 56ac29c + e4027ef commit 8f46cd4
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changes/foundation-delay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@simulacrum/foundation-simulator": minor:enhance
---

Add API to configure a delay of all responses with a set interval. Using this in a simulator would enable a feel closer to a real external endpoint.
4 changes: 4 additions & 0 deletions packages/foundation/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import type {
SimulationRoute,
} from "./store/schema";
import type { RecursivePartial } from "./store/types";
import { delayMiddleware } from "./middleware/delay";
import { generateRoutesHTML } from "./routeTemplate";

type SimulationHandlerFunctions = (
Expand All @@ -57,12 +58,14 @@ export function createFoundationSimulationServer<
ExtendedSimulationSelectors
>({
port = 9000,
delayResponses,
serveJsonFiles,
openapi,
extendStore,
extendRouter,
}: {
port: number;
delayResponses?: number | { minimum: number; maximum: number };
serveJsonFiles?: string;
openapi?: {
document: Document | (Document | RecursivePartial<Document>)[];
Expand Down Expand Up @@ -102,6 +105,7 @@ export function createFoundationSimulationServer<
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
let simulationStore = createSimulationStore(extendStore);
app.use(delayMiddleware(delayResponses));

app.use((req, res, next) => {
// add each response to the internal log
Expand Down
53 changes: 53 additions & 0 deletions packages/foundation/src/middleware/delay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { Request, Response, NextFunction } from "express";

export function delayMiddleware(
delayResponses?: number | { minimum: number; maximum: number }
) {
const delayMin =
typeof delayResponses === "number"
? delayResponses
: delayResponses?.minimum;
const delayMax =
typeof delayResponses === "number" ? undefined : delayResponses?.maximum;

return async function delayHandler(
request: Request,
response: Response,
next: NextFunction
) {
if (delayMin || delayMax) {
let timeoutDuration = calculateTimeoutDuration(delayMin, delayMax);
await new Promise<void>((resolve) => {
let timeoutHandle: NodeJS.Timeout | undefined = undefined;

const done = () => {
if (timeoutHandle) {
clearTimeout(timeoutHandle);
}
resolve();
};

timeoutHandle = setTimeout(done, timeoutDuration);
});
}
next();
};
}

function calculateTimeoutDuration(
min: number | undefined,
max: number | undefined
): number {
if (max && !min) {
// sets the timeout at +/- 20% of configured max
return max * 0.8 + max * 0.4 * Math.random();
} else if (min && !max) {
// sets the timeout at +/- 20% of configured max
return min * 0.8 + min * 0.4 * Math.random();
} else if (max && min) {
const timeoutRange = max - min;
return min + timeoutRange * Math.random();
}

return 0;
}

0 comments on commit 8f46cd4

Please sign in to comment.