Nest: unit-test controller guard

Created on 2 May 2020  ·  3Comments  ·  Source: nestjs/nest


 FAIL  src/modules/material/controller/material.controller.spec.ts
  ● Test suite failed to run

    Invalid guard passed to @UseGuards() decorator (CreativeController).

      12 | @Controller('creative')
      13 | @UseGuards(AuthGuard)
    > 14 | export class CreativeController {
         |                                ^
      15 |     constructor(private readonly creativeService: CreativeService) {}

      at Object.validateEach (../node_modules/_@[email protected]@@nestjs/common/utils/validate-each.util.js:20:15)
      at UseGuards (../node_modules/_@[email protected]@@nestjs/common/decorators/core/use-guards.decorator.js:38:30)
      at DecorateConstructor (../node_modules/[email protected]@reflect-metadata/Reflect.js:541:33)
      at Object.decorate (../node_modules/[email protected]@reflect-metadata/Reflect.js:130:24)
      at Object.__decorate (../node_modules/[email protected]@tslib/tslib.js:94:96)
      at Object.<anonymous> (modules/creative/controller/creative.controller.ts:14:32)

AuthGuard.ts

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(private readonly authService: AuthService) {}

    async canActivate(context: ExecutionContext): Promise<boolean | any> {
      ......  
      return true;
    }
}

material.controller.ts、creative.controller.ts


// material.controller.ts
@UseGuards(AuthGuard)
export class MaterialController {
    constructor(private readonly materialService: MaterialService) {}
}

// creative.controller.ts
@UseGuards(AuthGuard)
export class CreativeController {
    constructor(private readonly creativeService: CreativeService) {}
}

material.controller.spec.ts

describe('test controller', () => {
    let controller: MaterialController;
    beforeEach(() => {
        // const mockGuard: CanActivate = { canActivate: jest.fn(() => Promise.resolve(true)) };

        const module: TestingModule = await Test.createTestingModule({
            imports: [MaterialModule],
        }).compile();

        controller = module.get<MaterialController>(MaterialController);
    });
});

I don't know why?
Invalid guard passed to @UseGuards() decorator (CreativeController).

Appreciate any help, Thanks.

needs triage question 🙌

Most helpful comment

My guess is that you use index.ts files (barrel files) to re-export classes. In Jest, this will sometimes lead to classes represented as undefined. This error:

Invalid guard passed to @UseGuards() decorator (CreativeController).

Means that you passed undefinedvalue (AuthGuard = undefined). Make sure to get rid of your index.ts (or any barrel files) in your app.

Please, use our Discord channel (support) or StackOverflow for such questions. We are using GitHub to track bugs, feature requests, and potential improvements.

All 3 comments

You shouldn't be using imports in your unit tests, as that will import the entire module. Rather, you should be using controllers: [MaterialController] and provide custom providers to mock out the dependencies of the MaterialController for the unit test.

Please use our Discord as we are using GitHub to track bugs and feature requests.

Sorry, I can't use discordapp.com in China

I find .overrideguard() doesn't work.
It's ok if I try to remove line constructor(private readonly authService: AuthService) {}

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(private readonly authService: AuthService) {}

    async canActivate(context: ExecutionContext): Promise<boolean | any> {}

material.controller.spec.ts


describe('test controller', () => {
    let controller: MaterialController;
    beforeEach(async () => {
        const mockGuard: CanActivate = { canActivate: jest.fn(() => true) };

        const module: TestingModule = await Test.createTestingModule({
            controllers: [MaterialController],
            // providers: [{ provide: AuthGuard, useValue: mockGuard }],
        })
            .overrideGuard(AuthGuard)
            .useValue(mockGuard)
            .compile();

       controller = module.get<MaterialController>(MaterialController);
    });

        describe('controller test', () => {
            it('test hi', (done) => {
                expect(controller.query()).toBe('hi');
                done();
            });
        });
});

Environment

  • Nest version: 6.5.0
  • Node version: 10.15.3

My guess is that you use index.ts files (barrel files) to re-export classes. In Jest, this will sometimes lead to classes represented as undefined. This error:

Invalid guard passed to @UseGuards() decorator (CreativeController).

Means that you passed undefinedvalue (AuthGuard = undefined). Make sure to get rid of your index.ts (or any barrel files) in your app.

Please, use our Discord channel (support) or StackOverflow for such questions. We are using GitHub to track bugs, feature requests, and potential improvements.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

VRspace4 picture VRspace4  ·  3Comments

rafal-rudnicki picture rafal-rudnicki  ·  3Comments

cojack picture cojack  ·  3Comments

breitsmiley picture breitsmiley  ·  3Comments

janckerchen picture janckerchen  ·  3Comments