1

我正在为我的应用程序编写一些测试,并且正在尝试模拟Linking模块。我正在使用jest. 模拟Linking.canOpenURL它工作正常(toHaveBeenCalled正在返回true),但openURL永远不会调用模拟。

    function mockSuccessLinking() {
      const canOpenURL = jest
        .spyOn(Linking, 'canOpenURL')
        .mockImplementation(() => Promise.resolve(true));
      const openURL = jest
        .spyOn(Linking, 'openURL')
        .mockImplementation(() => Promise.resolve(true));

      return { canOpenURL, openURL };
    }

问题是openURL没有被调用。

这是测试:

test('should open url when there is a proper app the open it', async () => {
      const { canOpenURL, openURL } = mockSuccessLinking();
      const { result } = renderHook(() =>
         useApplyToJob('https://www.google.com/'),
      );
      const [apply] = result.current;

      // Act
      apply();

      // Assert
      expect(result.current[1].error).toBeNull();
      expect(canOpenURL).toHaveBeenCalled();
      expect(openURL).toHaveBeenCalled();
});

这是被测试的钩子:

export function useApplyToJob(url) {
  const [error, setError] = useState(null);

  const apply = () => {
    Linking.canOpenURL(url).then(supported => {
      if (supported) {
        Linking.openURL(url);
      } else {
        setError(`Don't know how to open ${url}`);
      }
    });
  };

  return [apply, { error }];
}
4

1 回答 1

0

鉴于canOpenURL返回一个承诺,您需要等待异步发生,然后再测试是否openURL已被调用。react-hooks-testing-library提供了一些异步工具来帮助解决这个问题。

通常最好使用它,waitForNextUpdate或者waitForValueToChange因为它们对测试正在等待的内容更具描述性,但是您的钩子在成功的情况下不会更新任何状态,因此您需要使用更通用的waitFor实用程序来代替:

test('should open url when there is a proper app the open it', async () => {
      const { canOpenURL, openURL } = mockSuccessLinking();
      const { result, waitFor } = renderHook(() =>
         useApplyToJob('https://www.google.com/'),
      );
      const [apply] = result.current;

      // Act
      apply();

      // Assert
      expect(result.current[1].error).toBeNull();
      expect(canOpenURL).toHaveBeenCalled();

      await waitFor(() => {
          expect(openURL).toHaveBeenCalled();
      });
});

作为旁注,不建议result.current对访问进行解构。它现在可能可以工作,但在您调用的是使用先前渲染中的陈旧值apply之前不需要进行太多重构。apply

同样,我建议将apply()调用包装在 中act,即使它现在不更新任何状态。它只是使将来的重构更容易,并在您测试错误案例(需要act调用)时使您的测试更加一致。

import { renderHook, act } from '@testing-library/react-hooks';

// ...

test('should open url when there is a proper app the open it', async () => {
      const { canOpenURL, openURL } = mockSuccessLinking();
      const { result, waitFor } = renderHook(() =>
         useApplyToJob('https://www.google.com/'),
      );

      // Act
      act(() => {
        result.current[0]();
      });

      // Assert
      expect(result.current[1].error).toBeNull();
      expect(canOpenURL).toHaveBeenCalled();

      await waitFor(() => {
          expect(openURL).toHaveBeenCalled();
      });
});
于 2021-06-17T13:49:52.503 回答