用 Jest 模拟库钩子
Posted
技术标签:
【中文标题】用 Jest 模拟库钩子【英文标题】:Mocking library hook with Jest 【发布时间】:2021-05-11 07:06:33 【问题描述】:设置
我在我的一个组件中使用了一个名为 react-firebase-hooks 的库。
// Component.tsx
import React, useEffect from 'react';
import Firebase from '../firebase/firebase';
import useAuthState from 'react-firebase-hooks/auth';
export const Component = () =>
// Note that Firebase.getAuth is a static method of a class of mine for getting the firebase authentication object
const [user, loading ] = useAuthState(Firebase.getAuth());
if (!loading && !user)
// ... stuff
return (
<div>
...stuff
</div>
);
;
一种有效的方式
我试图在我的一项测试中模拟出useAuthState
调用,但在找出执行模拟的最佳方法时遇到了很多麻烦。我找到了一个可行的解决方案:
// Component.test.tsx
import useAuthState from 'react-firebase-hooks/auth'
jest.mock('react-firebase-hooks/auth', () => (
useAuthState: jest.fn()
));
但是,上面的模拟实现使得模拟对象无法在 IDE 中完成。例如,这是我尝试设置一个模拟返回值:
test(`component correctly loads`, () =>
useAuthState.mockReturnValue([true, false])
// renderApp is a utility method of mine to render using react-testing-library
const getByText = renderApp();
// expect some stuff
);
我的首选结果(和尝试 1)
我发现useAuthState
没有自动完成功能。
理想情况下,我希望声明模拟的方式更接近
const mockAuth = jest.fn();
jest.mock('react-firebase-hooks/auth', () =>
return jest.fn().mockImplementation(() =>
return useAuthState: mockAuth
)
);
然后让我通过我声明的测试(并获得自动完成)很好地改变 mockAuth
对象,例如:
test(`component correctly loads`, () =>
mockAuth.mockReturnValue([true, false])
// renderApp is a utility method of mine to render using react-testing-library which renders Component
const getByText = renderApp();
// expect some stuff
);
但是,通过上述实现,我收到以下错误:(0 , _auth.useAuthState) is not a function or its return value is not iterable
in Component
。
尝试 2
我也尝试过将模拟声明为
const mockAuth = jest.fn();
jest.mock('react-firebase-hooks/auth', () => (
useAuthState: mockAuth
));
但这给了我ReferenceError: Cannot access 'mockAuth' before initialization
的错误。
尝试 3
我也试过
const mockAuth = jest.fn();
import useAuthState from 'react-firebase-hooks/auth'
jest.mock('react-firebase-hooks/auth', () => (
useAuthState: mockAuth
));
但这给出了同样的错误。
结束问题
有没有办法让我在模拟声明的“外部”声明一个模拟函数,以便我可以自动完成它?
【问题讨论】:
看这个***.com/questions/57305823/…或者创建沙盒 我看不出这如何有助于在模块模拟声明之外声明模拟函数。 你能做codesanbox吗? @DaniilLoban CodeSandbox doesn't support jest mocking。我必须以我认为你想知道的艰难方式弄清楚这一点。 我只需要最小的安装项目,而不是在 sunbox 中运行 【参考方案1】:如果您使用另一个文件进行模拟,您应该很容易更改实现并仍然保留 TypeScript Intellisense。
src/App.test.jsx
import App from "../App";
import render from "@testing-library/react";
import useAuthState from "../__mocks__/react-firebase-hooks/auth";
it("should be mocked", () =>
// Change the implementation of the mock
useAuthState.mockReturnValue([true, false]);
const getByText = render(<App />);
// Expect that the app file got the mocked value
expect(useAuthState).toBeCalledWith("my auth");
expect(getByText("true,false")).toBeTruthy();
);
src/__mocks__/react-firebase-hooks/auth.js
export const useAuthState = jest.fn();
src/App.js
import useAuthState from "react-firebase-hooks/auth";
export default function App()
const test = useAuthState("my auth");
return <div>test.toString()</div>;
【讨论】:
哇,太酷了。我以前没有见过这种语法。你有没有我可以阅读的文档的链接?这是模拟的首选方式吗?这种方法有什么缺点? 我能想到的唯一缺点是必须制作一个单独的文件。有时这是理想的,有时它有点烦人。这是相关的文档(尽管在这个特定模型上很少)jestjs.io/docs/en/manual-mocks以上是关于用 Jest 模拟库钩子的主要内容,如果未能解决你的问题,请参考以下文章
使用 jest 模拟 react-router-dom 钩子不起作用