Crud: Unit Tests in Crud Nestjs

Created on 14 Nov 2019  ·  4Comments  ·  Source: nestjsx/crud

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?

duplicate

Most helpful comment

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()
  };
}

All 4 comments

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)

Was this page helpful?
0 / 5 - 0 ratings