I tried writing a nestjs project that just saves some objects in mongodb, but running the test specs (users.service and users.controller), I get this mysterious error:
Nest can't resolve dependencies of the UsersService (?). Please make sure that the argument "UserModel" at index [0] is available in the RootTestModule context.
Potential solutions:
- Is RootTestModule a valid NestJS module?
- If "UserModel" is a provider, is it part of the current RootTestModule?
- If "UserModel" is exported from a separate @Module, is that module imported within RootTestModule?
@Module({
imports: [ /* the Module containing "UserModel" */ ]
})
6 |
7 | beforeEach(async () => {
> 8 | const module: TestingModule = await Test.createTestingModule({
| ^
9 | providers: [UsersService],
10 | }).compile();
11 |
I have a root app module, that imports and sets up mongoose and a users module. The app controller has the /
endpoint which just returns a status message. The tests for the app controller work. I am getting the above error for both user service and users controller specs. Here is the users service spec for example
import { Test, TestingModule } from '@nestjs/testing';
import { UsersService } from './users.service';
describe('UsersService', () => {
let service: UsersService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UsersService],
}).compile();
service = module.get<UsersService>(UsersService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
The user controller has 2 endpoints to create and fetch a new user. Here is the user module:
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { MongooseModule } from '@nestjs/mongoose';
import { User, UserSchema } from './schemas/user.schema';
@Module({
imports: [
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
],
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}
Followed by the users service:
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { User } from './schemas/user.schema';
import { Model } from 'mongoose';
import { CreateUserDto } from './dto/create-user.dto';
@Injectable()
export class UsersService {
constructor(@InjectModel(User.name) private userModel: Model<User>) {}
async create(createUserDto: CreateUserDto): Promise<User> {
const user = new this.userModel(createUserDto);
return user.save();
}
async findById(id: string): Promise<User> {
return this.userModel.findById(id).exec();
}
}
And here is the users controller:
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { User } from './schemas/user.schema';
@Controller('users')
export class UsersController {
constructor(private usersService: UsersService) {}
@Post()
async create(@Body() createUserDto: CreateUserDto) {
await this.usersService.create(createUserDto);
}
@Get(':id')
async findById(@Param('id') id: string): Promise<User> {
return this.usersService.findById(id);
}
}
The problem is in how the spec is written. I'm quite new to dependency injection frameworks so your help in understanding and solving this is much appreciated.
You need to add in mocks of the dependencies of the UsersService
, in this case, a custom provider that matches the injection token of @InjectModel(User.name)
. Fortunately, @nestjs/mongoose
has a helper method to create this token, so you only need to add a mock instance to your providers
array of the testing module and you'll be good to go.
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { User } from './schemas/user.schema';
import { UsersService } from './users.service';
describe('UsersService', () => {
let service: UsersService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
UsersService,
{
provide: getModelToken(User.name),
useValue: {
findById: () => ({
exec: jest.fn().mockResolvedValue(someMockUserObject)
})
}
}
],
}).compile();
service = module.get<UsersService>(UsersService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
You can see more in-depth examples in this community maintained testing example repository