如何使用 useEffect 内的事件侦听器测试自定义钩子?

时间:2021-04-07 17:58:53

标签: reactjs react-native testing jestjs listener

我使用 react native 和 jest 来创建我的测试。我在测试侦听来自 expo-linking 的 url 事件的事件侦听器时遇到了问题。此事件侦听器位于 useEffect 钩子内。

下面是我的自定义钩子的代码,里面有我的 useEffect 和一个事件监听器:

useEffect(() => {
    isMounted.current = true;
    Linking.addEventListener('url', async () => {
      try {
        if (!navigation.isFocused() || !isMounted.current) return;

        setIsLoading(true);

        const response = await api.get('sessions/auth/success');

        if (!response.data) return;

        console.log('aqui');

        const { notRegisteredUser, token } = response.data;

        api.defaults.headers.authorization = `Bearer ${token}`;

        if (notRegisteredUser && token) {
          setIsLoading(false);
          navigation.navigate('BirthDateScreen');

          dispatch(
            updateUser({
              ...notRegisteredUser,
            }),
          );
        }
      } catch (err) {
        Alert.alert('Error', `${translate('loginRegisterError')}: `, err);
      }
    });
    return () => {
      isMounted.current = false;
    };
  }, [dispatch, navigation]);

在我的测试文件中,我有以下模拟:

jest.mock('expo-linking', () => {
  return {
    addEventListener: (event: string, callback: () => void) => callback(),
  };
});

jest.mock('@react-navigation/native', () => {
  return {
    useNavigation: () => ({
      isFocused: mockedNavigationFocus,
      navigate: mockedNavigation,
    }),
  };
});

jest.mock('react-redux', () => {
  return {
    useDispatch: jest.fn(),
  };
});

jest.mock('../../../store/modules/user/actions', () => {
  return {
    updateUser: jest.fn(),
  };
});

jest.mock('i18n-js', () => {
  return {
    locale: 'en',
    t: () => 'any key',
  };
});

最后,这是我第一次尝试时的测试结果:

it('should pass the test', async done => {
  mockedNavigationFocus.mockImplementation(() => true);

  apiMock.onGet('sessions/auth/success').reply(200, {
    notRegisteredUser: { name: 'Logan' },
    token: '123',
  });

  render(<LoginScreen />);

  
  await waitFor(() =>
    expect(mockedNavigation).toHaveBeenCalledWith('BirthDateScreen'),
  );

  done();
});

在我的第二次尝试中,这是我的测试的样子(我使用了来自 @testing-library/react-hooks 的 renderHooks):

it('should pass the test', async ()  => {
  mockedNavigationFocus.mockImplementation(() => true);

  apiMock.onGet('sessions/auth/success').reply(200, {
    notRegisteredUser: { name: 'Logan' },
    token: '123',
  });


  const { result, waitForValueToChange } = renderHook(() => useLoginButton());

  const { isLoading } = result.current;

 
  await waitForValueToChange(() => isLoading);
  await waitForValueToChange(() => isLoading);

  expect(mockedNavigation).toHaveBeenCalledWith('BirthDateScreen');

});

通过这两个测试,我得到以下错误: test error

我得到的另一个错误是我的 useEffect 中的回调函数在它停止之前运行了很多次,而这在我不测试时不会发生。

有谁知道我该如何编写这个测试?

0 个答案:

没有答案