BuGaGa
BuGaGa

Reputation: 449

Why doesn't Jest spy on the function?

I wrote a simple custom Hook:

import { IsValueAlreadyRegistered } from "../../entities/registration/actions";

export const useForgetPassword = () => {
  const activeStep = 0;
  const email = "[email protected]";

  const nextStep = (): void => {
    let isThereError: boolean = false;

    switch (activeStep) {
      case 0:
        if (!isThereError) {
          IsValueAlreadyRegistered(email, "isEmailRegistered");
        }
        break;
    }
  };

  return { nextStep };
};

It has only one function that I import. I want to spy on it and make sure that it is called with the expected arguments.

This is my test:

import { renderHook } from "@testing-library/react";
import { useForgetPassword } from ".";
import * as Registered from "../../entities/registration/actions";

describe("useForgetPassword", () => {
  const { result } = renderHook(() => useForgetPassword());

  const IsValueAlreadyRegisteredMock = jest.fn();

  test("nextStep", () => {
    jest
      .spyOn(Registered, "IsValueAlreadyRegistered")
      .mockReturnValue(IsValueAlreadyRegisteredMock);

    const { nextStep } = result.current;
    nextStep();

    expect(IsValueAlreadyRegisteredMock).toBeCalledWith(
      "[email protected]",
      "isEmailRegistered"
    );
  });
});

I checked the path where I import the function IsValueAlreadyRegistered and the path I want to spy on, they match.

Here is the function code IsValueAlreadyRegistered:

import { registrationFormSlice } from ".";
import { AppDispatch } from "../store";

const { setEmail } = registrationFormSlice.actions;

export const IsValueAlreadyRegistered =
  (value: string, process: string) => async (dispatch: AppDispatch) => {
    switch (process) {
      case "isEmailRegistered":
        dispatch(setEmail({ value, error: false, text: "" }));
        break;
    }
  };

The problem is that Jest indicates that the IsValueAlreadyRegistered function is not called. I don't understand why?

enter image description here

I followed the code execution and made sure that the function IsValueAlreadyRegistered is called and the arguments I need are passed to it:

enter image description here

I suggest that this may be due to the use of dispatch: AppDispatch in IsValueAlreadyRegistered, since when executing the code, the debugger did not switch to the IsValueAlreadyRegistered function. But when you spy on a function, does it have to execute the code of that function? In my opinion, no, it is replaced by just.fn().

I also assume that maybe I'm using it incorrectly :

jest
      .spyOn(Registered, "IsValueAlreadyRegistered")
      .mockReturnValue(IsValueAlreadyRegisteredMock);

Tell me where I made a mistake, I'm sure it's some little thing, but I can't see it. Thank you very much in advance for any help!

Upvotes: 1

Views: 370

Answers (1)

Lin Du
Lin Du

Reputation: 102467

The assertion is wrong, Registered.IsValueAlreadyRegistered is called with "[email protected]" and "isEmailRegistered" parameters.

The mock return value of Registered.IsValueAlreadyRegistered is the IsValueAlreadyRegisteredMock function, it's not called. Your code seems not correct, I guess the IsValueAlreadyRegistered is a redux thunk based on its function signature. So a thunk should be called correctly like:

const dispatch = useDispatch();
dispatch(IsValueAlreadyRegistered(email, 'isEmailRegistered'))

So that the internal function(IsValueAlreadyRegisteredMock) will be called by the redux-thunk middleware.

Anyway, check the correct assertion.

describe("useForgetPassword", () => {
  const { result } = renderHook(() => useForgetPassword());
  const IsValueAlreadyRegisteredMock = jest.fn();

  test("nextStep", () => {
    jest
      .spyOn(Registered, "IsValueAlreadyRegistered")
      .mockReturnValue(IsValueAlreadyRegisteredMock)

    const { nextStep } = result.current;
    nextStep();

    expect(Registered.IsValueAlreadyRegistered).toBeCalledWith(
      "[email protected]",
      "isEmailRegistered"
    );
  });
})

Upvotes: 0

Related Questions