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

how to reset atom in unit test? #496

Closed
chj-damon opened this issue May 25, 2021 · 7 comments
Closed

how to reset atom in unit test? #496

chj-damon opened this issue May 25, 2021 · 7 comments

Comments

@chj-damon
Copy link

chj-damon commented May 25, 2021

I know I can follow the doc here: https://docs.pmnd.rs/jotai/guides/resettable in my code to achieve this.
But I'm writing unit tests in my project, which it appears that the atom value would be persisted somehow, but I think all the atom values used in different unit tests should not be the same.

my hook is defined below:

export const stepAtom = atom(0);

export function useOnBoardingService() {
  const { width } = useWindowDimensions();
  const [currentIndex, updateStep] = useAtom(stepAtom);

  const slidePrev = useCallback(() => {
    if (currentIndex !== 0) {
      const step = currentIndex - 1;
      updateStep(step);
    }
  }, [currentIndex, updateStep]);

  const slideNext = useCallback(() => {
    if (currentIndex !== 3) {
      const step = currentIndex + 1;
      updateStep(step);
    }
  }, [currentIndex, updateStep]);

  return {
    slidePrev,
    slideNext,
  };
}

and my unit test is below:

import { renderHook, act } from '@testing-library/react-hooks';
import { useAtomValue } from 'jotai/utils';
import { useOnBoardingService, stepAtom } from './useOnBoardingService';

test('should useOnBoardingService', () => {
  const { result } = renderHook(() => useOnBoardingService());
  expect(typeof result.current.slidePrev).toBe('function');
});

test('should step be 1', () => {
  const { result } = renderHook(() => useOnBoardingService());
  const { result: stepResult } = renderHook(() => useAtomValue(stepAtom));

  expect(stepResult.current).toBe(0);

  act(() => {
    result.current.slideNext();
  });

  expect(stepResult.current).toBe(1);
});

test('should step be 1 too', () => {
  const { result } = renderHook(() => useOnBoardingService());
  const { result: stepResult } = renderHook(() => useAtomValue(stepAtom));

  // I want this to be 0 but it actually is 1 because atom value changed after the above test executed
  expect(stepResult.current).toBe(0); 

  act(() => {
    result.current.slideNext();
  });

  // actual value would be 2
  expect(stepResult.current).toBe(1);
});
@dai-shi
Copy link
Member

dai-shi commented May 25, 2021

atomWithReset is not primarily for testing. Provider is.
jotai is based on react context and to isolate state within memory, we need to use <Provider>.

According to https://react-hooks-testing-library.com/usage/advanced-hooks#context

import { Provider } from 'jotai'

const wrapper = ({ children }) => <Provider>{children}</Provider>

This may help.

@chj-damon
Copy link
Author

I tried with Provider but it fails all my tests.

test('should increment step', () => {
  const wrapper = ({ children }: any) => <Provider>{children}</Provider>;

  const { result } = renderHook(() => useOnBoardingService(), { wrapper });
  const { result: stepResult } = renderHook(() => useAtomValue(stepAtom));

  expect(stepResult.current).toBe(0);

  act(() => {
    result.current.slideNext();
  });

  expect(stepResult.current).toBe(1);
});

// Expected: 1
// Received: 0

furthermore, there's an error occurred:
image

Am I missing something here?

@dai-shi
Copy link
Member

dai-shi commented May 25, 2021

My comment was too naive. Here I made the codesandbox example.
https://codesandbox.io/s/zealous-heyrovsky-w1u4t?file=/src/useOnBoardingService.test.tsx
You need to create two hooks under the same Provider.

For the act() warning, it's probably the same one we had in tests in our repo. Currently worked around, but we'd need to investigate for a proper fix for it. help wanted for this.

@chj-damon
Copy link
Author

Thanks, it works perfectly now. the act() warning has gone too. I think this may answer 252 of how to write unit tests.

@dai-shi
Copy link
Member

dai-shi commented May 26, 2021

Yeah, we should write some docs wrt #252. This issue helped understanding the usage. Thanks!

@chj-damon
Copy link
Author

besides, I think it's better to write logic code in custom hooks separately, instead of writing theme in components.

@dai-shi
Copy link
Member

dai-shi commented May 26, 2021

I'd personally do that even with useState. It's more about how you organize your code in React in general.
The library is rather unopinionated about the code structure. Happy to see someone come up with best practices.

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

2 participants