我四处寻找答案,但找不到有关此主题的任何解决方案。
本质上,我正在尝试使用“@testing-library/react-native”编写一些单元测试来测试按下登录按钮是否会调用 useAuth0().authorize 。我预计它已被调用 1 次,但收到 0 次回电。
我做错了什么?
以下是 ./app/(login)/index.tsx 中的登陆页面:
import { StyleSheet, TouchableOpacity, SafeAreaView } from 'react-native';
import { useAuth0 } from 'react-native-auth0';
export default function Landing(): React.JSX.Element {
const { authorize, clearSession, user } = useAuth0();
const onLogin = async () => {
try {
await authorize();
} catch (e) {
console.log(e);
}
};
const loggedIn = user !== undefined && user !== null;
const onLogout = async () => {
try {
await clearSession();
} catch (e) {
console.log('Log out cancelled');
}
};
return (
<SafeAreaView style={styles.container}>
<TouchableOpacity style={styles.logBtn} onPress={loggedIn ? onLogout : onLogin} testID='loginBtn'>
{user && <Text style={styles.btnTxt}>Log Out</Text>}
{!user && <Text style={styles.btnTxt}>Log In</Text>}
</TouchableOpacity>
</SafeAreaView>
}
这是我进行的测试:
import { render, fireEvent, waitFor } from '@testing-library/react-native';
import { useAuth0 } from 'react-native-auth0';
import Landing from '@/app/(login)/index';
jest.mock('react-native-auth0', () => ({
useAuth0: jest.fn(() => ({
authorize: jest.fn(),
})),
}));
describe('Login page renders and performs correct actions through Auth0', () => {
test('Login button correctly calls authorize function', async () => {
const { getByTestId } = render(<Landing />);
const loginBtn = getByTestId('loginBtn');
fireEvent.press(loginBtn)
await waitFor(() => {
expect(useAuth0().authorize).toHaveBeenCalledTimes(1);
})
})
})
这是我收到的错误:
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
43 | fireEvent.press(loginBtn)
44 |
> 45 | await waitFor(() => {
| ^
46 | expect(useAuth0().authorize).toHaveBeenCalledTimes(1);
47 | })
48 | })
我尝试过的其他一些事情:
切换:
fireEvent.press(loginBtn);
到
fireEvent(loginBtn, 'click');
<TouchableOpacity></TouchableOpacity>
到
<Button></Button>
这些也不起作用:(
这里的问题是,您在测试中引用了一个新的模拟,而不是在组件中引用的模拟。
要使其正常工作,您将需要使用传递到模拟模块中的模拟函数。
例如,我使用 React Router 的
useNavigate
钩子处理过一个非常相似的场景:
const mockUseNavigate = jest.fn();
jest.mock("react-router", () => ({
...jest.requireActual("react-router"),
useNavigate: () => mockUseNavigate,
}));
然后可以通过以下两种方式之一使用它:
const useNavigateMock = useNavigate();
// do stuff to trigger the nav
expect(useNavigateMock).toHaveBeenCalledWith("/");
或者你可以直接使用模拟:
expect(mockUseNavigate).toHaveBeenCalledWith("/");
第一种方法的缺点是您需要在每个测试中导入并调用钩子,第二种方法的缺点是您使用在测试/描述范围之外定义的模拟。无论您使用哪种方法,重要的是您最终都会得到
beforeEach
来重置模拟或在 Jest 配置中设置 resetMocks: true
。
在您的情况下,您当然可以更新您的 useAuth0()
模拟以返回一个对象以匹配钩子返回值的形状。例如
const mockAuthorize = jest.fn();
jest.mock('react-native-auth0', () => ({
useAuth0: () => ({
authorize: mockAuthorize,
}),
}));
(我也删除了包装jest.fn()
,因为你可能不需要它,除非你断言钩子本身的使用)