///
import * as http from "http";
import * as https from "https";
import { AsyncQueue } from "./async";
/**
* An arbitrary set of header names and values.
*/
export interface TestHttpHeaders {
[key: string]: string;
}
/**
* Properties of an HTTP request recorded by [[TestHttpServer]].
*/
export interface TestHttpRequest {
/**
* The HTTP method, lowercased ("get").
*/
method: string;
/**
* The URL path ("/index.html").
*/
path: string;
/**
* The request headers.
*/
headers: TestHttpHeaders;
/**
* The request body, if any. Requests with a streamed body will be read in full before being handled.
*/
body?: string;
}
/**
* A function that provides a response for [[TestHttpServer]]. May be synchronous or async.
*/
export declare type TestHttpHandler = ((req: TestHttpRequest, res: http.ServerResponse) => void) | ((req: TestHttpRequest, res: http.ServerResponse) => Promise);
/**
* A wrapper for Node's HTTP server API that provides convenient semantics for test code.
*
* Do not use this for actual server applications, since its request matching logic is inefficient
* and its request queue can grow without limit.
*
* ```
* const server = await TestHttpServer.start();
*
* // simulate an endpoint
* server.forMethodAndPath('get', '/thing',
* TestHttpHandlers.respond(200, {}, 'hello'));
*
* // return 500 error for non-matching requests
* server.byDefault(TestHttpHandlers.respond(500));
*
* // ... do some HTTP requests to server.url
*
* const request = await server.nextRequest(); // retrieve the first request
* server.close();
* ```
*/
export declare class TestHttpServer {
/**
* Creates and starts a [[TestHttpServer]] instance.
*
* Note: in a non-TypeScript project that uses a transpiler, you may not be able to access this
* static method; if so, use the same method in [[TestHttpServers]] instead.
*
* @param options
* Any desired [[http.ServerOptions]].
* @param port
* A specific port to listen on; if omitted, it picks an available port.
*/
static start(options?: http.ServerOptions, port?: number): Promise;
/**
* Creates and starts a [[TestHttpServer]] instance that uses HTTPS, with a self-signed certificate.
*
* Note: in a non-TypeScript project that uses a transpiler, you may not be able to access this
* static method; if so, use the same method in [[TestHttpServers]] instead.
*
* @param options
* Any desired [[https.ServerOptions]] other than the certificate.
* @param port
* A specific port to listen on; if omitted, it picks an available port.
*/
static startSecure(options?: https.ServerOptions, port?: number): Promise;
/**
* Creates and starts a [[TestHttpServer]] instance that acts as an HTTP proxy.
*
* The server will only act as a proxy and will ignore any request handlers that you specify, but
* it still has the same properties as a regular [[TestHttpServer]], behaves the same in terms of
* dynamically choosing a port, and allows you to inspect received requests. The received
* requests will have a `path` property equal to either the full request URL or, if using a
* tunneling agent, the request URL minus the path.
*
* Note that the current implementation does not support proxying a request to an HTTPS URL.
*
* @param options
* Any desired [[http.ServerOptions]].
* @param port
* A specific port to listen on; if omitted, it picks an available port.
*/
static startProxy(options?: http.ServerOptions, port?: number): Promise;
/**
* Creates and starts a [[TestHttpServer]] instance that acts as a secure HTTP proxy with a
* self-signed certificate.
*
* This is the same as [[TestHttpServer.startProxy]], but the proxy server itself is secure.
* Note that the current implementation does not support proxying a request to an HTTPS URL
* (that is, when the target server is itself secure).
*
* @param options
* Any desired [[https.ServerOptions]] other than the certificate.
* @param port
* A specific port to listen on; if omitted, it picks an available port.
*/
static startSecureProxy(options?: https.ServerOptions, port?: number): Promise;
private static nextPort;
private static startSecureInternal;
/**
* The server's base URL ("http://localhost:8000").
*/
url: string;
/**
* The server's hostname (always "localhost" in this implementation).
*/
hostname: string;
/**
* The server's port.
*/
port: number;
/**
* The server's self-signed certificate, if it is a secure server.
*/
certificate?: string;
/**
* An [[AsyncQueue]] of all requests handled so far. Call `await server.requests.take()` to block
* untiil the server has handled a request.
*/
requests: AsyncQueue;
private realServer;
private responses;
private matchers;
private defaultHandler;
private secure;
private count;
private constructor();
/**
* Consumes the next received request, waiting until one is available.
*
* @returns
* A Promise that will be resolved with a [[TestHttpRequest]].
*/
nextRequest(): Promise;
/**
* Returns the total number of requests that have been received.
*
* @returns
* The number of requests so far.
*/
requestCount(): number;
/**
* Specifies a [[TestHttpHandler]] to use for all requests that are not otherwise matched.
*
* @param handler
* The request handler. This is normally created with a function like [[respond]].
* @returns
* The same server.
*/
byDefault(handler: TestHttpHandler): TestHttpServer;
/**
* Specifies a [[TestHttpHandler]] to use for requests with the specified method and path.
* This overrides any previous handler for the same method and path.
*
* @param method
* The HTTP method.
* @param path
* The request path.
* @handler
* The request handler. This is normally created with a function like [[respond]].
* @returns
* The same server.
*/
forMethodAndPath(method: string, path: string, handler: TestHttpHandler): TestHttpServer;
/**
* Stops the server.
*/
close(): void;
/**
* Stops the server and provides a Promise to indicate when it is completely stopped.
*/
closeAndWait(): Promise;
private startInstance;
private preprocessRequest;
}
/**
* Abstract class that provides the same static factory methods as [[TestHttpServer]].
*
* This is provided only because some JavaScript projects may have difficulty importing a class that
* has both a constructor and static methods (transpilers may copy the import in a way that preserves
* only the constructor function and not the static members). `TestHttpServers.start()` is exactly
* equivalent to `TestHttpServer.start()`.
*/
export declare abstract class TestHttpServers {
/**
* Creates and starts a [[TestHttpServer]] instance.
*
* @param options
* Any desired [[http.ServerOptions]].
* @param port
* A specific port to listen on; if omitted, it picks an available port.
*/
static start(options?: http.ServerOptions, port?: number): Promise;
/**
* Creates and starts a [[TestHttpServer]] instance that uses HTTPS, with a self-signed certificate.
*
* @param options
* Any desired [[https.ServerOptions]] other than the certificate.
* @param port
* A specific port to listen on; if omitted, it picks an available port.
*/
static startSecure(options?: https.ServerOptions, port?: number): Promise;
/**
* Creates and starts a [[TestHttpServer]] instance that acts as an HTTP proxy.
*
* The server will only act as a proxy and will ignore any request handlers that you specify, but
* it still has the same properties as a regular [[TestHttpServer]], behaves the same in terms of
* dynamically choosing a port, and allows you to inspect received requests. The received
* requests will have a `path` property equal to either the full request URL or, if using a
* tunneling agent, the request URL minus the path.
*
* Note that the current implementation does not support proxying a request to an HTTPS URL.
*
* @param options
* Any desired [[http.ServerOptions]].
* @param port
* A specific port to listen on; if omitted, it picks an available port.
*/
static startProxy(options?: http.ServerOptions, port?: number): Promise;
/**
* Creates and starts a [[TestHttpServer]] instance that acts as a secure HTTP proxy with a
* self-signed certificate.
*
* This is the same as [[TestHttpServers.startProxy]], but the proxy server itself is secure.
* Note that the current implementation does not support proxying a request to an HTTPS URL
* (that is, when the target server is itself secure).
*
* @param options
* Any desired [[https.ServerOptions]] other than the certificate.
* @param port
* A specific port to listen on; if omitted, it picks an available port.
*/
static startSecureProxy(options?: https.ServerOptions, port?: number): Promise;
}
/**
* Predefined implementations of [[TestHttpHandler]] for use with [[TestHttpServer]].
*/
export declare abstract class TestHttpHandlers {
/**
* Creates a [[TestHttpHandler]] that sends a simple response.
*
* ```
* server.forMethodAndPath("get", "/path", TestHttpHandlers.respond(500));
* server.forMethodAndPath("get", "/path",
* TestHttpHandlers.respond(200, { "content-type": "text/plain" }, "hi"));
* ```
*
* @param status
* The desired HTTP status.
* @param headers
* Response headers, if any.
* @param body
* Response body, if any.
* @returns
* A response handler.
*/
static respond(status: number, headers?: TestHttpHeaders, body?: string): TestHttpHandler;
/**
* Shortcut for creating a [[TestHttpHandler]] that sends a 200 response with JSON content.
*
* ```
* server.forMethodAndPath("get", "/path",
* TestHttpHandlers.respondJson({ message: "hi" }));
* ```
*
* @param serializableData
* A value of any type that will be converted to JSON.
* @returns
* A response handler.
*/
static respondJson(serializableData: any): TestHttpHandler;
/**
* Creates a [[TestHttpHandler]] that sends a chunked HTTP response, using an [[AsyncQueue]] as a pipe.
*
* ```
* const chunkQueue = new AsyncQueue();
* server.forMethodAndPath("get", "/path",
* TestHttpHandlers.chunkedStream(200, {}, chunkQueue));
* chunkQueue.add("a chunk of data");
* chunkQueue.add("another one");
* chunkQueue.close();
* ```
*
* @param status
* The desired HTTP status.
* @param headers
* Response headers, if any.
* @param chunkQueue
* An existing [[AsyncQueue]]. As you add chunks of response data to the queue, they will be consumed and
* sent. Call `close()` on the queue to end the response.
* @returns
* A response handler.
*/
static chunkedStream(status: number, headers: TestHttpHeaders, chunkQueue: AsyncQueue): TestHttpHandler;
/**
* Creates a [[TestHttpHandler]] that sends a streaming response in Server-Sent Events format, using
* an [[AsyncQueue]] as an event pipe.
*
* ```
* const eventQueue = new AsyncQueue();
* server.forMethodAndPath("get", "/path",
* TestHttpHandlers.sseStream(eventQueue));
* eventQueue.add({ type: "patch", data: { path: "/flags", key: "x" } });
* eventQueue.add({ comment: "" });
* eventQueue.close();
* ```
*
* @param eventQueue
* An existing [[AsyncQueue]]. As you add [[SSEItem]] objects to the queue, they will be consumed and
* sent. Call `close()` on the queue to end the response.
*/
static sseStream(eventQueue: AsyncQueue): TestHttpHandler;
/**
* Creates a [[TestHttpHandler]] that will cause the request to terminate with a network error, by
* closing the response socket prematurely.
*
* @returns
* A response handler.
*/
static networkError(): TestHttpHandler;
}
/**
* A data item or comment in a Server-Sent Events stream, for [[TestHttpHandlers.sseStream]].
*/
export interface SSEItem {
/**
* The event type ("event:" field).
*/
type?: string;
/**
* The event ID ("id:" field).
*/
id?: string;
/**
* The event data ("data:" field). This must be defined unless `comment` is provided.
*/
data?: string;
/**
* A comment string to be sent instead of an event (":" will be prepended).
*/
comment?: string;
}