Reputation: 2478
I want to e2e an endpoint called /users
with nestjs but I got an error. I have doubts how to make the test pass with a guard.
First error
Nest can't resolve dependencies of the UserModel (?). Please make sure that the argument DatabaseConnection at index [0] is available in the MongooseModule context.
Second error
expected 200 "OK", got 401 "Unauthorized"
App.module
@Module({
imports: [
MongooseModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
uri: configService.mongoUri,
useNewUrlParser: true,
}),
inject: [ConfigService],
}),
GlobalModule,
UsersModule,
AuthModule,
PetsModule,
RestaurantsModule,
ConfigModule,
],
controllers: [],
providers: [],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(TokenDataMiddleware)
.forRoutes({ path: '*', method: RequestMethod.ALL });
}
}
UsersService
@Injectable()
export class UsersService {
constructor(
@InjectModel('User') private readonly userModel: Model<UserDocument>,
private readonly utilsService: UtilsService,
private readonly configService: ConfigService,
) { }
async getAllUsers(): Promise<UserDocument[]> {
const users = this.userModel.find().lean().exec();
return users;
}
}
Controller
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService, private readonly utilsService: UtilsService) { }
@Get()
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
async users() {
const users = await this.usersService.getAllUsers();
return users;
}
e2e file
describe('UsersController (e2e)', () => {
let app: INestApplication;
beforeAll(async () => {
const testAppModule: TestingModule = await Test.createTestingModule({
imports: [AppModule, GlobalModule,
UsersModule,
AuthModule,
PetsModule,
RestaurantsModule,
ConfigModule],
providers: [],
}).compile();
app = testAppModule.createNestApplication();
await app.init();
});
it('GET all users from API', async () => {
// just mocked users;
const users = getAllUsersMock.buildList(2);
const response = await request(app.getHttpServer())
.get('/users')
.expect(200);
});
afterAll(async () => {
await app.close();
});
});
Upvotes: 5
Views: 7244
Reputation: 60347
In a unit test, you test a single unit (service, controller,...) meaning you import one unit and mock all its dependencies. In an e2e test, however, you want to test your whole application so you should import the root module (AppModule
) instead of single units or modules. Sometimes you might want to mock particular parts of your application like a database or a 3rd-party API; you can do that with overrideProvider
etc.
In your case, you are probably missing the forRoot
import of the MongooseModule
from your AppModule
. Instead of restructuring parts of your application, import the AppModule:
await Test.createTestingModule({
imports: [AppModule],
}).compile()
.overrideProvider(HttpService)
.useValue(httpServiceMock);
You need to authenticate against your API if it's protected by a guard. You can either create a JWT programatically or use your API for it. I'm assuming you have an endpoint for authentication in the following example:
const loginResponse = await request(app.getHttpServer())
.post('/auth/login')
.send({ username: 'user', password: '123456' })
.expect(201);
// store the jwt token for the next request
const { jwt } = loginResponse.body;
await request(app.getHttpServer())
.get('/users')
// use the jwt to authenticate your request
.set('Authorization', 'Bearer ' + jwt)
.expect(200)
.expect(res => expect(res.body.users[0])
.toMatchObject({ username: 'user' }));
Upvotes: 12