0
# Application Testing
1
2
Create full NestJS applications and microservices from test modules for end-to-end testing scenarios. This capability allows developers to test complete application behavior, including HTTP endpoints, WebSocket connections, and microservice communication.
3
4
## Capabilities
5
6
### NestJS Application Creation
7
8
Create full HTTP applications from testing modules for integration and end-to-end testing.
9
10
```typescript { .api }
11
class TestingModule extends NestApplicationContext {
12
/**
13
* Create a NestJS HTTP application with default Express adapter
14
* @param options - Optional application configuration
15
* @returns NestJS application instance
16
*/
17
createNestApplication<T extends INestApplication = INestApplication>(
18
options?: NestApplicationOptions
19
): T;
20
21
/**
22
* Create a NestJS HTTP application with custom HTTP adapter
23
* @param httpAdapter - Custom HTTP server or adapter
24
* @param options - Optional application configuration
25
* @returns NestJS application instance
26
*/
27
createNestApplication<T extends INestApplication = INestApplication>(
28
httpAdapter: HttpServer | AbstractHttpAdapter,
29
options?: NestApplicationOptions
30
): T;
31
}
32
```
33
34
**Usage Examples:**
35
36
```typescript
37
import { Test, TestingModule } from "@nestjs/testing";
38
import { INestApplication } from "@nestjs/common";
39
import * as request from "supertest";
40
import { AppModule } from "./app.module";
41
42
describe("Application E2E Testing", () => {
43
let app: INestApplication;
44
let module: TestingModule;
45
46
beforeAll(async () => {
47
module = await Test.createTestingModule({
48
imports: [AppModule],
49
}).compile();
50
51
app = module.createNestApplication();
52
await app.init();
53
});
54
55
afterAll(async () => {
56
await app.close();
57
await module.close();
58
});
59
60
it("should handle GET /users", async () => {
61
const response = await request(app.getHttpServer())
62
.get("/users")
63
.expect(200);
64
65
expect(response.body).toBeInstanceOf(Array);
66
});
67
68
it("should handle POST /users", async () => {
69
const newUser = { name: "John Doe", email: "john@example.com" };
70
71
const response = await request(app.getHttpServer())
72
.post("/users")
73
.send(newUser)
74
.expect(201);
75
76
expect(response.body.id).toBeDefined();
77
});
78
});
79
```
80
81
### Custom HTTP Adapter
82
83
Use custom HTTP adapters for specific testing scenarios:
84
85
```typescript
86
import { FastifyAdapter } from "@nestjs/platform-fastify";
87
import { ExpressAdapter } from "@nestjs/platform-express";
88
import * as express from "express";
89
90
// Using Fastify adapter
91
const fastifyModule = await Test.createTestingModule({
92
imports: [AppModule],
93
}).compile();
94
95
const fastifyApp = fastifyModule.createNestApplication(
96
new FastifyAdapter()
97
);
98
99
await fastifyApp.init();
100
await fastifyApp.getHttpAdapter().getInstance().ready();
101
102
// Using custom Express instance
103
const expressServer = express();
104
const expressModule = await Test.createTestingModule({
105
imports: [AppModule],
106
}).compile();
107
108
const expressApp = expressModule.createNestApplication(
109
new ExpressAdapter(expressServer)
110
);
111
112
await expressApp.init();
113
114
// Testing with the custom server
115
const response = await request(expressServer)
116
.get("/health")
117
.expect(200);
118
```
119
120
### Application Configuration
121
122
Configure applications with specific options for testing:
123
124
```typescript
125
import { ValidationPipe, Logger } from "@nestjs/common";
126
127
const module = await Test.createTestingModule({
128
imports: [AppModule],
129
}).compile();
130
131
const app = module.createNestApplication({
132
logger: false, // Disable logging for tests
133
cors: true, // Enable CORS for testing
134
bodyParser: true,
135
});
136
137
// Configure global pipes, filters, interceptors
138
app.useGlobalPipes(new ValidationPipe({
139
transform: true,
140
whitelist: true,
141
}));
142
143
// Configure custom headers or middleware
144
app.use((req, res, next) => {
145
res.setHeader("X-Test-Mode", "true");
146
next();
147
});
148
149
await app.init();
150
```
151
152
### Microservice Creation
153
154
Create microservices for testing distributed system scenarios:
155
156
```typescript { .api }
157
class TestingModule extends NestApplicationContext {
158
/**
159
* Create a NestJS microservice instance
160
* @param options - Microservice configuration including transport and options
161
* @returns NestJS microservice instance
162
*/
163
createNestMicroservice<T extends object>(
164
options: NestMicroserviceOptions & T
165
): INestMicroservice;
166
}
167
```
168
169
**Usage Examples:**
170
171
```typescript
172
import { Test, TestingModule } from "@nestjs/testing";
173
import { INestMicroservice, Transport } from "@nestjs/microservices";
174
import { MicroserviceModule } from "./microservice.module";
175
176
describe("Microservice Testing", () => {
177
let microservice: INestMicroservice;
178
let module: TestingModule;
179
180
beforeAll(async () => {
181
module = await Test.createTestingModule({
182
imports: [MicroserviceModule],
183
}).compile();
184
185
microservice = module.createNestMicroservice({
186
transport: Transport.TCP,
187
options: {
188
port: 8877,
189
},
190
});
191
192
await microservice.listen();
193
});
194
195
afterAll(async () => {
196
await microservice.close();
197
await module.close();
198
});
199
200
it("should process messages", async () => {
201
// Test microservice message handling
202
const result = await microservice
203
.send({ cmd: "get_user" }, { id: 1 })
204
.toPromise();
205
206
expect(result).toBeDefined();
207
});
208
});
209
```
210
211
### Redis Microservice Testing
212
213
```typescript
214
// Redis microservice testing
215
const redisModule = await Test.createTestingModule({
216
imports: [RedisModule],
217
}).compile();
218
219
const redisMicroservice = redisModule.createNestMicroservice({
220
transport: Transport.REDIS,
221
options: {
222
host: "localhost",
223
port: 6379,
224
},
225
});
226
227
await redisMicroservice.listen();
228
229
// Test Redis pub/sub patterns
230
```
231
232
### RMQ Microservice Testing
233
234
```typescript
235
// RabbitMQ microservice testing
236
const rmqModule = await Test.createTestingModule({
237
imports: [RmqModule],
238
}).compile();
239
240
const rmqMicroservice = rmqModule.createNestMicroservice({
241
transport: Transport.RMQ,
242
options: {
243
urls: ["amqp://localhost:5672"],
244
queue: "test_queue",
245
queueOptions: {
246
durable: false,
247
},
248
},
249
});
250
251
await rmqMicroservice.listen();
252
```
253
254
### WebSocket Testing
255
256
Test WebSocket gateways and real-time functionality:
257
258
```typescript
259
import { Test } from "@nestjs/testing";
260
import { INestApplication } from "@nestjs/common";
261
import { Socket, io } from "socket.io-client";
262
import { ChatModule } from "./chat.module";
263
264
describe("WebSocket Gateway", () => {
265
let app: INestApplication;
266
let client: Socket;
267
268
beforeAll(async () => {
269
const module = await Test.createTestingModule({
270
imports: [ChatModule],
271
}).compile();
272
273
app = module.createNestApplication();
274
await app.init();
275
await app.listen(3001);
276
277
client = io("http://localhost:3001");
278
});
279
280
afterAll(async () => {
281
client.close();
282
await app.close();
283
});
284
285
it("should handle message events", (done) => {
286
client.emit("message", { text: "Hello World" });
287
288
client.on("message", (data) => {
289
expect(data.text).toBe("Hello World");
290
done();
291
});
292
});
293
});
294
```
295
296
### GraphQL Testing
297
298
Test GraphQL APIs with schema validation:
299
300
```typescript
301
import { Test } from "@nestjs/testing";
302
import { GraphQLModule } from "@nestjs/graphql";
303
import * as request from "supertest";
304
305
describe("GraphQL API", () => {
306
let app: INestApplication;
307
308
beforeAll(async () => {
309
const module = await Test.createTestingModule({
310
imports: [
311
GraphQLModule.forRoot({
312
autoSchemaFile: true,
313
playground: false,
314
}),
315
UsersModule,
316
],
317
}).compile();
318
319
app = module.createNestApplication();
320
await app.init();
321
});
322
323
it("should execute GraphQL queries", async () => {
324
const query = `
325
query {
326
users {
327
id
328
name
329
330
}
331
}
332
`;
333
334
const response = await request(app.getHttpServer())
335
.post("/graphql")
336
.send({ query })
337
.expect(200);
338
339
expect(response.body.data.users).toBeInstanceOf(Array);
340
});
341
342
it("should handle GraphQL mutations", async () => {
343
const mutation = `
344
mutation {
345
createUser(input: { name: "John", email: "john@example.com" }) {
346
id
347
name
348
349
}
350
}
351
`;
352
353
const response = await request(app.getHttpServer())
354
.post("/graphql")
355
.send({ query: mutation })
356
.expect(200);
357
358
expect(response.body.data.createUser.id).toBeDefined();
359
});
360
});
361
```
362
363
### Application Lifecycle Management
364
365
Handle application startup and shutdown properly in tests:
366
367
```typescript
368
describe("Application Lifecycle", () => {
369
let app: INestApplication;
370
371
beforeEach(async () => {
372
const module = await Test.createTestingModule({
373
imports: [AppModule],
374
}).compile();
375
376
app = module.createNestApplication();
377
378
// Enable shutdown hooks for graceful shutdown
379
app.enableShutdownHooks();
380
381
await app.init();
382
});
383
384
afterEach(async () => {
385
// Ensure proper cleanup
386
await app?.close();
387
});
388
389
it("should handle graceful shutdown", async () => {
390
await app.listen(3002);
391
392
// Simulate shutdown signal
393
process.emit("SIGTERM");
394
395
// Application should close gracefully
396
await new Promise((resolve) => setTimeout(resolve, 1000));
397
});
398
});
399
```
400
401
### Error Handling in Applications
402
403
Test error handling and exception filters:
404
405
```typescript
406
import { ExceptionFilter, ArgumentsHost, Catch } from "@nestjs/common";
407
408
@Catch()
409
class TestExceptionFilter implements ExceptionFilter {
410
catch(exception: any, host: ArgumentsHost) {
411
const response = host.switchToHttp().getResponse();
412
response.status(500).json({
413
error: "Test error",
414
message: exception.message,
415
});
416
}
417
}
418
419
describe("Error Handling", () => {
420
let app: INestApplication;
421
422
beforeAll(async () => {
423
const module = await Test.createTestingModule({
424
imports: [AppModule],
425
}).compile();
426
427
app = module.createNestApplication();
428
app.useGlobalFilters(new TestExceptionFilter());
429
430
await app.init();
431
});
432
433
it("should handle application errors", async () => {
434
const response = await request(app.getHttpServer())
435
.get("/error-endpoint")
436
.expect(500);
437
438
expect(response.body.error).toBe("Test error");
439
});
440
});
441
```
442
443
## Types
444
445
```typescript { .api }
446
import {
447
INestApplication,
448
INestMicroservice,
449
NestApplicationOptions,
450
HttpServer,
451
} from "@nestjs/common";
452
import { AbstractHttpAdapter } from "@nestjs/core";
453
import { NestMicroserviceOptions } from "@nestjs/common/interfaces/microservices/nest-microservice-options.interface";
454
455
interface NestApplicationOptions {
456
logger?: LoggerService | LogLevel[] | false;
457
cors?: boolean | CorsOptions;
458
bodyParser?: boolean;
459
httpsOptions?: HttpsOptions;
460
rawBody?: boolean;
461
defaultGlobalPrefix?: string;
462
snapshot?: boolean;
463
preview?: boolean;
464
}
465
466
interface NestMicroserviceOptions {
467
transport?: Transport;
468
options?: any;
469
logger?: LoggerService | LogLevel[] | false;
470
snapshot?: boolean;
471
preview?: boolean;
472
}
473
```