#mock function returns undefined

17 messages · Page 1 of 1 (latest)

faint olive
#

Hi i'm testing a function with few function dependencies been mocked and when i run the test it always returns undefined i've even debugged it and didn't understand the cause. it happens on the method of repistory typeorm "repository.save".
here is the code:

const oneCrop = new Crop();
oneCrop.id = expect.any(Number);
oneCrop.name = "avocado";
oneCrop.color = "green";
oneCrop.typeId = 1;
oneCrop.type = expect.any(CropType);
oneCrop.strains = expect.any(Array<CropStrain>);
const updateCrop = new Crop;
updateCrop.id = expect.any(Number);
updateCrop.name = "banana";
updateCrop.color = "yellow";
updateCrop.typeId = 3;
updateCrop.type = expect.any(CropType);
updateCrop.strains = expect.any(Array<CropStrain>);

const oneCropType = new CropType();
oneCropType.id = 3;
oneCropType.name = "Gidulim";

const mockRepository = {
    save: jest.fn((crop: Crop) => Promise.resolve(crop)),
    find: jest.fn(),
    findOne: jest.fn()
};
const mockConnectionService = {
    getStrainsByProject: jest.fn(projectId => []),
    getCropTypeById: jest.fn(id => Promise.resolve(oneCropType))
};

describe("Crop Service", () => {
    let cropService: CropService;
    beforeAll(async () => {
        const module: TestingModule = await Test.createTestingModule({
            providers: [
                CropService,
                {
                    provide: getRepositoryToken(Crop),
                    useValue: mockRepository
                },
                {
                    provide: CropsConnectionService,
                    useValue: mockConnectionService
                }
            ],
        }).compile();

        cropService = module.get<CropService>(CropService);
    });
#

and here the test:

describe("update", () => {
        let func;
        let spyCropId;
        describe("successfull call", () => {
            beforeAll(async () => {
                mockRepository.findOne.mockImplementationOnce((options: FindOneOptions<Crop>) => Promise.resolve(oneCrop));
                spyCropId = jest.spyOn(cropService, "getCropById");
                func = await cropService.update(1, { name: "banana", color: "yellow", typeId: 3 });
            });
            afterAll(() => {
                spyCropId.mockRestore();
                oneCrop.name = "avocado";
                oneCrop.color = "green";
                oneCrop.typeId = 1;
            });

            it("should return a crop object", () => {
                console.log(func);
                expect(func).toEqual(updateCrop);

            });
#

the update method:

  async update(
    id: number,
    updateCropDTO: UpdateCropDto) {
    let result = null;

    console.log(`CropService : update()  crop ${id} `);
    let cropEntity = await this.getCropById(id, "all")
    this.validator.checkEntity(cropEntity)

    if (cropEntity.typeId != updateCropDTO.typeId) {
      let newCropTypeObject = await this.cropsConnectionService.getCropTypeById(updateCropDTO.typeId)
      this.validator.checkEntity(newCropTypeObject)
    }
    cropEntity.typeId = updateCropDTO.typeId;
    cropEntity.name = updateCropDTO.name;
    cropEntity.color = updateCropDTO.color;

    result = await this.repository.save(cropEntity);

    return result;

  };
proper kettle
#

What does this.getCropById() do? You most likely don't mock what that method is supposed to return (by mocking its dependencies) and so you're trying to do undefiend.typeId = updateCropDTO.typeId

faint olive
#
  getCropById(
    id: number,
    relationsStr: relationsType = "none"): Promise<Crop> {
    let result = null
    let relatios = this.getRelationsRequest(relationsStr);
    //if (id <= 0)
    //  throw Error("Crop id cannot be negative");
    return this.repository.findOne({
      where: {
        id: id,
      },
      relations: relatios
    });
  }

this method is inside cropService so i didn't want to mock this one but because it uses findOne i mocked the implementation for it with:

mockRepository.findOne.mockImplementation((options: FindOneOptions<Crop>) => Promise.resolve(oneCrop));
#

this oneCrop object is defined in the description i provided

proper kettle
#

AH, yep. Missed that. Let me keep looking at the above

faint olive
#

maybe because i defined some properties as expect.any(Number) it might does that? although there isn't any use of id there. i tried to change to another object and it throw an aexception

proper kettle
#

I mean, it's weird to set properties to that if you're not expect(whatever).toEqual({ id: expcet.any(Number) }), but I don't think it would cause this issue

#

So, when this assertion runs, you get that func is undefined? expect(func).toEqual(updateCrop);

#

What if you move everything out of the beforeAll and into the it? I don't usually see services actually called in the before* methods, usually just test setup

faint olive
#

yes I get tha func is undefined when running debugger the entity changes it's properties but when repository.save runs it returns undefined for some reason the implentation is just (crop)=>Promise.resolve(crop)

proper kettle
#

Got a reproduction of this? Or code access you can share?

faint olive
proper kettle
#

Whatever I will need to run and understand the test

faint olive
proper kettle
#
    describe("incorrect values in update", () => {
      let spyCropId;
      beforeAll(async () => {
        mockRepository.findOne.mockImplementation((options: FindOneOptions<Crop>) => Promise.resolve(oneCrop));
        spyCropId = jest.spyOn(cropService, "getCropById");
      });
      afterAll(() => {
        spyCropId.mockRestore();
      });
      it("should fails and throws an exception for invalid name", async () => {
        await expect(cropService.update(1, { name: "123123", color: "yellow", typeId: 3 })).rejects.toThrow(Error);
      });
      it("should fails and throws an exception for invalid name", async () => {
        await expect(cropService.update(1, { name: "@$@\n", color: "yellow", typeId: 3 })).rejects.toThrow(Error);
      });
      json.forEach(word => {
          it("should throw error for invalid name " + word, async () => {
              await expect(cropService.update(1, { name: word, color: "yellow", typeId: 3 })).rejects.toThrow(Error);
          });
      });
      it("should fails and throws an exception for invalid color", async () => {
        await expect(cropService.update(1, { name: "banana", color: "yell", typeId: 3 })).rejects.toThrow(Error);
      });
      it("should fails and throws an exception for invalid negative typeId", async () => {
        await expect(cropService.update(1, { name: "banana", color: "yellow", typeId: -5 })).rejects.toThrow(Error);
      });
      it("should fails and throws an exception for invalid overflow typeId number", async () => {
        await expect(cropService.update(1, { name: "123123", color: "yellow", typeId: Number.MAX_VALUE + 21312321 })).rejects.toThrow(Error);
      });
    });
  });

Why are you expecting these to reject? With this ode for update

  async update(
    id: number,
    updateCropDTO: UpdateCropDto) {
    let result = null;

    console.log(`CropService : update()  crop ${id} `);
    let cropEntity = await this.getCropById(id, "all")
    this.validator.checkEntity(cropEntity)

    if (cropEntity.typeId != updateCropDTO.typeId) {
      let newCropTypeObject = await this.cropsConnectionService.getCropTypeById(updateCropDTO.typeId)
      this.validator.checkEntity(newCropTypeObject)
    }
    cropEntity.typeId = updateCropDTO.typeId;
    cropEntity.name = updateCropDTO.name;
    cropEntity.color = updateCropDTO.color;

    result = await this.repository.save(cropEntity);

    return result;

  };

I don't see why an error would be thrown