如何模拟反应自定义钩子返回值?

Posted

技术标签:

【中文标题】如何模拟反应自定义钩子返回值?【英文标题】:How to mock react custom hook returned value? 【发布时间】:2020-06-01 19:57:54 【问题描述】:

这是我的自定义钩子:

  export function useClientRect() 
    const [scrollH, setScrollH] = useState(0);
    const [clientH, setClientH] = useState(0);
    const ref = useCallback(node => 
      if (node !== null) 
        setScrollH(node.scrollHeight);
        setClientH(node.clientHeight);
      
    , []);
    return [scrollH, clientH, ref];
  

我希望每次调用它时,它都会返回我的值。喜欢:

jest.mock('useClientRect', () => [300, 200, () => ]);

我怎样才能做到这一点?

【问题讨论】:

到目前为止你尝试过什么?你看过 Jest 文档吗? jestjs.io/docs/en/manual-mocks#mocking-user-modules @Timo 看起来......运气不好。我想我可能需要先监视 useClientRect 然后模拟返回。 你试过github.com/testing-library/react-hooks-testing-library吗? 如果你模拟 scrollHeight/clientHeight 而不是模拟钩子呢? ***.com/a/56457850/2071697 【参考方案1】:

将钩子作为模块加载。然后模拟模块:

jest.mock('module_name', () => (
    useClientRect: () => [300, 200, jest.fn()]
));

mock 应该在 test fn 之外的文件之上调用。因此,我们将只有一个数组作为模拟值。

如果你想在不同的测试中用不同的值来模拟钩子:

import * as hooks from 'module_name';

it('a test', () => 
    jest.spyOn(hooks, 'useClientRect').mockImplementation(() => ([100, 200, jest.fn()]));
    //rest of the test
);

【讨论】:

上帝之母,指出它需要位于顶部是有帮助的 - 不知何故,在我看过的其他十几个教程中没有人提到这一点 对我来说,它给出的错误是“useClientRect 不是一个未定义的函数” @MuhammadHaseeb 您需要将 useClientRect 替换为您的钩子名称。在这个例子中,钩子返回一个需要模拟的数组。 @muhammad-haseeb 您需要将数组替换为模拟对象。在您的代码 console.log 中,您的钩子返回的值并替换数组,如:jest.spyOn(hooks, 'useYourHookName').mockImplementation(() => (a: 100, b: 200, c: jest.fn()));. @Mohammad Kermani 当你有一个钩子文件时,它类似于'../folder_name/hook_file_name.ts'。当你从 npm 库中模拟一个钩子时,它将是 npm 库的名称。【参考方案2】:

嗯,这很棘手,有时开发人员会对库感到困惑,但一旦你习惯了它,它就会变得轻而易举。几个小时前我遇到了类似的问题,我正在分享我的解决方案,以便您轻松获得解决方案。

我的自定义 Hook:

  import  useEffect, useState  from "react";
    import  getFileData  from "../../API/gistsAPIs";
    
    export const useFilesData = (fileUrl: string) => 
      const [fileData, setFileData] = useState<string>("");
      const [loading, setLoading] = useState<boolean>(false);
      useEffect(() => 
        setLoading(true);
        getFileData(fileUrl).then((fileContent) => 
          setFileData(fileContent);
          setLoading(false);
        );
      , [fileUrl]);
    
      return  fileData, loading ;
    ;

我的模拟代码: 请将此模拟包含在测试函数之外的测试文件中。 注意:注意mock的返回对象,它应该与预期的响应匹配

const mockResponse = 
  fileData: "This is a mocked file",
  loading: false,
;
jest.mock("../fileView", () => 
  return 
    useFilesData: () => 
      return 
        fileData: "This is a mocked file",
        loading: false,
      ;
    ,
  ;
);

完整的测试文件是:

import  render, screen, waitFor  from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import FileViewer from "../FileViewer";

const mockResponse = 
  fileData: "This is a mocked file",
  loading: false,
;
jest.mock("../fileView", () => 
  return 
    useFilesData: () => 
      return 
        fileData: "This is a mocked file",
        loading: false,
      ;
    ,
  ;
);

describe("File Viewer", () => 
  it("display the file heading", async () => 
    render(<FileViewer fileUrl="" filename="regex-tutorial.md" className="" />);
    const paragraphEl = await screen.findByRole("fileHeadingDiplay");
    expect(paragraphEl).toHaveTextContent("regex-tutorial.md");
  );

干杯!!如果这有帮助,请善待其他开发者并点赞。

【讨论】:

以上是关于如何模拟反应自定义钩子返回值?的主要内容,如果未能解决你的问题,请参考以下文章

反应:带有自定义钩子的滑块无法正常工作

在 React 自定义钩子中正确输入 useRef 值

在自定义反应钩子中使用 axios

如何使用 Mock Service Worker 在自定义钩子中模拟获取?

用 Jest 模拟 React 自定义钩子

如何在初始渲染后重新渲染自定义钩子