Home > Net >  Nestjs mongoose unit test: TypeError: <functionName> is not a function
Nestjs mongoose unit test: TypeError: <functionName> is not a function

Time:04-28

according to this github repo we want to test a user sample
consider this test file :

const mockUser = (
  phone = '9189993388',
  password = 'jack1234',
  id = '3458',
): User => ({
  phone,
  password,
  _id: new Schema.Types.ObjectId(id),
});

const mockUserDoc = (mock?: Partial<User>): Partial<IUserDocument> => ({
  phone: mock?.phone || '9189993388',
  password: mock?.password || 'jack1234',
  _id: mock?._id || new Schema.Types.ObjectId('3458'),
});

const userArray = [
  mockUser(),
  mockUser('Jack', '9364445566', '[email protected]'),
];

const userDocArray = [
  mockUserDoc(),
  mockUserDoc({
    phone: '9364445566',
    password: 'jack1234',
    _id: new Schema.Types.ObjectId('342'),
  }),
  mockUserDoc({
    phone: '9364445567',
    password: 'mac$',
    _id: new Schema.Types.ObjectId('425'),
  }),
];

describe('UserRepository', () => {
  let repo: UserRepository;
  let model: Model<IUserDocument>;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UserRepository,
        {
          provide: getModelToken('User'),
          // notice that only the functions we call from the model are mocked
          useValue: {
            new: jest.fn().mockResolvedValue(mockUser()),
            constructor: jest.fn().mockResolvedValue(mockUser()),
            find: jest.fn(),
            findOne: jest.fn(),
            update: jest.fn(),
            create: jest.fn(),
            remove: jest.fn(),
            exec: jest.fn(),
          },
        },
      ],
    }).compile();

    repo = module.get<UserRepository>(UserRepository);
    model = module.get<Model<IUserDocument>>(getModelToken('User'));
  });

  it('should be defined', () => {
    expect(repo).toBeDefined();
  });

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

  it('should return all users', async () => {
    jest.spyOn(model, 'find').mockReturnValue({
      exec: jest.fn().mockResolvedValueOnce(userDocArray),
    } as any);
    const users = await repo.findAll({});
    expect(users).toEqual(userArray);
  });

  it('should getOne by id', async () => {
    const userId = '324';
    jest.spyOn(model, 'findOne').mockReturnValueOnce(
      createMock<Query<IUserDocument, IUserDocument>>({
        exec: jest.fn().mockResolvedValueOnce(
          mockUserDoc({
            _id: new Schema.Types.ObjectId(userId),
          }),
        ),
      }) as any,
    );
    const findMockUser = mockUser('Tom', userId);
    const foundUser = await repo.findById(new Schema.Types.ObjectId(userId));
    expect(foundUser).toEqual(findMockUser);
  });

and this is the user document file:

export interface IUserDocument extends Document {
  _id: Schema.Types.ObjectId;
  email?: string;
  password: string;
  firstName?: string;
  lastName?: string;
  nationalCode?: string;
  phone: string;
  address?: string;
  avatar?: string;
}

the 1th and 2nd test are passed but the third one throws:

TypeError: this.userModel.findById is not a function also the interface is extended from mongoose Document, the findById function is not recognized in the test.

this is the github repo available. so any help will be appreciated.

CodePudding user response:

Notice how in your UserModel mock you don't provide a mock function for findById

{
  provide: getModelToken('User'),
  // notice that only the functions we call from the model are mocked
  useValue: {
    new: jest.fn().mockResolvedValue(mockUser()),
    constructor: jest.fn().mockResolvedValue(mockUser()),
    find: jest.fn(),
    findOne: jest.fn(),
    update: jest.fn(),
    create: jest.fn(),
    remove: jest.fn(),
    exec: jest.fn(),
    findById: jest.fn(), // <-------------- Add this
  },
},

There needs to be a findById method in that set of methods that you mock.

  • Related