Rig*_*eek 5 node.js typescript jestjs nestjs
我在 NestJS 中配置了一个控制器,我想检查是否设置了适当的保护 - 有没有人有如何完成的示例?
这个(删节的)示例作为一个应用程序可以正常工作,所以我只是在测试指导之后。
您会注意到在用户测试中有我正在调用的测试Reflect.getMetadata。我在做这样的事情 - 当我在__guards__元数据上检查它时,这是一个函数,我正在努力模拟它,以便我可以检查它AuthGuard('jwt')是否在设置时应用。
用户控制器.ts
@Controller('/api/user')
export class UserController {
@UseGuards(AuthGuard('jwt'))
@Get()
user(@Request() req) {
return req.user;
}
}
Run Code Online (Sandbox Code Playgroud)
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);
});
});
});
Run Code Online (Sandbox Code Playgroud)
我意识到这并不完全是您正在寻找的答案,但是在 @Jay McDoniel 的答案的基础上,我使用以下内容来测试控制器函数上自定义装饰器的存在(尽管我不能 100% 确定这是否是测试的正确方法)这适用于非定制警卫)
import { Controller } from '@nestjs/common';
import { UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from './jwtAuthGuard';
@Controller()
export class MyController {
@UseGuards(JwtAuthGuard)
user() {
...
}
}
Run Code Online (Sandbox Code Playgroud)
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)
});
Run Code Online (Sandbox Code Playgroud)
对于控制器来说
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)
});
Run Code Online (Sandbox Code Playgroud)
对于它的价值,您不应该需要测试框架提供的装饰器是否也设置了您所期望的。这就是该框架开始对它们进行测试的原因。不过,如果您想检查装饰器是否实际设置了预期的元数据,您可以在此处看到已完成的操作。
如果你只是想测试守卫,你可以直接实例化 GuardClass 并canActivate通过提供一个ExecutionContext对象来测试它的方法。我这里有一个例子。该示例使用一个为您创建模拟对象的库(从那时起重命名),但它的想法是您将创建一个对象,如
const mockExecutionContext: Partial<
Record<
jest.FunctionPropertyNames<ExecutionContext>,
jest.MockedFunction<any>
>
> = {
switchToHttp: jest.fn().mockReturnValue({
getRequest: jest.fn(),
getResponse: jest.fn(),
}),
};
Run Code Online (Sandbox Code Playgroud)
在哪里getRequest并getResponse返回 HTTP 请求和响应对象(或至少部分)。要仅使用此对象,您还需要使用as any来防止 Typescript 抱怨太多。
根据 myol 的回答,我制作了一个实用函数来在一个衬垫中测试这一点。其特点是:
测试是单行的。
即使有多个守卫也能工作。
当测试失败时,它会显示有意义的笑话风格的错误消息。例如:
Expected: findMe to be protected with JwtAuthGuard
Received: only AdminGuard,EditorGuard
测试如下所示:
it(`should be protected with JwtAuthGuard.`, async () => {
expect(isGuarded(UsersController.prototype.findMe, JwtAuthGuard)).toBe(true)
})
Run Code Online (Sandbox Code Playgroud)
为了测试整个控制器上的防护,请调用相同的函数,如下所示:
expect(isGuarded(UsersController, JwtAuthGuard)).toBe(true)
Run Code Online (Sandbox Code Playgroud)
这是效用函数isGuarded()。您可以将其复制到任何文件,例如test/utils.ts:
/**
* Checks whether a route or a Controller is protected with the specified Guard.
* @param route is the route or Controller to be checked for the Guard.
* @param guardType is the type of the Guard, e.g. JwtAuthGuard.
* @returns true if the specified Guard is applied.
*/
export function isGuarded(
route: ((...args: any[]) => any) | (new (...args: any[]) => unknown),
guardType: new (...args: any[]) => CanActivate
) {
const guards: any[] = Reflect.getMetadata('__guards__', route)
if (!guards) {
throw Error(
`Expected: ${route.name} to be protected with ${guardType.name}\nReceived: No guard`
)
}
let foundGuard = false
const guardList: string[] = []
guards.forEach((guard) => {
guardList.push(guard.name)
if (guard.name === guardType.name) foundGuard = true
})
if (!foundGuard) {
throw Error(
`Expected: ${route.name} to be protected with ${guardType.name}\nReceived: only ${guardList}`
)
}
return true
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3288 次 |
| 最近记录: |