Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing nestjs guards Unknown authentication strategy

Trying to write unit tests as described here but no idea how to get around this error

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

auth file

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

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

test

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();
})

The actual implementation works fine, I add it to a controller.

@UseGuards(MyGuard)
export class MyController {

I don't even need to add it as a provider or anything in my setup so not sure what other code to include.

I implemented a custom strategy which may be related

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) {
    ...
  }
}

And of course MyStrategy is added as a provider in my app.

I have unit tests covering my custom strategy already so it is really just the guard left

EDIT:

Trying Jay's suggestion below gets me a little closer but i'm still struggling.

It seems passport.use() expects a name and Strategy rather than a function (so TS compilation fails) so I tried

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

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

and the error disappears, but the test now outputs

expect(received).toBeTrue()

Expected value to be true:
  true
Received:
  {}

Any further suggestions?

like image 992
myol Avatar asked Apr 02 '26 22:04

myol


1 Answers

This is one of those quirky things with passport that I never thought I'd see. So, passport uses strategy names to determine what authentication method is actually being used, right? All of these strategies get registered to the passport context using passport.use(name, method) in the general scheme of things. In the context of Nest, this happens when you create a custom strategy, extend PassportStrategy and add the strategy as a provider as seen here. Later, the method passport.authenticate(strategy, (err, req, res, next) is called during the AuthGuard#canActivate method (the codes a bit complex, but this is where it happens). Because passport has never seen passport.use('test-jwt', authMethod) in the context of your test, it ends up not knowing what to do other than throwing the error about "Unknown authentication strategy".

Normally, the validate method is what becomes the authMethod, but if you're just needing this for the context of your test you can do something like

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();
})

and it should work out all right. You an then modify the value returned from that method, or make it a jest.fn() so that you can check what it was called with and modify what it returns if you need to do extra testing on the guard.

like image 142
Jay McDoniel Avatar answered Apr 04 '26 11:04

Jay McDoniel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!