如何对NestJS的控制器上应用防护措施进行单元测试?

时间:2020-01-16 10:16:59

标签: node.js typescript jestjs nestjs

我在NestJS中配置了一个控制器,我想检查是否设置了适当的防护措施-有人能举个例子吗?

这个(经过删节的)示例可以作为应用程序正常工作,所以我只是在测试指南之后。

您会注意到,在用户测试中,有一些我在叫Reflect.getMetadata的测试。我正在寻找类似的东西-当我在__guards__元数据上检查它时,这是一个函数,我正在努力模拟它,以便可以检查它是否与AuthGuard('jwt')一起应用

User.controller.ts

@Controller('/api/user')
export class UserController {
  @UseGuards(AuthGuard('jwt'))
  @Get()
  user(@Request() req) {
    return req.user;
  }
}

User.controller.spec.ts

describe('User Controller', () => {
  // beforeEach setup as per the cli generator

  describe('#user', () => {
    beforeEach(() => {
      // This is how I'm checking the @Get() decorator is applied correctly - I'm after something for __guards__
      expect(Reflect.getMetadata('path', controller.user)).toBe('/');
      expect(Reflect.getMetadata('method', controller.user)).toBe(RequestMethod.GET);
    });

    it('should return the user', () => {
      const req = {
        user: 'userObj',
      };

      expect(controller.user(req)).toBe(req.user);
    });
  });
});

2 个答案:

答案 0 :(得分:1)

对于它的价值,您不需要测试框架提供的装饰器是否也设置了您期望的装饰器。这就是框架从一开始就对其进行测试的原因。不过,如果您要检查装饰器是否确实设置了预期的元数据you can see that done here

如果您只是想测试Guard,可以通过提供canActivate对象直接实例化GuardClass并测试其ExecutionContext方法。 I've got an example here。该示例使用了一个为您创建模拟对象的库,但其目的是要创建一个像

这样的对象
const context = {
  switchToHttp: () => ({
    getRequest: jest.fn(),
    getResponse: jest.fn(),
  })
}

getRequestgetResponse返回HTTP请求和响应对象(或其中至少一部分)的地方。要仅使用该对象,还需要使用as any来防止Typescript抱怨太多。

答案 1 :(得分:1)

我意识到这不是您正在寻找的答案,但是基于@Jay McDoniel 的答案,我使用以下内容来测试控制器函数上自定义装饰器的存在(尽管我不是 100% 确定这是否正确)测试非自定义守卫的方法)

import { Controller } from '@nestjs/common';
import { UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from './jwtAuthGuard';

@Controller()
export class MyController {

  @UseGuards(JwtAuthGuard)
  user() {
    ...
  }
}
it('should ensure the JwtAuthGuard is applied to the user method', async () => {
  const guards = Reflect.getMetadata('__guards__', MyController.prototype.user)
  const guard = new (guards[0])

  expect(guard).toBeInstanceOf(JwtAuthGuard)
});

对于控制器

it('should ensure the JwtAuthGuard is applied to the controller', async () => {
  const guards = Reflect.getMetadata('__guards__', MyController)
  const guard = new (guards[0])

  expect(guard).toBeInstanceOf(JwtAuthGuard)
});