【问题标题】:How do I test a react hook method?如何测试反应钩子方法?
【发布时间】:2020-02-16 23:17:58
【问题描述】:

我正在使用 jest/istanbul 来跟踪代码覆盖率。我有以下组件:

 // Menu.jsx    
  const myComponent = ({ initialState }) = {
        const [state, setState] = useState(initialState);
        const [menuContent, setMenuContent] = useState(undefined);

        return (
            <Menu>
                {state.accordions.map(item, index) => (
                    <MenuPanel id={item.id}>
                        {item.details && typeof item.details === 'function'
                            ? <item.details setContent={myContent => setMenuContent(myContent)} />
                            : undefined}
                    </MenuPanel>
                )}
            </Menu>
        )
    }

在我对Menu.jsx 的测试中,开玩笑的覆盖率报告抱怨setMenuContent 不在我的测试中。我应该如何测试这样的钩子?我认为这是不可能的。我尝试测试子组件上是否存在 setContent 道具,但这没有帮助。关于如何让它通过覆盖率报告的任何想法?我在测试中使用浅层渲染。

【问题讨论】:

    标签: javascript reactjs testing jestjs


    【解决方案1】:

    你可以为这个特定组件模拟 useState,试试这个:

    const stateMock = jest.fn();
    
    jest.mock('react', () => {
      const ActualReact = require.requireActual('react');
      return {
        ...ActualReact,
        useState: () => ['value', stateMock], // what you want to return when useContext get fired goes here
      };
    });
    

    每次您的组件调用useState 时,您的stateMock 都会被触发,并且您的案例将被覆盖

    这只是您可以做的一个最小示例,但您可以增强模拟以识别每个状态调用

    如果你想保持 React 状态的默认行为,你可以在组件主体之外声明你的回调函数,在你的情况下,相关的代码行在这里:

    <item.details setContent={myContent => setMenuContent(myContent)} />
    

    因此,您可以将其从组件中取出并执行以下操作,而不是使用这个无论如何都会导致内存泄漏的匿名函数:

       const setContent = (setMenuContent) => (myContent) => setMenuContent(myContent)
    
    
      const myComponent = ({ initialState }) = {
        const [state, setState] = useState(initialState);
        const [menuContent, setMenuContent] = useState(undefined);
    
        return (
            <Menu>
                {state.accordions.map(item, index) => (
                    <MenuPanel id={item.id}>
                        {item.details && typeof item.details === 'function'
                            ? <item.details setContent={setContent(setMenuContent)} />
                            : undefined}
                    </MenuPanel>
                )}
            </Menu>
        )
    }
    

    现在您可以导出此函数并用文本覆盖它,这将允许您模拟 setMenuContent

    export const setContent = (setMenuContent) => (myContent) => setMenuContent(myContent)
    

    您的最后一个选择是使用类似酶或 react-testing-lib 的东西,在 dom 中找到这个 item.details 组件并触发点击操作

    【讨论】:

    • 虽然这不是我最终使用的解决方案(只是渲染更多组件增加了覆盖范围),但我尝试了您的第二个解决方案并且效果很好。但由于它是别人的代码,我无法更改它。谢谢。
    猜你喜欢
    • 2020-07-07
    • 1970-01-01
    • 1970-01-01
    • 2020-06-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-08
    • 2021-04-25
    • 2021-01-21
    相关资源
    最近更新 更多