nestjs / nest

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀
https://nestjs.com
MIT License
67.44k stars 7.6k forks source link

Guard: Not getting called in e2e tests unless specified in useGlobalGuards #9314

Closed vytautas-pranskunas- closed 2 years ago

vytautas-pranskunas- commented 2 years ago

Is there an existing issue for this?

Current behavior

I have local auth strategy giard and it is beying called when running application but it is not called when running e2e tests. I have tried litterally everything. I see similar issue here ithout answer: https://github.com/nestjs/nest/issues/628

I have added all required elements to repro just could not run e2e tests. In case it works - I am using not express but fastify adapter so code can be changed a bit to:

let app: NestFastifyApplication;

    beforeAll(async () => {
        const moduleFixture: TestingModule = await Test.createTestingModule({
            imports: [AppModule],
        })
            .compile();

        app = moduleFixture.createNestApplication<NestFastifyApplication>(new FastifyAdapter());
        await app.init();
        await app.getHttpAdapter().getInstance().ready();
    });

it('should return error if email was not found', async () => {
            const { body, statusCode } = await app.inject({
                method: 'GET',
                url: AuthRoutes.getFullRoute('signin'),
                payload: {
                    username: 'vytasbboy@gmail.com',
                },
            });

            expect(body).toBe(true);
        });

Minimum reproduction code

https://codesandbox.io/s/proud-architecture-rrubq6?file=/src/guards/jwt-auth.guard.ts

Steps to reproduce

No response

Expected behavior

Guards should be called same like in normal call

Package

Other package

No response

NestJS version

No response

Packages versions

Node.js version

No response

In which operating systems have you tested?

Other

No response

stanimirovv commented 2 years ago

Where exactly are you binding the guard ? Is it global or supposed to be for a controller ? I don't see it in the code, but that should be an issue on my end

jmcdo29 commented 2 years ago

Could you put this in a git so it's easier to work with in a local environment?

micalevisk commented 2 years ago

@vytautas-pranskunas- I think I know what's going on, assuming you have that app.useGlobalGuards line in your src/main.ts file only

You're expecting that the bootstrap function of your src/main.ts to being called. But it won't unless you call it explicity in your test suite setup (due to how nodejs works)

You can circumvent that by removing the app.useGlobalGuards in favor of this another approach:


import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';

@Module({
  providers: [
    {
      provide: APP_GUARD,
      useClass: YourGuardClassHere,
    },
  ],
})
export class AppModule {}

now you just need to add AppModule in your imports array if you want to enable the guard YourGuardClassHere globally.

vytautas-pranskunas- commented 2 years ago

Sry I forgot to add @useguard(LocalAuth) decorator on e dpoint in example but I ha e it in my code.

Glilobal Jwt decorator gets called but local is not

micalevisk commented 2 years ago

make sure you have registered the LocalStrategy as a provider.

Your AppModule that you shared should be providers: [AppService, LocalStrategy]

image

vytautas-pranskunas- commented 2 years ago

I was doing this example code very quick. As I have mentioned it is working when I am starting server locally but it does not when in e2e tests. I have it registered as provider

Screenshot 2022-03-09 at 20 29 45

as well as decorator:

Screenshot 2022-03-09 at 20 30 23
jmcdo29 commented 2 years ago

Can you provide a minimum reproduction as a git repo?

vytautas-pranskunas- commented 2 years ago

I did: https://github.com/vytautas-pranskunas-/temp

if you run loclly and hit signin endpoint with any username you will see console output: console.log('validating local strategy'); meaning that local auth guard was visited. If you run e2e tests you will see 'Unauthorized' message without console output Or you can simply debug

jmcdo29 commented 2 years ago

Works fine

❯ pnpm test:e2e

> temp@0.0.1 test:e2e /home/jay/Documents/code/help/guard-e2e
> jest --config ./tests/jest-e2e.json --runInBand --verbose --silent --detectOpenHandles --coverage

 FAIL  src/features/auth/auth.e2e.spec.ts
  Auth E2E
    on sign in
      ✕ should return error if email was not found (98 ms)

  ● Auth E2E › on sign in › should return error if email was not found

    expect(received).toContain(expected) // indexOf

    Expected substring: "some message"
    Received string:    "{\"statusCode\":401,\"message\":\"Unauthorized\"}"

      40 |             expect(statusCode).toBe(401);
      41 |
    > 42 |             expect(body).toContain('some message');
         |                          ^
      43 |         });
      44 |     });
      45 | });

      at Object.<anonymous> (features/auth/auth.e2e.spec.ts:42:26)

You get the 401, you get the unauthorized response, this works as I would expect it to.

For further support please use our Discord channel (Support). We are using GitHub to track Bug Reports, Feature Requests, and Regressions.

vytautas-pranskunas- commented 2 years ago

nooo! because it never goes to AuthGuard - dont you see? I could get 401 but it should visit AuthGuard! same as when you run server

jmcdo29 commented 2 years ago

It does go to the AuthGuard, and AuthGuard('local') calls to passport, passport returns an error because there's a missing password, Nest catches the error in the AuthGuard() and returns a 401. this is how the AuthGuard() works

vytautas-pranskunas- commented 2 years ago

Ah, OK I will try to add password when I am home. Thanks for now.