I am struggling to implement e2e test. Outside test environment in production my application works well with passport, but as soon as I import the main module in my e2e tests, I am getting a strange error from TypeError: passport.use is not a function. I am using Passport JWT Strategy implementation. I cannot seem to get past this
describe('Stand Module', () => {
let app: INestApplication;
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
imports: [
AppModule
]
})
//.overrideProvider(StandService)
//.useValue(standServiceMock)
.compile();
app = moduleRef.createNestApplication();
await app.init();
});
it('/GET all stands', () => {
return request(app.getHttpServer())
.get('/stand')
.expect(HttpStatus.UNAUTHORIZED);
});
afterAll(async () => {
await app.close();
});
});
Below is what I am getting but in production everything works just fine.
PASS src/stand/service/stand.service.spec.ts
PASS src/stand/controller/stand.controller.spec.ts
FAIL src/stand/stand.e2e.spec.ts (6.304s)
● Stand Module › /GET all stands
TypeError: passport.use is not a function
9 | export class JwtStrategy extends PassportStrategy(Strategy) {
10 | constructor(private readonly authService: AuthService) {
> 11 | super({
| ^
12 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
13 | secretOrKey: AppConfigs.secret,
14 | });
@kamilmysliwiec I really appreciate your help
Please provide a minimum reproduction repository.
I started to work up a minimum reproduction repository and it kept working. I narrowed it down to this moduleDirectories line, which I'd added in my failing version:
```--- a/test/jest-e2e.json
+++ b/test/jest-e2e.json
@@ -1,5 +1,4 @@
{
Here's a repo that reproduces the problem: https://github.com/woodchuck/nestjs-issue-5522
The first commit is the initial nest-generated app, the second sets up a JwtAuthGuard, and the third has the change that introduces the error.
@woodchuck Why do you change the moduleDirectories property? It works just fine as moduleDirectories: [node_modules].
I'm able to reproduce the problem, but if I use the property above without the ../ then there is no issue with running the code
Hi @jmcdo29. I wanted to reference imports in some areas of the code based on the root dir, rather than using a relative path. For instance, I like using
import { FooModel } from 'src/database/models/foo.model';
vs.
import { FooModel } from '../../database/models/foo.model';
@jmcdo29 If you happen to use absolute imports, the below moduleDirectories config is necessary
- "moduleDirectories": ["node_modules", "./"],
@woodchuck @rungwe Gotcha. Well, by saying to import from '../' that affects all import statements, not just the ones in your application, so when there is an import * as passport from 'passport' call in this file, it finds the first directory called passport which happens to be @nestjs/passport. The exports from here are:
{
__esModule: true,
AbstractStrategy: [class AbstractStrategy],
AuthGuard: [Function (anonymous)],
AuthModuleOptions: [class AuthModuleOptions],
PassportModule: [class PassportModule],
PassportSerializer: [class PassportSerializer],
PassportStrategy: [Function: PassportStrategy]
}
Which obviously does not have a use method. Normally, passport's exports look like this:
Authenticator {
_key: 'passport',
_strategies: {
session: SessionStrategy {
name: 'session',
_deserializeUser: [Function: bound ]
}
},
_serializers: [],
_deserializers: [],
_infoTransformers: [],
_framework: {
initialize: [Function: initialize],
authenticate: [Function: authenticate]
},
_userProperty: 'user',
_sm: SessionManager {
_key: 'passport',
_serializeUser: [Function: bound ]
},
Authenticator: [Function: Authenticator],
Passport: [Function: Authenticator],
Strategy: <ref *1> [Function: Strategy] { Strategy: [Circular *1] },
strategies: { SessionStrategy: [Function: SessionStrategy] }
}
To solve this,you can use "<rootDir>/../" instead of ../ and it will only resolve from your rootDir (which is the test directory)
@jmcdo29 thanks a lot that solved the problem. The solution works perfectly
@jmcdo29 Works for me too. Thanks!
Most helpful comment
@woodchuck @rungwe Gotcha. Well, by saying to import from
'../'that affects all import statements, not just the ones in your application, so when there is animport * as passport from 'passport'call in this file, it finds the first directory calledpassportwhich happens to be@nestjs/passport. The exports from here are:Which obviously does not have a
usemethod. Normally,passport's exports look like this:To solve this,you can use
"<rootDir>/../"instead of../and it will only resolve from yourrootDir(which is thetestdirectory)