Jest: Cannot spy the property because it is not a function; undefined given instead getting error while executing my test cases

Viewed 14417
           This is my controller class(usercontoller.ts) i am trying to write junit test cases for this class  

            import { UpsertUserDto } from '../shared/interfaces/dto/upsert-user.dto';
            import { UserDto } from '../shared/interfaces/dto/user.dto';
            import { UserService } from './user.service';
                async updateUser(@BodyToClass() user: UpsertUserDto): Promise<UpsertUserDto> {
                    try {
                        if (!user.id) {
                            throw new BadRequestException('User Id is Required');
                        }
                        return await this.userService.updateUser(user);
                    } catch (e) {
                        throw e;
                    }
                } 

This is my TestClass(UserContollerspec.ts) while running my test classes getting error " Cannot spy the updateUser property because it is not a function; undefined given instead. getting error. However, when I use spyOn method, I keep getting TypeError: Cannot read property 'updateuser' of undefined:

*it seems jest.spyOn() not working properly where i am doing mistake. could some one please help me.the argument which I am passing ?

    jest.mock('./user.service');

        describe('User Controller', () => {
            let usercontroller: UserController;
            let userservice: UserService;
            // let fireBaseAuthService: FireBaseAuthService;
            beforeEach(async () => {
                const module: TestingModule = await Test.createTestingModule({
                    controllers: [UserController],
                    providers: [UserService]
                }).compile();

                usercontroller = module.get<UserController>(UserController);

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

            afterEach(() => {
                jest.resetAllMocks();
            });

         describe('update user', () => {
             it('should return a user', async () => {
               //const result = new  UpsertUserDto();
               const testuser =  new  UpsertUserDto();
               const mockDevice = mock <Promise<UpsertUserDto>>();
               const mockNumberToSatisfyParameters = 0;
               //const userservice =new UserService();
               //let userservice: UserService;
                jest.spyOn(userservice, 'updateUser').mockImplementation(() => mockDevice);
              expect(await usercontroller.updateUser(testuser)).toBe(mockDevice);

          it('should throw internal  error if user not found', async (done) => {
            const expectedResult = undefined;
             ****jest.spyOn(userservice, 'updateUser').mockResolvedValue(expectedResult);****
             await usercontroller.updateUser(testuser)
              .then(() => done.fail('Client controller should return NotFoundException error of 404 but did not'))
              .catch((error) => {
                expect(error.status).toBe(503);
                expect(error.message).toMatchObject({error: 'Not Found', statusCode: 503});  done();
            });
        });
        });
        });
1 Answers

More than likely, your UserService class has other dependencies and as such, Nest cannot instantiate the UserService class. When you are trying to do userService = module.get(UserService) you are retrieving an undefined hence the error about jest.spyOn(). In unit tests, you should be providing a mock provider to take the place of your actual provider, like so:

describe("User Controller", () => {
  let usercontroller: UserController;
  let userservice: UserService;
  // let fireBaseAuthService: FireBaseAuthService;
  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [UserController],
      providers: [
        {
          provide: UserService,
          useValue: {
            updateUser: jest.fn(),
            // other UserService methods
          }
        }
      ],
    }).compile();

    usercontroller = module.get<UserController>(UserController);

    userservice = module.get<UserService>(UserService);
  });
  // rest of tests
});

Now when you retrieve the UserService you'll have an object with the proper functions back, which can then be jest.spyOned and mocked

Related