A collection of test utilities specifically designed for LoopBack 4 applications and TypeScript testing
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Async HTTP/HTTPS request utilities and server configuration helpers for test environments.
Async wrappers for making HTTP and HTTPS requests.
/**
* Async wrapper for making HTTP GET requests
* @param urlString - URL to request
* @param agent - Optional HTTP agent for connection pooling
* @returns Promise resolving to IncomingMessage response
*/
function httpGetAsync(
urlString: string,
agent?: http.Agent
): Promise<IncomingMessage>;
/**
* Async wrapper for making HTTPS GET requests
* Uses a default agent that accepts self-signed certificates
* @param urlString - HTTPS URL to request
* @param agent - Optional HTTPS agent, defaults to permissive agent
* @returns Promise resolving to IncomingMessage response
*/
function httpsGetAsync(
urlString: string,
agent?: https.Agent
): Promise<IncomingMessage>;Usage Examples:
import { httpGetAsync, httpsGetAsync, expect } from "@loopback/testlab";
import http from "http";
import https from "https";
// Basic HTTP request
const response = await httpGetAsync("http://localhost:3000/api/status");
expect(response.statusCode).to.equal(200);
// Read response body
let body = "";
response.on("data", (chunk) => {
body += chunk;
});
response.on("end", () => {
const data = JSON.parse(body);
expect(data.status).to.equal("ok");
});
// HTTPS request (accepts self-signed certificates by default)
const httpsResponse = await httpsGetAsync("https://localhost:3443/secure-endpoint");
expect(httpsResponse.statusCode).to.equal(200);
// Custom HTTP agent for connection pooling
const customAgent = new http.Agent({
keepAlive: true,
maxSockets: 5
});
const pooledResponse = await httpGetAsync("http://api.example.com/data", customAgent);
// Custom HTTPS agent with specific SSL options
const customHttpsAgent = new https.Agent({
rejectUnauthorized: true, // Require valid certificates
keepAlive: true
});
const secureResponse = await httpsGetAsync("https://api.example.com/secure", customHttpsAgent);Helper functions for creating HTTP/HTTPS server configurations suitable for testing.
/**
* Create an HTTP-server configuration that works well in test environments
* - Assigns ephemeral port (port 0)
* - Uses IPv4 localhost (127.0.0.1) to avoid IPv6 issues
* - Provides default TLS configuration for HTTPS
* @param customConfig - Additional configuration options
* @returns Complete server configuration with host and port
*/
function givenHttpServerConfig<T extends HttpOptions | HttpsOptions>(
customConfig?: T
): HostPort & T;
/**
* HTTP server configuration options
*/
interface HttpOptions extends ListenOptions {
protocol?: 'http';
}
/**
* HTTPS server configuration options
*/
interface HttpsOptions extends ListenOptions, HttpsServerOptions {
protocol: 'https';
}
/**
* Interface requiring host and port properties
*/
interface HostPort {
host: string;
port: number;
}Usage Examples:
import { givenHttpServerConfig, expect } from "@loopback/testlab";
import http from "http";
import https from "https";
// Basic HTTP server configuration
const httpConfig = givenHttpServerConfig();
expect(httpConfig.host).to.equal("127.0.0.1");
expect(httpConfig.port).to.equal(0); // Ephemeral port
// Create HTTP server with test config
const httpServer = http.createServer((req, res) => {
res.writeHead(200, {"Content-Type": "application/json"});
res.end(JSON.stringify({message: "Hello"}));
});
httpServer.listen(httpConfig, () => {
const address = httpServer.address() as any;
console.log(`HTTP server listening on ${address.address}:${address.port}`);
});
// HTTPS server configuration with defaults
const httpsConfig = givenHttpServerConfig({protocol: "https"});
expect(httpsConfig.protocol).to.equal("https");
expect(httpsConfig.host).to.equal("127.0.0.1");
expect(httpsConfig.port).to.equal(0);
expect(httpsConfig).to.have.property("key"); // Default TLS key
expect(httpsConfig).to.have.property("cert"); // Default TLS cert
// Create HTTPS server with test config
const httpsServer = https.createServer(httpsConfig, (req, res) => {
res.writeHead(200, {"Content-Type": "application/json"});
res.end(JSON.stringify({secure: true}));
});
httpsServer.listen(httpsConfig, () => {
const address = httpsServer.address() as any;
console.log(`HTTPS server listening on ${address.address}:${address.port}`);
});
// Custom HTTP configuration
const customHttpConfig = givenHttpServerConfig({
host: "0.0.0.0", // Accept from any interface
port: 8080 // Specific port
});
// Custom HTTPS configuration with own certificates
const customHttpsConfig = givenHttpServerConfig({
protocol: "https",
key: fs.readFileSync("/path/to/private-key.pem"),
cert: fs.readFileSync("/path/to/certificate.pem"),
host: "localhost",
port: 8443
});HTTP error logging utilities for debugging test failures.
/**
* Creates a logger that logs HTTP errors when status code is unexpected
* @param expectedStatusCode - Status code that should not be logged
* @returns Error logging function
*/
function createUnexpectedHttpErrorLogger(
expectedStatusCode?: number
): LogError;
/**
* Error logging function type
*/
type LogError = (err: Error, statusCode: number, request: Request) => void;Usage Examples:
import { createUnexpectedHttpErrorLogger, expect } from "@loopback/testlab";
import { Request } from "express";
// Create logger that ignores 404 errors
const logger = createUnexpectedHttpErrorLogger(404);
// Simulate different error scenarios
const mockRequest = {method: "GET", url: "/api/test"} as Request;
// This will be logged (unexpected error)
logger(new Error("Database connection failed"), 500, mockRequest);
// Output: "Unhandled error in GET /api/test: 500 Error: Database connection failed..."
// This will NOT be logged (expected 404)
logger(new Error("Not found"), 404, mockRequest);
// No output
// Logger for successful requests (ignore 200)
const successLogger = createUnexpectedHttpErrorLogger(200);
// This will be logged (unexpected error)
successLogger(new Error("Validation failed"), 400, mockRequest);
// This will NOT be logged (expected success)
successLogger(new Error("Should not happen"), 200, mockRequest);
// Use in Express error handler
function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) {
const logger = createUnexpectedHttpErrorLogger();
logger(err, res.statusCode || 500, req);
res.status(500).json({error: "Internal server error"});
}Complete examples of using HTTP utilities in test scenarios.
Usage Examples:
import {
givenHttpServerConfig,
httpGetAsync,
httpsGetAsync,
expect
} from "@loopback/testlab";
import http from "http";
import https from "https";
// Test HTTP server lifecycle
describe("HTTP Server Tests", () => {
let server: http.Server;
let serverUrl: string;
beforeEach(async () => {
const config = givenHttpServerConfig();
server = http.createServer((req, res) => {
if (req.url === "/ping") {
res.writeHead(200, {"Content-Type": "application/json"});
res.end(JSON.stringify({pong: true}));
} else {
res.writeHead(404);
res.end("Not found");
}
});
await new Promise<void>((resolve) => {
server.listen(config, () => {
const address = server.address() as any;
serverUrl = `http://${address.address}:${address.port}`;
resolve();
});
});
});
afterEach(async () => {
await new Promise<void>((resolve) => {
server.close(() => resolve());
});
});
it("should respond to ping", async () => {
const response = await httpGetAsync(`${serverUrl}/ping`);
expect(response.statusCode).to.equal(200);
let body = "";
response.on("data", chunk => body += chunk);
await new Promise(resolve => response.on("end", resolve));
expect(JSON.parse(body)).to.eql({pong: true});
});
it("should return 404 for unknown routes", async () => {
const response = await httpGetAsync(`${serverUrl}/unknown`);
expect(response.statusCode).to.equal(404);
});
});
// Test HTTPS server with custom certificates
describe("HTTPS Server Tests", () => {
let server: https.Server;
let serverUrl: string;
beforeEach(async () => {
const config = givenHttpServerConfig({protocol: "https"});
server = https.createServer(config, (req, res) => {
res.writeHead(200, {"Content-Type": "application/json"});
res.end(JSON.stringify({secure: true, url: req.url}));
});
await new Promise<void>((resolve) => {
server.listen(config, () => {
const address = server.address() as any;
serverUrl = `https://${address.address}:${address.port}`;
resolve();
});
});
});
afterEach(async () => {
await new Promise<void>((resolve) => {
server.close(() => resolve());
});
});
it("should handle HTTPS requests", async () => {
// Uses default permissive agent for self-signed certificates
const response = await httpsGetAsync(`${serverUrl}/secure`);
expect(response.statusCode).to.equal(200);
let body = "";
response.on("data", chunk => body += chunk);
await new Promise(resolve => response.on("end", resolve));
const data = JSON.parse(body);
expect(data.secure).to.be.true();
expect(data.url).to.equal("/secure");
});
});
// Test external API integration
describe("External API Tests", () => {
it("should handle API responses", async () => {
// Mock external service (you would replace with actual service in tests)
const mockServer = http.createServer((req, res) => {
res.writeHead(200, {"Content-Type": "application/json"});
res.end(JSON.stringify({data: "mock response"}));
});
const config = givenHttpServerConfig();
await new Promise<void>(resolve => mockServer.listen(config, resolve));
const address = mockServer.address() as any;
const mockUrl = `http://${address.address}:${address.port}`;
// Test API call
const response = await httpGetAsync(`${mockUrl}/api/data`);
expect(response.statusCode).to.equal(200);
await new Promise<void>(resolve => mockServer.close(() => resolve()));
});
});