NestJS:如何在 canActivate 中模拟 ExecutionContext

tmp*_*ech 6 unit-testing jestjs nestjs

我在 Guard 中间件中模拟 ExecutionContext 时遇到了麻烦。

这是我的 RoleGuard 扩展 JwtGuard

@Injectable()
export class RoleGuard extends JwtAuthGuard {
 ...
 async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const params = request.params;

    ...
 }
}
Run Code Online (Sandbox Code Playgroud)

这就是我在单元测试中所尝试的。

let context: ExecutionContext = jest.genMockFromModule('@nestjs/common');
  
context.switchToHttp = jest.fn().mockResolvedValue({
  getRequest: () => ({
   originalUrl: '/',
   method: 'GET',
   params: undefined,
   query: undefined,
   body: undefined,
  }),
  getResponse: () => ({
    statusCode: 200,
  }),
});
    
jest.spyOn(context.switchToHttp(), 'getRequest').mockImplementation(() => {
 return Promise.resolve(null);
});
Run Code Online (Sandbox Code Playgroud)

我收到了这种错误。

Cannot spy the getRequest property because it is not a function; undefined given instead
Run Code Online (Sandbox Code Playgroud)

我希望你建议任何其他方式来模拟上下文。谢谢你。

Jay*_*iel 11

当涉及到时ExecutionContext,根据我要测试的内容,我只是提供一个简单的对象,例如

const ctxMock = {
  switchToHttp: () => ({
    getRequest: () => ({
      params: paramsToAdd,
      url: 'some url path',
      ...
    }),
  }),
}
Run Code Online (Sandbox Code Playgroud)

并根据我的需要使用它。如果我需要访问笑话函数,我会事先将它们保存到变量中,并将上下文的函数分配给该变量,然后我就可以expect(variable).toHaveBeenCalledTimes(x)毫无问题地使用。

另一种选择是用于@golevelup/ts-jest为您创建类型安全的模拟对象。我已经广泛使用了这个库以及我制作的其他库。


Xin*_*g L 5

请检查这个库https://www.npmjs.com/package/@golevelup/ts-jest

然后你可以模拟 ExecutionContext 如下。

import { createMock } from '@golevelup/ts-jest';
import { ExecutionContext } from '@nestjs/common';
 
describe('Mocked Execution Context', () => {
  it('should have a fully mocked Execution Context', () => {
    const mockExecutionContext = createMock<ExecutionContext>();
    expect(mockExecutionContext.switchToHttp()).toBeDefined();

    ...

  });
});
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你