0
# HTTP Client Testing
1
2
SuperTest integration and utilities for creating HTTP clients for testing REST applications and request handlers.
3
4
## Capabilities
5
6
### SuperTest Integration
7
8
Complete SuperTest library re-export for HTTP testing.
9
10
```typescript { .api }
11
/**
12
* SuperTest library for HTTP endpoint testing
13
* Provides fluent API for making HTTP requests and assertions
14
*/
15
const supertest: typeof import("supertest");
16
17
/**
18
* SuperTest client type for making HTTP requests
19
*/
20
type Client = supertest.SuperTest<supertest.Test>;
21
```
22
23
**Usage Examples:**
24
25
```typescript
26
import { supertest } from "@loopback/testlab";
27
import express from "express";
28
29
const app = express();
30
app.get("/users", (req, res) => res.json([{id: 1, name: "Alice"}]));
31
32
// Direct SuperTest usage
33
await supertest(app)
34
.get("/users")
35
.expect(200)
36
.expect("Content-Type", /json/)
37
.expect([{id: 1, name: "Alice"}]);
38
```
39
40
### Client for Handler Function
41
42
Creates a SuperTest client for testing HTTP handler functions without starting a server.
43
44
```typescript { .api }
45
/**
46
* Create a SuperTest client connected to an HTTP server listening
47
* on an ephemeral port and calling handler to handle incoming requests
48
* @param handler - Request handler function
49
* @returns SuperTest client for making requests
50
*/
51
function createClientForHandler(
52
handler: (req: http.IncomingMessage, res: http.ServerResponse) => void
53
): Client;
54
```
55
56
**Usage Examples:**
57
58
```typescript
59
import { createClientForHandler, expect } from "@loopback/testlab";
60
import { IncomingMessage, ServerResponse } from "http";
61
62
// Simple handler
63
function simpleHandler(req: IncomingMessage, res: ServerResponse) {
64
res.writeHead(200, {"Content-Type": "application/json"});
65
res.end(JSON.stringify({message: "Hello World"}));
66
}
67
68
// Create client and test
69
const client = createClientForHandler(simpleHandler);
70
71
await client
72
.get("/")
73
.expect(200)
74
.expect("Content-Type", /json/)
75
.expect({message: "Hello World"});
76
77
// Handler with routing logic
78
function routingHandler(req: IncomingMessage, res: ServerResponse) {
79
const url = req.url;
80
res.writeHead(200, {"Content-Type": "application/json"});
81
82
if (url === "/users") {
83
res.end(JSON.stringify([{id: 1, name: "Alice"}]));
84
} else if (url === "/status") {
85
res.end(JSON.stringify({status: "ok"}));
86
} else {
87
res.writeHead(404);
88
res.end(JSON.stringify({error: "Not found"}));
89
}
90
}
91
92
const routingClient = createClientForHandler(routingHandler);
93
94
await routingClient.get("/users").expect(200).expect([{id: 1, name: "Alice"}]);
95
await routingClient.get("/status").expect(200).expect({status: "ok"});
96
await routingClient.get("/invalid").expect(404);
97
```
98
99
### Client for REST Application
100
101
Creates a SuperTest client for testing running LoopBack REST applications.
102
103
```typescript { .api }
104
/**
105
* Create a SuperTest client for a running RestApplication instance
106
* The app must be running and listening on a port
107
* @param app - A running RestApplication instance
108
* @returns SuperTest client for the application
109
* @throws Error if the application is not listening
110
*/
111
function createRestAppClient(app: RestApplicationLike): Client;
112
113
/**
114
* Interface for LoopBack-like REST applications
115
*/
116
interface RestApplicationLike {
117
restServer: RestServerLike;
118
}
119
120
/**
121
* Interface for LoopBack-like REST servers
122
*/
123
interface RestServerLike {
124
url?: string;
125
rootUrl?: string;
126
}
127
```
128
129
**Usage Examples:**
130
131
```typescript
132
import { createRestAppClient, expect } from "@loopback/testlab";
133
134
// Assuming you have a LoopBack application
135
class MyApplication {
136
restServer = {
137
url: "http://localhost:3000",
138
rootUrl: "http://localhost:3000"
139
};
140
}
141
142
const app = new MyApplication();
143
144
// Create client for running application
145
const client = createRestAppClient(app);
146
147
// Test application endpoints
148
await client
149
.get("/ping")
150
.expect(200)
151
.expect({greeting: "Hello from LoopBack"});
152
153
await client
154
.post("/users")
155
.send({name: "Bob", email: "bob@example.com"})
156
.expect(201)
157
.expect((res) => {
158
expect(res.body).to.have.property("id");
159
expect(res.body.name).to.equal("Bob");
160
});
161
162
// Testing with different HTTP methods
163
await client.get("/users").expect(200);
164
await client.put("/users/1").send({name: "Updated"}).expect(200);
165
await client.delete("/users/1").expect(204);
166
```
167
168
### SuperTest Test Interface
169
170
Common SuperTest methods and assertions for HTTP testing.
171
172
```typescript { .api }
173
// SuperTest Test interface (partial - key methods)
174
interface Test {
175
// HTTP methods
176
get(url: string): Test;
177
post(url: string): Test;
178
put(url: string): Test;
179
patch(url: string): Test;
180
delete(url: string): Test;
181
head(url: string): Test;
182
options(url: string): Test;
183
184
// Request configuration
185
send(data: any): Test;
186
query(params: object | string): Test;
187
set(field: string, value: string): Test;
188
set(fields: object): Test;
189
auth(user: string, pass: string): Test;
190
attach(field: string, file: string, filename?: string): Test;
191
field(name: string, value: string): Test;
192
193
// Response expectations
194
expect(status: number): Test;
195
expect(status: number, callback?: (err: Error, res: Response) => void): Test;
196
expect(body: any): Test;
197
expect(field: string, value: string | RegExp): Test;
198
expect(callback: (res: Response) => void): Test;
199
200
// Execution
201
end(callback: (err: Error, res: Response) => void): void;
202
then(resolve: (res: Response) => void, reject?: (err: Error) => void): Promise<Response>;
203
}
204
```
205
206
**Usage Examples:**
207
208
```typescript
209
import { createClientForHandler } from "@loopback/testlab";
210
211
const client = createClientForHandler(handler);
212
213
// Method chaining
214
await client
215
.post("/api/users")
216
.set("Content-Type", "application/json")
217
.set("Authorization", "Bearer token123")
218
.send({name: "Charlie", email: "charlie@example.com"})
219
.expect(201)
220
.expect("Content-Type", /json/)
221
.expect((res) => {
222
expect(res.body).to.have.property("id");
223
expect(res.body.name).to.equal("Charlie");
224
});
225
226
// Query parameters
227
await client
228
.get("/api/users")
229
.query({limit: 10, offset: 0})
230
.expect(200);
231
232
// File uploads
233
await client
234
.post("/api/upload")
235
.attach("file", "/path/to/file.jpg")
236
.field("description", "Profile picture")
237
.expect(200);
238
239
// Custom expectations
240
await client
241
.get("/api/status")
242
.expect((res) => {
243
expect(res.body.uptime).to.be.greaterThan(0);
244
expect(res.headers).to.have.property("x-api-version");
245
});
246
```
247
248
### Error Handling
249
250
Proper error handling patterns for HTTP client testing.
251
252
**Usage Examples:**
253
254
```typescript
255
import { createRestAppClient, expect } from "@loopback/testlab";
256
257
// Testing error responses
258
await client
259
.get("/api/nonexistent")
260
.expect(404)
261
.expect({error: "Resource not found"});
262
263
// Testing validation errors
264
await client
265
.post("/api/users")
266
.send({}) // Missing required fields
267
.expect(422)
268
.expect((res) => {
269
expect(res.body.error.details).to.be.an.Array();
270
});
271
272
// Testing authentication errors
273
await client
274
.get("/api/protected")
275
.expect(401)
276
.expect({error: "Unauthorized"});
277
278
// Handling client creation errors
279
try {
280
const nonRunningApp = { restServer: {} }; // No URL
281
const client = createRestAppClient(nonRunningApp);
282
} catch (error) {
283
expect(error.message).to.match(/not listening/);
284
}
285
```