Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing custom hook with recoil atom inside #2292

Open
maliyshock opened this issue Oct 22, 2023 · 0 comments
Open

Testing custom hook with recoil atom inside #2292

maliyshock opened this issue Oct 22, 2023 · 0 comments

Comments

@maliyshock
Copy link

I have a custom hook useImageActions which returns a set of functions

handleAddImages
handleUpdateImagesPosition
handleDelete
handleFinishEdit

Each function makes some things like mutations with GQL, or else and update the state with the result with recoil.

From your documentation i used RecoilObserver and i came up with this solution

describe("", () => {
  it("", async () => {
    const onChange = jest.fn();
    const atom = imagesAtom(PRODUCT_SET_ID);

    const wrapper = ({ children }: PropsWithChildren<{}>) => (
      <RecoilRoot initializeState={({set}) => set(atom, INIT_IMAGES)}>
        <RecoilObserver node={atom} onChange={onChange}/>
        <Providers>
          <MockedProvider addTypename={false} mocks={[mock]}>
            {children}
          </MockedProvider>
          </Providers>
      </RecoilRoot>
    );

    const { result } = renderHook(
      () => useImageActions({ productSetId: PRODUCT_SET_ID }),
      { wrapper },
    );

    await act(async () => {
      await result.current.handleAddImages(ADD_IMAGES);
    });

    expect(onChange).toHaveBeenCalledTimes(2);
    expect(onChange).toHaveBeenCalledWith(INIT_IMAGES);
    expect(onChange).toHaveBeenCalledWith([...INIT_IMAGES, ...ADD_IMAGES]);
  });
});

As you can see i initialized first state with initializeState, i also provided atom to the observer
I ve been using renderHook which gonna be rendered behind the scene in some test component.
For my atom i use families because i need to, and PRODUCT_SET_ID is unique ID for each "family" for that purposes.
I am using the same PRODUCT_SET_ID for atom, and i am using the same imagesAtom as i use in the project.

it looks like this

export const imagesAtom = atomFamily<ExtendedImage[], string>({
  key: "images",
  default: [],
});

My hook uses this atom as well inside, to provide a possibility to the functions (image actions) to change the state.

So basically, my expectations that the hook and RecoilRoot and RecoilObserver should share the same atom family, because all of them use the same imagesAtom and all of them have the same PRODUCT_SET_ID. But i guess it is not true

The issue
It looks like they are disconnected.
During the test when i invoke

   await act(async () => {
      await result.current.handleAddImages(ADD_IMAGES);
    });

I get
amount of calls 1
and last toHaveBeenCalledWith does not have ADD_IMAGES its still just have INIT_IMAGES only

My question is how can i make this kind of connection in the right way? What am i missing?
Or what i am doing it is an antipattern and it should be used in some other way?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant