[ ] Regression
[ ] Bug report
[ ] Feature request
[x] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
I have followed the unit test example but I am unable to get my very simple test to run (it's literally just testing if true === true) but it won't work because I'm met with this error
Nest can't resolve dependencies of the RoleService (?). Please verify whether [0] argument is available in the current context.
You can find the repo at https://bitbucket.org/mogusbi/breeze-bb/
After cloning, run npm run api:test
// role.controller.spec.ts
import {Test} from '@nestjs/testing';
import {TestingModule} from '@nestjs/testing/testing-module';
import {RoleController} from './role.controller';
import {RoleService} from './role.service';
describe('Role controller', () => {
let controller: RoleController;
let service: RoleService;
beforeEach(async () => {
const mod: TestingModule = await Test
.createTestingModule({
components: [
RoleService
],
controllers: [
RoleController
]
})
.compile();
controller = mod.get<RoleController>(RoleController);
service = mod.get<RoleService>(RoleService);
});
it('should be true', () => {
expect(true).toBe(true);
});
});
// role.controller.ts
import {Controller} from '@nestjs/common';
import {RoleService} from './role.service';
@Controller('role')
export class RoleController {
constructor (
private readonly roleService: RoleService
) {}
...
}
// role.service.ts
import {InjectModel} from '@nestjs/mongoose';
import {PaginateModel} from 'mongoose';
import {IRole} from './role.interface';
import {RoleSchema} from './role.schema';
@Component()
export class RoleService {
constructor (
@InjectModel(RoleSchema) private readonly model: PaginateModel<IRole>
) {}
...
}
- Node version: 8.2.1
- Platform: Mac OS 10.13.2
โโโ @nestjs/[email protected]
โโโ @nestjs/[email protected]
โโโ @nestjs/[email protected]
โโโ @nestjs/[email protected]
โโโ @nestjs/[email protected]
โโโ @types/[email protected]
โโโ @types/[email protected]
โโโ @types/[email protected]
โโโ @types/[email protected]
โโโ @types/[email protected]
โโโ @types/[email protected]
โโโ @types/[email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
โโโ [email protected]
I suppose it's failing because in your RoleService you are injecting an mongoose model, which is not including in the testing module. You should create a mock or inject the real one
@xxxtonixxx It's not clear how you would inject it, I've tried the following
beforeEach(async () => {
const mod: TestingModule = await Test
.createTestingModule({
components: [
RoleService
],
controllers: [
RoleController
],
imports: [
MongooseModule.forFeature([
{
name: 'Role',
schema: RoleSchema
}
])
]
})
.compile();
controller = mod.get<RoleController>(RoleController);
service = mod.get<RoleService>(RoleService);
});
but it only yields this error; Nest can't resolve dependencies of the useFactory (?). Please verify whether [0] argument is available in the current context.
That is because the MongooseModule.forFeature(...)
needs to inject your Connection
object. You should either add MongooseModule.forRoot(...)
to your imports or mock your RoleSchema
.
EDIT: See @shane-melton's response
I you want to mock the RoleSchema
(which is the best option), try :
beforeEach(async () => {
const mod: TestingModule = await Test
.createTestingModule({
components: [
RoleService
],
controllers: [
RoleController
],
imports: [
{
provide: 'RoleSchemaModel',
useValue: {
// Your mock
}
}
]
})
.compile();
controller = mod.get<RoleController>(RoleController);
service = mod.get<RoleService>(RoleService);
});
If you're wondering why provide: 'RoleSchemaModel'
have a look at this ;)
EDIT: Missing link
https://github.com/nestjs/mongoose/blob/master/lib/mongoose.utils.ts#L3
@fwoelffel look at what? My apologies if this appears to be a bit of stupid question but what would a mocked schema look like
Once I can get this working I'll put in a pull request to include a test in the mongoose module example
look at what? My apologies if this appears to be a bit of stupid question
The only stupid thing here is me forgetting to c/c the link... Here it is https://github.com/nestjs/mongoose/blob/master/lib/mongoose.utils.ts#L3
According to your code, and my understanding (I've never used Mongoose), your mock should look like a PaginateModel<IRole>
.
Hi,
Yeah, that's my mistake, there's no example in the documentation about how to mock repository/model. I'll update it soon. In the meantime, @shane-melton shows the best solution ๐
@mogusbi Not sure if you got @fwoelffel's solution to work yet; but I had to put the mock in components
instead of imports
to get things working properly. Something like the following:
beforeEach(async () => {
const mod: TestingModule = await Test
.createTestingModule({
components: [
RoleService,
{
provide: 'RoleSchemaModel',
useValue: {
// Your mock
}
}
],
controllers: [
RoleController
],
}
]
})
.compile();
controller = mod.get<RoleController>(RoleController);
service = mod.get<RoleService>(RoleService);
});
For people encoutering the same error message with TypeORM, please note that the DI loader cannot "know" your Repository instances as they're injected with @InjectRepository
:
export class DogsService {
constructor(@InjectRepository(Dog) private readonly dogsRepository: Repository<Dog>) {
// ...
}
}
I had more or less the same issue this morning and solved it by injecting "DogsRepository" manually:
Test.createTestingModule({
components: [
{
provide: 'DogsRepository',
useClass: Repository,
}
],
// ...
}).compile();
However, I would recommend extending Repositoryclass DogsRepository extends Repository<Dog>
) and use it in useClass (useClass: DogsRepository
, instead of useClass: Repository
), in order to be able to test the type of values returned by the repository instance (if you need to).
@kamilmysliwiec: does everything sound correct? Or am I mistaken somewhere? Shall I add it do the documentation?
I'm having no luck at all with this, I still can't work out how to mock the schema and even using the actual schema results in an error regardless of whether it's included in components or imports
const mod: TestingModule = await Test
.createTestingModule({
components: [
RoleService
],
controllers: [
RolesController
],
imports: [
{
provide: 'RoleSchemaModel',
useValue: RoleSchema
}
]
})
.compile();
results in TypeError: Object prototype may only be an Object or null: undefined
while
const mod: TestingModule = await Test
.createTestingModule({
components: [
RoleService,
{
provide: 'RoleSchemaModel',
useValue: RoleSchema
}
],
controllers: [
RolesController
]
})
.compile();
results in Error: Nest can't resolve dependencies of the RoleService (?). Please verify whether [0] argument is available in the current context.
@VinceOPS I'm having this issue with TypoORM, but cannot see what exactly I shall do.
I have my UsersService with this code:
@Component()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly usersRepo: Repository<User>
) {}
//...
I written this in the spec file for the test:
//...
beforeEach( async () => {
const module = await Test.createTestingModule({
components: [ UsersService, {
provide: User,
useClass: Repository
} ],
controllers: [ UsersController ],
}).compile()
//...
But I have no clear what I need to write in provide
and userClass
to avoid the message
Error: Nest can't resolve dependencies of the UsersService (?). Please verify whether [0] argument is available in the current context.
@ebadia Hi. Please have a look at this.
Give a token (name of the injected dependency) as provide
(here, I use the default one: <entityName>Repository
(e.g. "UserRepository"
), and the class to use to instantiate this dependency in useClass
(here, you want to inject an instance of "Repository" for your UsersService).
Hi all,
I have tried by following these steps:
Extending the Repository
```
import {Repository} from "typeorm";
import {Label} from "../Models/Label";
export class LabelsRepository extends Repository
}
2. Declaring it on my dependency installer:
const module = await Test.createTestingModule({
controllers: [LabelsController],
components: [{
provide: 'LabelsRepository',
useClass: LabelsRepository,
}, LabelsService
]
}).compile();
3. Injecting it in my service constructor:
private readonly labelRepository: LabelsRepository;
constructor(@Inject('LabelsRepository')
labelRepository: LabelsRepository) {
this.labelRepository = labelRepository;
}
```
But I still have an error:
_Nest can't resolve dependencies of the LabelsService (?). Please verify whether [0] argument is available in the current context._
Am I wrong?
Hi @samueleresca
The default injection token (for TypeORM repositories) is <entityName>Repository
. In your case, LabelRepository
, not LabelsRepository
.
Hi @VinceOPS ,
It still not working, I have tried both, by extending Repository<Label>
using LabelRepository
class, and also by simply referring Repository
.
Where am I doing wrong? Here you can find the repository:
https://github.com/samueleresca/Blog.NestGettingStarted
Hey!
I have almost the same situation as @samueleresca but with mongoose models. Neither registering a mock as component nor importing it resolves it.
Since almost every class to test somehow depends on a mongoose model I cannot write any tests. After reading through this issue I can't provide anything new. I made sure to update all dependencies to the latest version (4.6.4 in case of nestjs).
So does anyone has a working example?
Hey guys trying to write some tests for mongoose models as well, having no luck with this, im getting TypeError: Object prototype may only be an Object or null: undefined
i have a same problem
same here..
using...
https://github.com/EasyMetrics/nestjs-api-seed
and then simply following
https://docs.nestjs.com/techniques/sql
Nest can't resolve dependencies of the DemoService (?). Please verify whether [0] argument is available in the current context.
Is there any way at all to make this error message more helpful? Listing what has been included would be really good. I've been able to get to the bottom of it sometimes, but I've also just had to roll back my code and do something else. Also he was asking about database testing, can we get an example that doesn't use mocks?
In the documentation "Mongoose.forRoot" is imported in the Application module, this module is not imported during the creation the TestModule leading to this error as Mongoose.forFeature won't be able to find the connection initialized by Mongoose.forRoot.
You can declare "Mongoose.forRoot()" in your Test.createTestModule() statement or use a similar as me :
( please note that i have multiple database in my real project thats why i have a DatabaseModule )
@Module({
imports: [MongooseModule.forRoot('mongodb://localhost')],
})
export class DatabaseModule {}
@Module({
imports: [MongooseModule.forFeature([{ name: 'Cat', schema: CatSchema }])], // note that database module is not imported here
controllers: [CatController],
components: [CatService, CatRepository],
})
export class CatModule {}
@Module({
imports: [DatabaseModule, CatModule],
controllers: [],
components: [],
})
export class ApplicationModule {}
// ...
beforeAll(async () => {
const module = await Test.createTestingModule({
imports: [DatabaseModule, CatModule],
})
.compile();
// ....
});
Can someone help me to understand the issue? i've created an example of simple app with 2 modules (dummy using nest/mongoose and cats using custom provider as per the doc: https://github.com/ganchikov/nest_mongo_ut_sample
Both modules have tests:
the app itself is successfully executed, but when I run the test I get the following error for both modules:
`FAIL src\nest-mongoose\dummy.controller.spec.ts
โ Test suite failed to run
TypeError: mongoose.Schema is not a constructor
at Object.<anonymous> (nest-mongoose/dummy.schema.ts:2:43)
at Object.<anonymous> (nest-mongoose/dummy.service.ts:24:14)
at Object.<anonymous> (nest-mongoose/dummy.controller.spec.ts:11:14)
at Generator.next (<anonymous>)
at new Promise (<anonymous>)
at handle (../node_modules/worker-farm/lib/child/index.js:44:8)
at process.<anonymous> (../node_modules/worker-farm/lib/child/index.js:51:3)
at emitTwo (../events.js:126:13)
at process.emit (../events.js:214:7)
at emit (../internal/child_process.js:772:12)
at _combinedTickCallback (../internal/process/next_tick.js:141:11)
at process._tickCallback (../internal/process/next_tick.js:180:9)
`
and
`FAIL src\nest-providercats.controller.spec.ts
โ Test suite failed to run
TypeError: mongoose.Schema is not a constructor
at Object.<anonymous> (nest-provider/cat.schema.ts:2:39)
at Object.<anonymous> (nest-provider/cats.providers.ts:1:252)
at Object.<anonymous> (nest-provider/cats.module.ts:11:14)
at Object.<anonymous> (nest-provider/cats.controller.spec.ts:13:13)
at Generator.next (<anonymous>)
at new Promise (<anonymous>)
at handle (../node_modules/worker-farm/lib/child/index.js:44:8)
at process.<anonymous> (../node_modules/worker-farm/lib/child/index.js:51:3)
at emitTwo (../events.js:126:13)
at process.emit (../events.js:214:7)
at emit (../internal/child_process.js:772:12)
at _combinedTickCallback (../internal/process/next_tick.js:141:11)
at process._tickCallback (../internal/process/next_tick.js:180:9)
`
I've played the whole day yesterday trying different options including suggestions from this thread: #438
The result is always the same :( What i am missing?
@ganchikov also i have the same problem exactly... Any solution please ?
This is how I fixed it in my case:
I wanted to create a test case using a test database and not mock data.
So this is what I did (I'm using mocha but it should be the same with jest):
describe('Customer', function() {
this.timeout(22000);
const server = express();
before(async () => {
const module = await Test.createTestingModule({
imports: [
testDatabase([Customer, Channel]),
TypeOrmModule.forFeature([Customer, Channel])],
controllers: [CustomerController],
components: [CustomerService]
})
.compile();
const app = module.createNestApplication(server);
await app.init();
});
it(`/GET customer/all`, () => {
return request(server)
.get('/customer/all')
.expect(200);
});
});
And in testDatabse file :
export const testDatabase = (entities) => {
return TypeOrmModule.forRoot({
type: "mssql",
url: "databaseurlhere",
entities: entities || [],
options: {
encrypt: true
},
synchronize: false
})
}
Works fine so far and it's kind of amazing that it can access the database only using a portion of the entities that the db has!
So basically recreate the exact module in the test (Without importing the module itself) but before this add the connection to your desired database first. I used this simple functional wrapper to do that, you can do it your own way.
I like this approach even if it has a bit more work because it lets you see what entities are connected with the entity you're testing just by looking at the test's imports.
I hope this works with mongodb too.
@ganchikov +1. Waiting for solution...
This is explained in the new version of the documentation: https://docs.nestjs.com/v5/
@ganchikov @ChenShihao @AlbertoNitro I have the same problem. Any idea??
The documentation is now moved to the root directory.
Also, in order to learn more about custom providers, see here: https://docs.nestjs.com/fundamentals/custom-providers
Hey guys!
I've read the testing part of the database documentation but I could not find any hint or best practice for creating the mockRepository
object.
I would like to write tests where I mock the database layer of the service (e.g.: the adminRepository
of the AuthService
) by providing good ol' POJOs as data source. Is this achievable with the current version of TypeORM / Nest?
There is a related conversation in typeorm/typeorm#1267, but I couldn't get closer to my desired functionality.
My AuthService looks like this:
// auth.service.ts
@Injectable()
export class AuthService {
constructor(
@InjectRepository(Admin)
private readonly adminRepository: Repository<Admin>,
) { }
findByEmail(email: string): Promise<Admin> {
return this.adminRepository.findOne({ where: { email } });
}
findById(id: number): Promise<Admin> {
return this.adminRepository.findOne(id);
}
}
The desired output would look like something like this:
// auth.service.spec.ts
describe('AuthService', () => {
let authService: AuthService;
const mockRepository = {
data: [
{ id: 1, email: '[email protected]', password: '' },
{ id: 2, email: '[email protected]', password: '' },
],
};
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
AuthService,
{
provide: getRepositoryToken(Admin),
useValue: mockRepository,
},
],
}).compile();
authService = module.get<AuthService>(AuthService);
});
describe('findByEmail', () => {
it('should return an Admin with a valid email', async () => {
const email = '[email protected]';
const expected = mockRepository.data[1];
const admin = await authService.findByEmail(email);
expect(admin).toBe(expected);
});
});
});
I really look forward to hear some advices and tips about the pros/cons of this kind of testing strategy, my primary goal is to keep my unit tests as simple and as fast as I can. I really appreciate any help!
Does one has a idea to fix that?
It can not be that there is no working sample to unit test a component or sample with this setup. I found multiple sample projects on GH but they all have no tests.
I think you've run into the same issue as me. In order to use jest for testing, nest uses ts-jest to compile test files. Somehow ts-jest doesn't seem to handle _synthetic default imports_ properly. As soon as I turned it off all tests passed.
I've created a separate tsconfig for jest:
// tsconfig.jest.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"allowSyntheticDefaultImports": false
}
}
And configured ts-jest to use this in package.json:
// package.json
...
"jest": {
...
"globals": {
"ts-jest": {
"tsConfigFile": "./tsconfig.jest.json"
}
},
....
...
Don't forget to also turn this off for e2e tests. By default, nest creates another configuration file for it under test/jest-e2e.json
. I also added the globals object there:
...
"globals": {
"ts-jest": {
"tsConfigFile": "./tsconfig.jest.json"
}
},
...
And voila, everything's running.
Hopefully that'll work for the rest of us too.
Do u have to implement findOne on your const mockRepository ?
I'm getting
TypeError: this.userRepository.findOne is not a function
Any update on this issue?
I'll leave a note, since this issue comes up first in most google searches about mocks / unit tests with Typeorm in Nest.
TL;DR see the example below, or the corrected link from @jkchao above: the https://github.com/jkchao/blog-service/blob/nest/src/module/auth/__test__/auth.service.spec.ts
The recommended testing strategy (mentioned in the docs), to add { provides: getRepositoryToken(...), useWhatever }
works nicely for simple modules. The problem is when your tested module imports any other module, that depends (maybe indirectly) on any other db providers. Then, you get an error, because the other modules imports TypeOrmModule.forFeature(...)
, which in turn "depends" on TypeOrmModule.forRoot
:
Nest can't resolve dependencies of the YourEntity2Repository (?). Please verify whether [0] argument is available in the current context.
You can, of course, recursively list all the required imported providers in your call to createTestingModule
, and add all the mock db providers the same way, but it quickly becomes unmaintainable. A much simpler solution is to just import the whole tested module, and then use .overrideProvider
for each DB entity that the module uses (directly or not):
const testingModule = await Test.createTestingModule({ imports: [YourTestedModule] })
.overrideProvider(getRepositoryToken(YourEntity1))
.useValue(...)
.overrideProvider(getRepositoryToken(YourEntity2))
.useValue(...)
.compile();
Maybe it's worth mentioning this approach in the "Techniques > Database > Testing" docs? It took me a surprisingly long time looking for other workarounds (including mocking the db connection itself inside TypeOrmModule
), until I found out about .overrideProvider
.
Do u have to implement findOne on your const mockRepository ?
I'm gettingTypeError: this.userRepository.findOne is not a function
@danil-z did you find an answer to this?
@trainerbill if your mockRepository
object doesn't have all the methods it should have, it will fail if your services actually call the repository. You should either implement the method to return from some mock dataset, or mock the actual calls. This is what I'm currently using for the mock repos -- an object with the repo functions I use set to fail if used:
function mockRepositoryProvider<T extends /*my base entity type*/>(entity: Type<T>): ValueProvider {
const mkFailFn = (name: string) => () => {
throw new Error(`unexpected/unmocked call to Repository<${entity.name}>.${name}`);
};
const mockRepo: Partial<Repository<T>> = [
'find',
'findOne',
'findOneOrFail',
'save',
'delete',
'remove',
].reduce(
(acc, fnName) => {
acc[fnName] = mkFailFn(fnName);
return acc;
},
{},
);
return {
provide: getRepositoryToken(entity),
useValue: mockRepo,
};
}
Then, for each entity my test module needs, I do .overrideProvider(...)
like I wrote above. Finally, in the unit tests, I mock the return values for the repositories, for example:
const someRepo = testingModule.get<Repository<SomeEntity>>(getRepositoryToken(SomeEntity));
jest.spyOn(someRepo, 'findOneOrFail').mockReturnValueOnce(someEntity)
Hey guys!
I've read the testing part of the database documentation but I could not find any hint or best practice for creating the
mockRepository
object.I would like to write tests where I mock the database layer of the service (e.g.: the
adminRepository
of theAuthService
) by providing good ol' POJOs as data source. Is this achievable with the current version of TypeORM / Nest?There is a related conversation in typeorm/typeorm#1267, but I couldn't get closer to my desired functionality.
My AuthService looks like this:
// auth.service.ts @Injectable() export class AuthService { constructor( @InjectRepository(Admin) private readonly adminRepository: Repository<Admin>, ) { } findByEmail(email: string): Promise<Admin> { return this.adminRepository.findOne({ where: { email } }); } findById(id: number): Promise<Admin> { return this.adminRepository.findOne(id); } }
The desired output would look like something like this:
// auth.service.spec.ts describe('AuthService', () => { let authService: AuthService; const mockRepository = { data: [ { id: 1, email: '[email protected]', password: '' }, { id: 2, email: '[email protected]', password: '' }, ], }; beforeEach(async () => { const module = await Test.createTestingModule({ providers: [ AuthService, { provide: getRepositoryToken(Admin), useValue: mockRepository, }, ], }).compile(); authService = module.get<AuthService>(AuthService); }); describe('findByEmail', () => { it('should return an Admin with a valid email', async () => { const email = '[email protected]'; const expected = mockRepository.data[1]; const admin = await authService.findByEmail(email); expect(admin).toBe(expected); }); }); });
I really look forward to hear some advices and tips about the pros/cons of this kind of testing strategy, my primary goal is to keep my unit tests as simple and as fast as I can. I really appreciate any help!
@pterblgh pt
This topic is old, but in your case, you need to retrieve your repo by adding:
let authRepository = new Repository<Admin>(getRepositoryToken(Admin));
...
authService = module.get<AuthService>(AuthService);
authRepository = module.get<Repository<Admin>>(getRepositoryToken(Admin));
I spent a ton of time on finding a solution here so I am going to post what I came up with. Its a combination of @quezak solution and providing a mock value.
import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { getRepositoryToken } from "@nestjs/typeorm";
import * as request from 'supertest';
import { UsersModule } from './../src/modules/users/users.module';
import { UserEntity } from "./../src/modules/users/entities/user.entity";
describe('UserController (e2e)', () => {
let app: INestApplication;
const mockUser = new UserEntity({
email: '[email protected]'
});
beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
imports: [
UsersModule
]
})
.overrideProvider(getRepositoryToken(UserEntity))
.useValue({
find: () => mockUser,
findOne: () => mockUser,
save: () => mockUser,
})
.compile();
app = moduleFixture.createNestApplication();
await app.init();
});
I think for me, I had two questions.
1) How do you test with a test DB
Solution:
user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,
) {}
async findAll(): Promise<User[]> {
return await this.userRepository.find();
}
}
user.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UserService } from './user.service';
describe('UserService', () => {
let service: UserService;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [
TypeOrmModule.forRoot(),
TypeOrmModule.forFeature([User]),
],
providers: [UserService],
}).compile();
service = module.get<UserService>(UserService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
2) How do you test with a mocked repository
Solution:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,
) {}
async findAll(): Promise<User[]> {
return await this.userRepository.find();
}
}
user.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { UserRepository } from './user.repository';
import { UserService } from './user.service';
describe('UserService', () => {
let service: UserService;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
UserService,
{
provide: 'UserRepository',
useValue: UserRepository,
},
],
}).compile();
service = module.get<UserService>(UserService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
user.repository.ts
import { EntityRepository, Repository } from 'typeorm';
import { User } from './user.entity';
@EntityRepository(User)
export class UserRepository extends Repository<User> {}
I can't make tests work using Custom repository
.
Having this in my service's constructor:
constructor(
@InjectRepository(UserRepository)
private readonly userRepository: UserRepository,
) {}
Tests does not work. But without the UserRepository
class. I can test the service as well as @pterblgh
Here is a extract of the service's test
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
// imports: [TypeOrmModule.forFeature([User, UserRepository])],
providers: [
UserService,
{
provide: getRepositoryToken(User),
useValue: mockRepository,
},
],
}).compile();
service = module.get<UserService>(UserService);
});
And the test's output:
Nest can't resolve dependencies of the UserService (?). Please make sure that the argument at index [0] is available in the TestModule context.
@mazyvan adding a custom provider directly in the module works only sometimes. To be sure it works, use the overrideProvider
construct mentioned above (for example in my previous comment)
@mazyvan I ran into the same problem, here is what i found to work for me:
My custom repository:
@EntityRepository(User)
export class UserRepository extends Repository<User> {
public async findOneByEmail(email: string): Promise<User> {
return this.findOne({ where: { email } });
}
}
My Service constructor
export class LoginService {
constructor(
@InjectRepository(UserRepository)
private readonly userRepository: UserRepository,
) {}
// ...
}
and the spec file:
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
LoginService,
{ provide: getRepositoryToken(UserRepository), useValue: mockRepository },
],
}).compile();
service = module.get<LoginService>(LoginService);
});
Notice that I get the repositoryToken
for UserRepository
instead of User
Trying to use it for 3 days now.
I'm getting error during creating testing Module:
beforeAll(async () => {
module = await Test.createTestingModule({
imports: [
UserModule
],
controllers: [AuthController],
providers: [
]
})
.overrideProvider(getRepositoryToken(User))
.useValue({})
.compile()
this.authController = module.get<AuthController>(AuthController)
});
Tryed a lot of variants but still the same error in injected file. With postman it all works good. So is there any fix for this?
Error:
TypeError: Cannot read property 'prototype' of undefined
export class UserService {
constructor(@InjectRepository(User)
...
at Object.getRepositoryToken
There is my project
thanks for having this issue!
the solution in https://github.com/nestjs/nest/issues/363#issuecomment-359115921 saved my life :)
One note that I needed to put mock into providers
instead of imports
.
This issue was referenced in a question on Stackoverflow. Here is my solution: https://stackoverflow.com/a/55366343/4694994
@kiwikern I got this error with your code:
Type 'Mock<{ findOne: Mock<any, any[]>; }, []>' is not assignable to type '() => MockType<Repository<any>>'.
Type '{ findOne: Mock<any, any[]>; }' is missing the following properties from type 'MockType<Repository<any>>': manager, metadata, createQueryBuilder, target, and 19 more
@xavi-dev As it says, your mock definition is not complete. That's why in the example there is // @ts-ignore
telling the typescript compiler to ignore the missing properties error in your mock. Alternatively, you can either remove the type definition or define all 23 missing properties.
@kiwikern I got this error with your code:
Type 'Mock<{ findOne: Mock<any, any[]>; }, []>' is not assignable to type '() => MockType<Repository<any>>'. Type '{ findOne: Mock<any, any[]>; }' is missing the following properties from type 'MockType<Repository<any>>': manager, metadata, createQueryBuilder, target, and 19 more
You can avoid typescript errors if you mention that your mock is partial:
export type MockType<T> = {
[P in keyof T]?: jest.Mock<{}>;
};
@VinceOPS I'm having this issue with TypoORM, but cannot see what exactly I shall do.
I have my UsersService with this code:
@Component() export class UsersService { constructor( @InjectRepository(User) private readonly usersRepo: Repository<User> ) {} //...
I written this in the spec file for the test:
//... beforeEach( async () => { const module = await Test.createTestingModule({ components: [ UsersService, { provide: User, useClass: Repository } ], controllers: [ UsersController ], }).compile() //...
But I have no clear what I need to write in
provide
anduserClass
to avoid the message
Error: Nest can't resolve dependencies of the UsersService (?). Please verify whether [0] argument is available in the current context.
Did you figure this out? if yes can you give an example in the same context.
Thanks in advance
@kunal-relan
In this case something like the following should work:
UserService
@Component()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly usersRepo: Repository<User>
) {}
//...
The spec file:
import { getRepositoryToken } from '@nestjs/typeorm';
//...
beforeEach( async () => {
const module = await Test.createTestingModule({
components: [ UsersService, {
provide: getRepositoryToken(User),
useClass: Repository
} ],
controllers: [ UsersController ],
}).compile()
//...
I'm not sure about the useClass: Repository
part, I would mock that out,
but the provide
part has to look like above
How to Solve the Problem
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Hey guys!
I've read the testing part of the database documentation but I could not find any hint or best practice for creating the
mockRepository
object.I would like to write tests where I mock the database layer of the service (e.g.: the
adminRepository
of theAuthService
) by providing good ol' POJOs as data source. Is this achievable with the current version of TypeORM / Nest?There is a related conversation in typeorm/typeorm#1267, but I couldn't get closer to my desired functionality.
My AuthService looks like this:
The desired output would look like something like this:
I really look forward to hear some advices and tips about the pros/cons of this kind of testing strategy, my primary goal is to keep my unit tests as simple and as fast as I can. I really appreciate any help!