React-navigation-hooks:如何测试 useFocusEffect

Vas*_*iak 9 unit-testing jestjs react-native react-navigation

据我了解,应该这样做,以便 useFocusEffect 可以作为 useEffect 进行测试(模拟)。我使用 useFocusEffect 来获取数据:

useFocusEffect(
  useCallback(() => {
    fetchData();
  }, [fetchData]),
);
Run Code Online (Sandbox Code Playgroud)

错误消息: react-navigation 挂钩需要导航上下文,但无法找到。确保您没有忘记创建和渲染反应导航应用程序容器。如果需要访问可选的导航对象,可以使用useContext(NavigationContext),它可能会返回

封装版本:

"jest": "^24.9.0",
"react-native": "0.61.2",
"react-navigation": "^4.0.10",
"react-navigation-hooks": "^1.1.0",
"@testing-library/react-native": "^4.0.14",
Run Code Online (Sandbox Code Playgroud)

mes*_*ntz 11

假设你在测试中渲染你的组件,你需要将它包装在一个假的<NavigationContext>. 这样做可以useFocusEffect查找确定组件是否已被应用程序导航聚焦所需的内容。

此示例使用render来自react-native-testing-library. 我认为它类似于其他渲染方法。

import { NavigationContext } from "@react-navigation/native"
import { render } from "react-native-testing-library"

// fake NavigationContext value data
const navContext = {
  isFocused: () => true,
  // addListener returns an unscubscribe function.
  addListener: jest.fn(() => jest.fn())
}

// MyComponent needs to be inside an NavigationContext, to allow useFocusEffect to function.
const { toJSON } = render(
  <NavigationContext.Provider value={navContext}>
    <MyComponent />
  </NavigationContext.Provider>
)
Run Code Online (Sandbox Code Playgroud)


our*_*dam 5

这只是@meshantz 上面答案的更完整版本。

import { NavigationContext } from '@react-navigation/native';
import { render } from '@testing-library/react-native';
import React from 'react';

// This would probably be imported from elsewhere...
const ComponentUnderTest = () => {
  useFocusEffect(
    useCallback(() => {
      fetchData();
    }, [fetchData]),
  );
  
  return null;
};

const mockFetchData = jest.fn();
jest.mock('fetchData', () => mockFetchData);

describe('testing useFocusOnEffect in ComponentUnderTest', () => {
  afterAll(() => {
    jest.restoreAllMocks();
  });

  describe('when the view comes into focus', () => {
    it('calls fetchData', () => {
      const navContextValue = {
        isFocused: () => false,
        addListener: jest.fn(() => jest.fn()),
      };

      render(
        <NavigationContext.Provider value={navContextValue}>
          <ComponentUnderTest />
        </NavigationContext.Provider>,
      );

      expect(mockFetchData).toBeCalledTimes(0);

      render(
        <NavigationContext.Provider
          value={{
            ...navContextValue,
            isFocused: () => true,
          }}
        >
          <ComponentUnderTest />
        </NavigationContext.Provider>,
      );

      expect(mockFetchData).toBeCalledTimes(1);
    });
  });
});

Run Code Online (Sandbox Code Playgroud)

  • 这太棒了!多谢。你知道如何用打字稿写这个吗?我尝试过,但 navContext 缺少一些类型,例如:调度、导航、重置、返回。 (2认同)