Jest.js react-navigation-hooks:如何测试useFocusEffect

yqlxgs2m  于 2024-01-04  发布在  Jest
关注(0)|答案(8)|浏览(214)

据我所知,应该这样做,以便useFocusEffect将作为useFocusEffect用于测试(模拟)。我使用useFocusEffect用于fetchData:

  1. useFocusEffect(
  2. useCallback(() => {
  3. fetchData();
  4. }, [fetchData]),
  5. );

字符串

**错误消息:**react-navigation hooks需要导航上下文,但找不到。请确保您没有忘记创建和渲染react-navigation应用容器。如果您需要访问可选的导航对象,可以使用Context(NavigationContext),它可能会返回
软件包版本:

  1. "jest": "^24.9.0",
  2. "react-native": "0.61.2",
  3. "react-navigation": "^4.0.10",
  4. "react-navigation-hooks": "^1.1.0",
  5. "@testing-library/react-native": "^4.0.14",

tzxcd3kk

tzxcd3kk1#

假设你在测试中渲染你的组件,你需要将它 Package 在一个假的<NavigationContext>中。这样做可以让useFocusEffect查找它需要的东西,以确定该组件是否已被你的应用导航聚焦。
这个例子使用了react-native-testing-library中的render。我认为它类似于其他渲染方法。

  1. import { NavigationContext } from "@react-navigation/native"
  2. import { render } from "react-native-testing-library"
  3. // fake NavigationContext value data
  4. const navContext = {
  5. isFocused: () => true,
  6. // addListener returns an unscubscribe function.
  7. addListener: jest.fn(() => jest.fn())
  8. }
  9. // MyComponent needs to be inside an NavigationContext, to allow useFocusEffect to function.
  10. const { toJSON } = render(
  11. <NavigationContext.Provider value={navContext}>
  12. <MyComponent />
  13. </NavigationContext.Provider>
  14. )

字符串

展开查看全部
8qgya5xd

8qgya5xd2#

这只是@meshantz上述回答的更完整版本。

  1. import { NavigationContext } from '@react-navigation/native';
  2. import { render } from '@testing-library/react-native';
  3. import React from 'react';
  4. // This would probably be imported from elsewhere...
  5. const ComponentUnderTest = () => {
  6. useFocusEffect(
  7. useCallback(() => {
  8. fetchData();
  9. }, [fetchData]),
  10. );
  11. return null;
  12. };
  13. const mockFetchData = jest.fn();
  14. jest.mock('fetchData', () => mockFetchData);
  15. describe('testing useFocusOnEffect in ComponentUnderTest', () => {
  16. afterAll(() => {
  17. jest.restoreAllMocks();
  18. });
  19. describe('when the view comes into focus', () => {
  20. it('calls fetchData', () => {
  21. const navContextValue = {
  22. isFocused: () => false,
  23. addListener: jest.fn(() => jest.fn()),
  24. };
  25. render(
  26. <NavigationContext.Provider value={navContextValue}>
  27. <ComponentUnderTest />
  28. </NavigationContext.Provider>,
  29. );
  30. expect(mockFetchData).toBeCalledTimes(0);
  31. render(
  32. <NavigationContext.Provider
  33. value={{
  34. ...navContextValue,
  35. isFocused: () => true,
  36. }}
  37. >
  38. <ComponentUnderTest />
  39. </NavigationContext.Provider>,
  40. );
  41. expect(mockFetchData).toBeCalledTimes(1);
  42. });
  43. });
  44. });

字符串

展开查看全部
j5fpnvbx

j5fpnvbx3#

