Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ A simple HTTP server that can be used to mock HTTP responses for testing purpose
* Auto detect the port that is not in use
* Maintained and updated regularly!

# Table of Contents
- [Deploy via Docker](#deploy-via-docker)
- [Deploy via Docker Compose](#deploy-via-docker-compose)
- [Deploy via NodeJS](#deploy-via-nodejs)
- [Response Injection (Tap Feature)](#response-injection-tap-feature)
- [Rate Limiting](#rate-limiting)
- [Logging](#logging)
- [API Reference](#api-reference)
- [About mockhttp.org](#about-mockhttporg)
- [Contributing](#contributing)
- [License](#license)

# Deploy via Docker
```bash
docker run -d -p 3000:3000 jaredwray/mockhttp
Expand Down Expand Up @@ -405,6 +417,26 @@ await mock.start(); // Restarts with new settings

For the complete list of options, see the [@fastify/rate-limit documentation](https://github.com/fastify/fastify-rate-limit#options).

# Logging

MockHttp uses [Pino](https://github.com/pinojs/pino) for logging via Fastify's built-in logger. Logging is **enabled by default** but can be disabled when needed.

## Disabling Logging

```javascript
import { MockHttp } from '@jaredwray/mockhttp';

const mock = new MockHttp({ logging: false });
await mock.start();
// Server runs silently without any log output
```

You can also disable logging via the `LOGGING` environment variable:

```bash
LOGGING=false node your-app.js
```

# API Reference

## MockHttp Class
Expand All @@ -423,6 +455,7 @@ new MockHttp(options?)
- `helmet?`: boolean - Use Helmet for security headers (default: true)
- `apiDocs?`: boolean - Enable Swagger API documentation (default: true)
- `rateLimit?`: RateLimitPluginOptions - Configure rate limiting (default: 1000 req/min, localhost excluded)
- `logging?`: boolean - Enable logging (default: true)
- `httpBin?`: HttpBinOptions - Configure which httpbin routes to enable
- `httpMethods?`: boolean - Enable HTTP method routes (default: true)
- `redirects?`: boolean - Enable redirect routes (default: true)
Expand All @@ -443,6 +476,7 @@ new MockHttp(options?)
- `autoDetectPort`: boolean - Get/set auto-detect port behavior
- `helmet`: boolean - Get/set Helmet security headers
- `apiDocs`: boolean - Get/set API documentation
- `logging`: boolean - Get/set logging enabled state
- `rateLimit`: RateLimitPluginOptions | undefined - Get/set rate limiting options
- `httpBin`: HttpBinOptions - Get/set httpbin route options
- `server`: FastifyInstance - Get/set the Fastify server instance
Expand Down
30 changes: 17 additions & 13 deletions src/fastify-config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
export const fastifyConfig = {
logger: {
transport: {
target: "pino-pretty",
options: {
colorize: true,
translateTime: true,
ignore: "pid,hostname",
singleLine: true,
},
},
},
};
export function getFastifyConfig(logging = true) {
return {
logger: logging
? {
transport: {
target: "pino-pretty",
options: {
colorize: true,
translateTime: true,
ignore: "pid,hostname",
singleLine: true,
},
},
}
: false,
};
}
5 changes: 5 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ export const start = async () => {
mockHttp.host = process.env.HOST;
}

/* v8 ignore next -- @preserve */
if (process.env.LOGGING === "false") {
mockHttp.logging = false;
}

await mockHttp.start();

return mockHttp;
Expand Down
29 changes: 27 additions & 2 deletions src/mock-http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { fastifySwagger } from "@fastify/swagger";
import { detect } from "detect-port";
import Fastify, { type FastifyInstance } from "fastify";
import { Hookified, type HookifiedOptions } from "hookified";
import { fastifyConfig } from "./fastify-config.js";
import { getFastifyConfig } from "./fastify-config.js";
import { anythingRoute } from "./routes/anything/index.js";
import {
basicAuthRoute,
Expand Down Expand Up @@ -100,6 +100,10 @@ export type MockHttpOptions = {
* Hookified options.
*/
hookOptions?: HookifiedOptions;
/**
* Whether to enable logging. Defaults to true.
*/
logging?: boolean;
};

export class MockHttp extends Hookified {
Expand All @@ -108,6 +112,7 @@ export class MockHttp extends Hookified {
private _autoDetectPort = true;
private _helmet = true;
private _apiDocs = true;
private _logging = true;
private _httpBin: HttpBinOptions = {
httpMethods: true,
redirects: true,
Expand Down Expand Up @@ -160,6 +165,10 @@ export class MockHttp extends Hookified {
this._rateLimit = options.rateLimit as RateLimitPluginOptions;
}
}

if (options?.logging !== undefined) {
this._logging = options.logging;
}
}

/**
Expand Down Expand Up @@ -244,6 +253,22 @@ export class MockHttp extends Hookified {
this._apiDocs = apiDocs;
}

/**
* Whether to enable logging. Defaults to true.
* @default true
*/
public get logging(): boolean {
return this._logging;
}

/**
* Whether to enable logging. Defaults to true.
* @default true
*/
public set logging(logging: boolean) {
this._logging = logging;
}

/**
* HTTP Bin options. Defaults to all enabled.
*/
Expand Down Expand Up @@ -316,7 +341,7 @@ export class MockHttp extends Hookified {
await this._server.close();
}

this._server = Fastify(fastifyConfig);
this._server = Fastify(getFastifyConfig(this._logging));

// Register injection hook to intercept requests
this._server.addHook("onRequest", async (request, reply) => {
Expand Down
38 changes: 38 additions & 0 deletions test/mock-http.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,44 @@ describe("MockHttp", () => {
});
});

describe("logging", () => {
test("should be enabled by default", () => {
const mock = new MockHttp();
expect(mock.logging).toBe(true);
});

test("should be able to disable logging via options", () => {
const mock = new MockHttp({ logging: false });
expect(mock.logging).toBe(false);
});

test("should be able to enable logging via options", () => {
const mock = new MockHttp({ logging: true });
expect(mock.logging).toBe(true);
});

test("should be able to set logging via setter", () => {
const mock = new MockHttp();
expect(mock.logging).toBe(true);

mock.logging = false;
expect(mock.logging).toBe(false);

mock.logging = true;
expect(mock.logging).toBe(true);
});

test("should start server with logging disabled", async () => {
const mock = new MockHttp({ logging: false });
await mock.start();

// Server should start successfully with logging disabled
expect(mock.server).toBeDefined();

await mock.close();
});
});

describe("rate limiting", () => {
test("should be enabled by default with 1000 requests per minute and localhost excluded", () => {
const mock = new MockHttp();
Expand Down
Loading