Call the class's main method directly. Interceptors and pipes are classes with one main method, so you don't need an HTTP app.
The interceptor. Pass it a stubbed ExecutionContext and a CallHandler. The CallHandler stands for the route handler. Its handle() returns an observable (an RxJS stream of values):const out = interceptor.intercept(ctx, { handle: () => of({ id: 1 }) }).
Then read the result: expect(await lastValueFrom(out)).toEqual({ data: { id: 1 } }).
To test error mapping, return throwError(() => new Error('x')) from handle(). Then assert that the observable errors with the mapped exception.
The pipe. Create new ValidationPipe({ whitelist: true }). Call transform(value, { type: 'body', metatype: CreateUserDto }). The metatype tells the pipe which DTO class holds the rules. Assert two things:
- Invalid input rejects with
BadRequestException. - Valid input comes back as expected.
These tests are fast. An e2e (end-to-end) test still checks that the pipe and the interceptor are registered.
- Call intercept() with a stub CallHandler that returns of(value).
- Read the result with lastValueFrom, and test errors with throwError.
- Call ValidationPipe.transform with metatype set to the DTO class.
- Invalid input rejects with BadRequestException.
- NestJS interceptors (https://docs.nestjs.com/interceptors)docs.nestjs.com
- NestJS pipes (https://docs.nestjs.com/pipes)docs.nestjs.com