如何测试NestJs响应拦截器

zed*_*ian 2 http interceptor typescript jestjs nestjs

我试图遵循这个线程,但我不断收到错误。

变换响应.interceptor.ts:

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { ApiResponseInterface } from '@walletxp/shared-interfaces';

@Injectable()
export class TransformResponseInterceptor<T>
  implements NestInterceptor<T, ApiResponseInterface<Record<string, unknown>>>
{
  intercept(context: ExecutionContext, next: CallHandler): Observable<ApiResponseInterface<Record<string, unknown>>> {
    return next.handle().pipe(map((data) => ({ success: true, data })));
  }
}

Run Code Online (Sandbox Code Playgroud)

对于它的测试,transform-response.interceptor.spec.ts:

import { TransformResponseInterceptor } from './transform-response.interceptor';
const interceptor = new TransformResponseInterceptor();

const executionContext: any = {
  switchToHttp: jest.fn().mockReturnThis(),
  getRequest: jest.fn().mockReturnThis(),
};

const callHandler = {
  handle: jest.fn(),
};

describe('ResponseInterceptor', () => {
  it('should be defined', () => {
    expect(interceptor).toBeDefined();
  });
  describe('#intercept', () => {
    it('t1', async () => {
      (executionContext.switchToHttp().getRequest as jest.Mock<any, any>).mockReturnValueOnce({
        body: { data: 'mocked data' },
      });
      callHandler.handle.mockResolvedValueOnce('next handle');
      const actualValue = await interceptor.intercept(executionContext, callHandler);
      expect(actualValue).toBe('next handle');
      expect(executionContext.switchToHttp().getRequest().body).toEqual({
        data: 'mocked data',
        addedAttribute: 'example',
      });
      expect(callHandler.handle).toBeCalledTimes(1);
    });
  });
});

Run Code Online (Sandbox Code Playgroud)

我的目标是模拟从控制器返回的数据,并检查它在通过拦截器后是否等于我想要的格式化数据。

Yog*_*ity 8

我将展示我的项目中的一个简单且清晰的现实世界示例。该示例与问题中显示的示例类似,该问题是关于使用拦截器来转换对象的。我使用此拦截器来排除敏感属性,例如hashedPassword作为user以下对象发送的对象response

describe('SerializerInterceptor', () => {
  let interceptor: SerializerInterceptor

  beforeEach(() => {
    interceptor = new SerializerInterceptor(UserDto)
  })

  it('should return user object without the sensitive properties', async () => {

    const context = createMock<ExecutionContext>()
    const handler = createMock<CallHandler>({
      handle: () => of(testUser)
    })

    const userObservable = interceptor.intercept(context, handler)
    const user = await lastValueFrom(userObservable)

    expect(user.id).toEqual(testUser.id)
    expect(user.username).toEqual(testUser.username)

    expect(user).not.toHaveProperty('hashedPassword')
  })
})
Run Code Online (Sandbox Code Playgroud)

为了模拟ExecutionContextCallHandler,我们使用@golevelup/ts-jestcreateMock()包中的函数。

NestJSInterceptor在底层使用 RxJS。因此,当intercept()框架调用它的方法时,它会返回Observable我们的对象的一个​​。为了从 this 中干净地提取我们的值Observable,我们使用 RxJS 中的便利函数lastValueFrom()

这里testUser是您的被测试对象。您需要创建它并将其提供给模拟处理程序,如上所示。