Hi guys,
Could you thell how you do unit tests when are using CRUD package?
I try to do it as follows, but it doesn't work.
This is my service:
@Injectable()
export class AddressService extends TypeOrmCrudService<Address> {
constructor(@InjectRepository(Address) repo) {
super(repo);
}
}
This is my test class:
describe('AddressService', () => {
let module: TestingModule;
let addressService: AddressService;
let addressRepositoryMock: MockType<Repository<Address>>;
const req: CrudRequest = { parsed: null, options: null };
const createDto: Address = {Omitted: ''};
const addressMock: Address = {Omitted: ''};
beforeEach(async () => {
module = await Test.createTestingModule({
providers: [
AddressService,
{
provide: getRepositoryToken(Address),
useFactory: repositoryMockFactory,
},
],
}).compile();
addressService = module.get<AddressService>(AddressService);
addressRepositoryMock = module.get(getRepositoryToken(Address));
});
afterEach(() => {
jest.resetAllMocks();
});
describe('create Address', () => {
it('should calls addressRepository.save() and returns the result', async () => {
addressRepositoryMock.save.mockReturnValue(addressMock);
expect(addressService.createOne).not.toHaveBeenCalled();
const result = await addressService.createOne(req, createDto);
expect(result).toEqual(addressMock);
});
});
});
What's wrong?
FAIL src/modules/address/address.service.spec.ts
● AddressService › create Address › should calls addressRepository.save() and returns the result
TypeError: Cannot read property 'columns' of undefined
8 | export class AddressService extends TypeOrmCrudService<Address> {
9 | constructor(@InjectRepository(Address) repo) {
> 10 | super(repo);
| ^
11 | }
12 |
13 | public async findAddress(address: Address): Promise<Address> {
at AddressService.onInitMapEntityColumns (../node_modules/@nestjsx/crud-typeorm/src/typeorm-crud.service.ts:327:45)
at new TypeOrmCrudService (../node_modules/@nestjsx/crud-typeorm/src/typeorm-crud.service.ts:31:10)
at new AddressService (modules/address/address.service.ts:10:3)
at Injector.instantiateClass (../node_modules/@nestjs/core/injector/injector.js:276:19)
at callback (../node_modules/@nestjs/core/injector/injector.js:74:41)
at Injector.resolveConstructorParams (../node_modules/@nestjs/core/injector/injector.js:113:24)
at Injector.loadInstance (../node_modules/@nestjs/core/injector/injector.js:78:9)
at Injector.loadProvider (../node_modules/@nestjs/core/injector/injector.js:35:9)
at async Promise.all (index 3)
● AddressService › create Address › should calls addressRepository.save() and returns the result
TypeError: Cannot read property 'save' of undefined
56 | describe('create Address', () => {
57 | it('should calls addressRepository.save() and returns the result', async () => {
> 58 | addressRepositoryMock.save.mockReturnValue(addressMock);
| ^
59 | expect(addressService.createOne).not.toHaveBeenCalled();
60 | const result = await addressService.createOne(req, createDto);
61 | expect(result).toEqual(addressMock);
at Object.<anonymous> (modules/address/address.service.spec.ts:58:26)
Test Suites: 1 failed, 1 passed, 2 total
Could any Jedi Master help me?
Have you tried searching? There were already a couple of similar issues:
https://github.com/nestjsx/crud/issues/33
https://github.com/nestjsx/crud/issues/207
Appearantly your repositoryMockFactory is producing repository mocks which are missing columns property and save method. Here is a simple solution:
describe('ArtistsService', () => {
let service: ArtistsService;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [ArtistsService, {
provide: getRepositoryToken(Artist),
useValue: {
save: jest.fn(),
metadata: {
columns: [{
propertyName: 'id',
isPrimary: true
}],
relations: []
}
}
}]
}).compile();
service = module.get<ArtistsService>(ArtistsService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
I have my own RepositoryMock Class to test my code, feel free to use it :) (just use useClass instead of useValue):
export class MockRepository<T> {
public createQueryBuilder = jest.fn(() => this.queryBuilder);
public manager = { transaction: a => Promise.resolve(a()) };
public save = jest.fn();
public delete = jest.fn();
public update = jest.fn();
public findOne = jest.fn();
public findOneOrFail = jest.fn();
public find = jest.fn();
public getMany = jest.fn();
public queryBuilder = {
offset: jest.fn().mockReturnThis(),
take: jest.fn().mockReturnThis(),
orderBy: jest.fn().mockReturnThis(),
skip: jest.fn().mockReturnThis(),
limit: jest.fn().mockReturnThis(),
from: jest.fn().mockReturnThis(),
addFrom: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
andWhere: jest.fn().mockReturnThis(),
innerJoinAndSelect: jest.fn().mockReturnThis(),
leftJoinAndSelect: jest.fn().mockReturnThis(),
getManyAndCount: jest.fn(),
getMany: jest.fn(),
getOne: jest.fn(),
delete: jest.fn().mockReturnThis(),
execute: jest.fn().mockReturnThis()
};
}
@Darkein This would be incredibly useful to put in the actual library
It's more related to Typeorm than NestJsx, and it depends which testing framework you use.
Today i use sqljs to run my unit tests, to be sure to get the correct datas.
The counterpart is it works only with basic entities (no bigint or JSON attributes, for exemple)
Most helpful comment
I have my own RepositoryMock Class to test my code, feel free to use it :) (just use
useClassinstead ofuseValue):