Weboldal keresés

typescript - Hogyan tudom kezelni a Zustand persist funkciót a Jest teszteimben?


Jelenleg egy React Native alkalmazást készítek, Zustandot használva az állapotkezelésemhez. A Zustand képes az állapotot tárolásba menteni, az én esetemben a React Native aszinkron tárolójába. Ez jól működik, azonban a tesztek futtatásakor a Zustand persist wrapper-je miatt a Jest tesztcsomagom megbukik.
Egyszerű részlet a Zustand állapotomból:

  persist(
    (set) => ({
      variable: "something",
      changeVariable: (variable: string) => {
        set({ variable });
      }, 
    }),
    {
      name: "async-storage",
      getStorage: () => AsyncStorage,
    }
  )

A tesztem:

describe("<SomeComponent />", () => {
  it("renders default elements", () => {
    const { getByText } = render(<SomeComponent />);
    expect(getByText("Hello World")).toBeInTheDocument();
  });
});

Ha kikommentezem a persist wrappert, a teszt lefut, ebben az állapotban azonban ezt a hibaüzenetet kapom

 TypeError: Cannot read properties of undefined (reading 'bind')

      14 | }
      15 |
    > 16 | export const useStore = create<ZustandState>()(
         |                                                        ^
      17 |     persist(
      18 |       (set) => ({

Megpróbáltam az egész zustandot mockolni a https://docs.pmnd.rs/zustand/guides/testing használatával, de a kötési hiba csak a mockra kerül. Nem vagyok biztos benne, hogy maga a store undefined, és ezért nem engedi a kötést, vagy csak a persist okozza. Azonban nem tudom, hogyan kezeljem ezt. Bárkinek van ötlete, hogyan lehetne ezt megoldani?

Válasz #1

Szóval két napot töltöttem azzal, hogy megpróbáljak kitalálni egy hasonló problémát, szóval remélem, ez neked is működni fog.

Győződj meg róla, hogy a Zustand teszteket a dokumentációhoz hasonlóan állítod be, bár néhány módosítást kellett végrehajtanom annak érdekében, hogy a függvényeket helyesen tudjam exportálni.

A fő javítás akkor látható, amikor a reset függvényt hívjuk, létre kellett hoznom az inicializáló állapot egy mélyklónját. Majd készíteni egy másik mélyklónt abból, amikor a Zustand állapotát állítjuk. Rendkívül furcsa, de működik.

Referencia gyanánt a @react-native-async-storage/async-storage-t használjuk tartós tárolásként. Lehetséges, hogy ez befolyásolja.

Ne felejtsd el a node modulokat sem mock-olni, a fájlnak a __mocks__ mappában kell lennie, és ugyanúgy kell elnevezni, tehát zustand.ts

const { createStore: createStore } = jest.requireActual('zustand') as any;
export const storeResetFns = new Set<() => void>();

export const create = <S>(createState: StateCreator<S>) => {
  return typeof createState === 'function' ? createInternalFn(createState) : createInternalFn;
};

export default create;

const createInternalFn = <S>(createState: StateCreator<S>) => {
  const store = createStore(createState);
  const initialState = _.cloneDeep(store.getState());

  storeResetFns.add(() => {
    /**
      This is a hack to get around persisting 
      This might looks odd, it is. if you pass {initial state} to setState, then initial state gets updates to the current state...
    */
    const t = _.cloneDeep(initialState)
    if(initialState.trips) store.setState(t,true);
  })
  return store;
};

afterEach(() => {
    //clear out state before each test
    storeResetFns.forEach(fn => {
      fn()
    })
  });