0

Similar to How to test custom async/await hook with react-hooks-testing-library and Testing async custom hooks that useEffect with react-hooks-testing-library but I am trying to get rid of the act warnings (the tests themselves pass).

I have the hook

import AsyncStorage from "@react-native-async-storage/async-storage";
import {
    Dispatch,
    SetStateAction, useEffect, useState
} from "react";

/**
 * If the value is null on storage it will not use the state.  This is limited to strings.
 * @param storageKey AsyncStorage key
 * @param initialState initial state if not available in the storage.  If it is in the storage the value in the storage will be used.
 */
export function useStoredState(
  storageKey: string,
  initialState: (string | null) | (() => string | null)
): [string | null, Dispatch<SetStateAction<string | null>>] {
  const [state, setState] = useState<string | null>();
  useEffect(() => {
    (async () => {
      if (state === undefined) {
        const val = await AsyncStorage.getItem(storageKey);
        if (val !== null) {
          setState(val);
        } else {
          setState(initialState);
        }
      } else if (state === null) {
        await AsyncStorage.removeItem(storageKey);
      } else {
        await AsyncStorage.setItem(storageKey, state);
      }
    })();
  }, [storageKey, setState, state]);
  if (state === undefined && typeof initialState === "function") {
    return [
      initialState(),
      setState as Dispatch<SetStateAction<string | null>>,
    ];
  } else if (state === undefined && typeof initialState !== "function") {
    return [initialState, setState as Dispatch<SetStateAction<string | null>>];
  } else {
    return [
      state as string | null,
      setState as Dispatch<SetStateAction<string | null>>,
    ];
  }
}

I mocked AsyncStorage as follows

import AsyncStorage from '@react-native-async-storage/async-storage/jest/async-storage-mock';
export default AsyncStorage;

The test I have that works but has act errors is.

it.only("should work like normal with async storage check", async () => {
  const { result, unmount } = renderHook(() => useStoredState("foo", "bar"));
  let [state, setState] = result.current;
  expect(state).toBe("bar");
  act(() => setState("foo"));
  [state] = result.current;
  expect(state).toBe("foo");
  expect(await AsyncStorage.getItem("foo")).toBe("foo");
  unmount();
});

I have more complicated tests that use await waitForNextUpdate(), but this is the simplest one that shows the problem. enter image description here

Archimedes Trajano
  • 35,625
  • 19
  • 175
  • 265

0 Answers0