【问题标题】:Unit testing nestjs guards Unknown authentication strategy单元测试nestjs保护未知的身份验证策略
【发布时间】:2021-08-22 06:03:48
【问题描述】:

尝试按照here 的描述编写单元测试,但不知道如何解决此错误

Exception has occurred: Error: Unknown authentication strategy "test-jwt"
  at attempt (/home/user/Workspace/project/node_modules/passport/lib/middleware/authenticate.js:190:39)
    at authenticate

授权文件

import { Injectable } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";

@Injectable()
export class MyGuard extends AuthGuard('test-jwt') { }

测试

import { ExecutionContext } from "@nestjs/common";
import { MyGuard } from "./mygaurd";

it('test' () => {
    const context: ExecutionContext = {
      switchToHttp: () => context,
      getRequest: () => {
        return {
          headers: {
            authorization: `bearer ${jwt}` 
          }
        }
      },
      getResponse: () => { }
    } as unknown as ExecutionContext

    const guard = new MyGuard()

    expect(guard.canActivate(context)).toBeTrue();
})

实际实现效果很好,我将它添加到控制器中。

@UseGuards(MyGuard)
export class MyController {

我什至不需要将它添加为提供程序或我的设置中的任何内容,因此不确定要包含哪些其他代码。

我实施了一个可能相关的自定义策略

import { Strategy, ExtractJwt } from "passport-jwt";
import { Injectable } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";

@Injectable()
export class MyStrategy extends PassportStrategy(Strategy, 'test-jwt') {
   
  constructor() {
    super({ 
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 
      secretOrKey: 'secret'
    })
  }

  async validate(payload) {
    ...
  }
}

当然,MyStrategy 作为提供程序添加到我的应用程序中。

我已经对我的自定义策略进行了单元测试,所以它实际上只是剩下的警卫

编辑:

在下面尝试 Jay 的建议让我更接近了一点,但我仍在苦苦挣扎。

似乎passport.use() 需要名称和策略而不是函数(因此 TS 编译失败)所以我尝试了

import passport, { Strategy } from "passport";
...

passport.use('test-jwt', {
   authenticate: (payload) => true
} as Strategy);

错误消失了,但测试现在输出

expect(received).toBeTrue()

Expected value to be true:
  true
Received:
  {}

还有什么建议吗?

【问题讨论】:

    标签: unit-testing testing jestjs passport.js nestjs


    【解决方案1】:

    这是我从未想过会看到的带有护照的古怪事物之一。所以,passport 使用策略名称来确定实际使用的身份验证方法,对吗?在总体方案中,所有这些策略都使用passport.use(name, method) 注册到护照上下文中。在 Nest 的上下文中,当您创建自定义策略、扩展 PassportStrategy 并将策略添加为提供者 as seen here 时,就会发生这种情况。后来,passport.authenticate(strategy, (err, req, res, next) 方法被称为during the AuthGuard#canActivate 方法(代码有点复杂,但这就是它发生的地方)。由于passport 从未在您的测试环境中看到passport.use('test-jwt', authMethod),因此除了抛出有关“未知身份验证策略”的错误之外,它最终不知道该做什么。

    通常,validate 方法会变成 authMethod,但如果您只是在测试环境中需要它,您可以执行类似的操作

    it('test' () => {
        passport.use('test-jwt', (payload) => true);
        const context: ExecutionContext = {
          switchToHttp: () => context,
          getRequest: () => {
            return {
              headers: {
                authorization: `bearer ${jwt}` 
              }
            }
          },
          getResponse: () => { }
        } as unknown as ExecutionContext
    
        const guard = new MyGuard()
    
        expect(guard.canActivate(context)).toBeTrue();
    })
    

    它应该可以正常工作。然后,您可以修改从该方法返回的值,或将其设为 jest.fn(),这样您就可以检查调用它的内容,并在需要对守卫进行额外测试时修改它返回的内容。

    【讨论】:

    • 我用我的新问题更新了我的问题。 canActivate 应该返回一个 boolean 所以我得到一个空对象返回的事实让我觉得我仍然没有正确实现这个测试。
    • 您可能需要等待guard.canActivate 并使测试异步。我相信 Nest 默认将 AuthGuard#canActivate 视为异步
    • 我尝试使测试异步,但我的模拟导致了问题。在auth.guards.js 中的87 行,Promise 永远不会解决并且我的测试超时。在我的自定义守卫中的实时呼叫handleRequest 会在该行之后立即调用。我花了几个小时单步执行代码,但回调不是我的强项。我相信我的测试在 createPassportContext 或执行 yield passportFn(...) 时失败
    猜你喜欢
    • 2022-07-19
    • 2015-09-10
    • 2021-12-15
    • 2020-10-21
    • 2019-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-08
    相关资源
    最近更新 更多