Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot spyOn on a primitive value; undefined given in nestJS

I know this question is asked before but I'm having this error in nestjs when I run service test function

here is my service code

user.service.ts

import { Injectable,HttpException, HttpCode, HttpStatus  } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
import { UserRegisterAC } from '../application/userRegisterAC';

@Injectable()
export class UserService {

constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>) {}

async allUsersList(): Promise<User[]> {
 var users = this.userRepository.find();

 if(users==null){
  throw new HttpException("Users not found",HttpStatus.NOT_FOUND)
 }else{
  return users as unknown as User[];
 }
}

async create(userDTO: UserRegisterAC): Promise<User> {
const user = new User();

user.name = userDTO.name;
user.phoneNo = userDTO.phoneNo;
return this.userRepository.save(user);
}
}

user.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { UserService } from './user.service';


describe('UserService', () => {
let service: UserService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
  providers: [UserService],
}).compile();

service = module.get<UserService>(UserService);
});

it('should return user array', async() => {
const result = [{id:1,name:'mayur',phoneNo:'9998814695'}];
// @ts-ignore
jest.spyOn(service,'allUsersList').mockImplementation(() => result); 
expect(await service.allUsersList()).toBe(result);
 });
});

In this file I want test allUserlist function in user service which return array of user. user entity contain id,name and phoneNo. when I run test I'm getting error like

Cannot spyOn on a primitive value; undefined given

  17 |     const result = [{id:1,name:'mayur',phoneNo:'9998814695'}];
  18 |     // @ts-ignore
> 19 |     jest.spyOn(service,'allUsersList').mockImplementation(() => result);
     |          ^
  20 |     expect(await service.allUsersList()).toBe(result);
  21 |   });
  22 | });

Here is my jest config

{
 "moduleFileExtensions": ["js", "json", "ts"],
 "rootDir": ".",
 "testEnvironment": "node",
 "testRegex": ".spec.ts$",
 "transform": {
 "^.+\\.(t|j)s$": "ts-jest"

},
"automock": true

}

I tried everything please give some suggestion

like image 442
mayur.p Avatar asked Jul 10 '20 07:07

mayur.p


2 Answers

There's a couple of things that I notice here.

  1. you're mocking the class that you're testing, meaning your tests are meaningless. You should instead mock the dependencies of it.

  2. You aren't mocking the dependencies of your class, so Nest cannot instantiate the class for you, meaning you are getting an undefined instead of a class.

To fix this, you'll want to do something like this:

beforeEach(async () => {
  const modRef = await Test.createTestingModle({
    providers: [
      UserService,
      {
        provide: getRepositoryToken(User),
        useClass: Repository,
      }
    ]
  }).compile();
  service = modRef.get(UserService);
  repository = modRef.get<Repository<User>>(getREpositoryToken(User));
});

And now you can mock the repository methods while still using the service to test the coverage.

There's a more in depth answer here and a repository full of test examples here. Feel free to take a look and dive a bit deeper.

like image 129
Jay McDoniel Avatar answered Sep 20 '22 06:09

Jay McDoniel


Your allUsersList will endup under the prototype in the service , kindly try

jest.spyOn(service.prototype,'allUsersList').mockImplementation(() => result); 
like image 35
PersianIronwood Avatar answered Sep 18 '22 06:09

PersianIronwood