testing-library/react-hooks-testing-library

Testing async setState

binyellow opened this issue · 1 comments

What is your question:

I wrote a hook to return a function, and after executing the returned function, change the state according to the promise state, but I can't get the latest state in the test

// hooks file
import useMergedState from "rc-util/lib/hooks/useMergedState";
import { useCallback } from "react";
import { useRequestLoadingProps, useRequestLoadingRes } from "./index.type";

function isThenable(thing?: PromiseLike<any>): boolean {
  return !!(thing && !!thing.then);
}

const useRequestLoading = (props: useRequestLoadingProps): useRequestLoadingRes => {
  const { fn, loading: oLoading } = props;
  const [loading, setLoading] = useMergedState(false, { value: oLoading });

  const next = useCallback(() => {
    let returnValueOfFn = typeof fn === "function" ? fn?.() : null;
    if (!isThenable(returnValueOfFn)) {
      return;
    }
    setLoading(true);
    returnValueOfFn!.finally(() => {
      setLoading(false);
    });
  }, []);

  return [next, loading, { setLoading }];
};
export default useRequestLoading;
// test file
import { act, renderHook } from "@testing-library/react-hooks";
import useRequestLoading from "../useRequestLoading";

export function request(t = 1000, req, data) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("timer call ===>", t, data);
      if (req === 0) {
        reject(new Error(data || "fail"));
      } else {
        resolve(data || "success");
      }
    }, t);
  });
}

export function sleep(t) {
  return request(t);
}

export const getCurrent = (hook) => hook?.result?.current;

test("测试requestLoading", async () => {
  const requestLoading = (props) => {
    return renderHook(() => useRequestLoading(props));
  };

  const fn = () => request(1000, 1, { ret: 0, message: "success!" });
  let hook;
  let current;

  jest.useFakeTimers();
  act(() => {
    hook = requestLoading({ fn });
  });

  await act(async () => {
    current = getCurrent(hook);
    current[0]();
    // **This should be loading, but I don't know why I can't get the latest state**
    console.log(1, current);
    jest.runAllTimers();
  });
  console.log(2, current);
});

The definition of hook needs to be advanced