对于TypeScript,它也需要满足类型要求,所以在我的例子中,它是通过使用jest.requireActual完成的:

  1. const withProvider = (element, store = defaultStore) => {
  2. // fake NavigationContext value data
  3. const actualNav = jest.requireActual("@react-navigation/native");
  4. const navContext = {
  5. ...actualNav.navigation,
  6. navigate: () => {},
  7. dangerouslyGetState: () => {},
  8. setOptions: () => {},
  9. addListener: () => () => {},
  10. isFocused: () => true,
  11. };
  12. return (
  13. <NavigationContext.Provider value={navContext}>
  14. <MyComponent />
  15. </NavigationContext.Provider>
  16. );
  17. };
  18. it("renders correctly", () => {
  19. render(withProvider(() => <SportsBooksScreen {...defaultProps} />));
  20. });

字符串

展开查看全部
yduiuuwa

yduiuuwa4#

我在这个帖子中提出的解决方案有问题/限制,所以我最终用“React.useEffect”来模仿“useFocusEffect”。
它做得很好:我的测试现在是绿色的!

  1. jest.mock('@react-navigation/native', () => {
  2. const { useEffect } = require('react');
  3. const actualModule = jest.requireActual('@react-navigation/native');
  4. return {
  5. ...actualModule,
  6. useFocusEffect: useEffect,
  7. };
  8. });

字符串

14ifxucb

14ifxucb5#

而不是useFocusEffect,使用useIsFocused和useEffect,代码工作正常。

  1. In Your component:
  2. import React, { useEffect } from 'react';
  3. import { useIsFocused } from '@react-navigation/native';
  4. const Component = () => {
  5. const isFocused = useIsFocused();
  6. useEffect(() => {
  7. if (isFocused) {
  8. fetchData();
  9. }
  10. }, [isFocused]);
  11. return (<><View testID="child_test_id">{'render child nodes'}</View></>)
  12. }
  13. For Testing:
  14. import Component from '--path-to-component--';
  15. jest.mock('--path-to-fetchData--');
  16. jest.mock('@react-navigation/native', () => {
  17. return {
  18. useIsFocused: () => true
  19. };
  20. });
  21. it('should render child component when available', async () => {
  22. const mockedData = [];
  23. fetchData.mockImplementation(() => mockedData);
  24. let screen = null;
  25. await act(async () => {
  26. screen = renderer.create(<Component />);
  27. });
  28. const childNode = screen.root.findByProps({ testID: 'child_test_id' });
  29. expect(childNode.children).toHaveLength(1);
  30. });

字符串

展开查看全部
gopyfrb3

gopyfrb36#

useFocusEffect使用navigation.isFocused(),可以从jest的renderHookWithProviders访问。
做一个navigation.isFocused.mockReturnValue(true);应该就行了!现在刚试过,效果很好。

yqyhoc1h

yqyhoc1h7#

创建组件FocusEffects

  1. import { useFocusEffect } from "@react-navigation/native";
  2. import { BackHandler } from "react-native";
  3. import React from "react";
  4. export default function FocusEffect({ onFocus, onFocusRemoved }) {
  5. useFocusEffect(
  6. React.useCallback(() => {
  7. onFocus();
  8. return () => onFocusRemoved();
  9. }, [onFocus, onFocusRemoved]),
  10. );
  11. return null;
  12. }

字符串
使用示例:

  1. import React from 'react';
  2. import { Text, View } from 'react-native';
  3. import { FocusEffect } from './components';
  4. const App = () => {
  5. onFocus = () => {
  6. // ============>>>> onFocus <<<<==============
  7. fetchData();
  8. };
  9. onFocusRemoved = () => {
  10. // ============>>>> onFocusRemoved <<<<==============
  11. };
  12. return (
  13. <View>
  14. <FocusEffect
  15. onFocus={this.onFocus}
  16. onFocusRemoved={this.onFocusRemoved}
  17. />
  18. <Text>Hello, world!</Text>
  19. </View>
  20. )
  21. }
  22. export default App;

展开查看全部
yfwxisqw

yfwxisqw8#

如果useFocusEffect()中的代码对您的测试没有影响,您可以模拟钩子,如下所示:

  1. jest.mock("@react-navigation/native", () => ({
  2. useFocusEffect: jest.fn(),
  3. // ...
  4. }));

字符串

相关问题