Jest:在函数组件中测试 useNavigate 钩子
Jest: Test useNavigate hook in function component
我正在用 Jest 编写测试,想测试一个简单的按钮,该按钮用作注销并通过 onClick
将您重定向到 "/login"
。
import {loginService} from "../../utils/loginService";
import React from "react";
import {useNavigate} from "react-router-dom";
const Logout = () => {
const navigate = useNavigate()
const logout = e => {
loginService.logout();
navigate("/login");
}
return (
<button className={'logout'} onClick={logout}>Logout</button>
)
}
export default Logout
我能够编写第一个测试来呈现按钮并检查它是否存在。第二个测试应该检查,点击浏览器将您重定向到“/login”。
import Logout from "../../components/navbar/Logout";
import {BrowserRouter} from "react-router-dom";
import {fireEvent, render} from "@testing-library/react";
import {screen} from '@testing-library/react';
describe('Test Logout Button', () => {
it('it is rendered', () => {
render(
<BrowserRouter>
<Logout/>
</BrowserRouter>
)
expect(screen.getByText(/logout/i)).toBeInTheDocument()
})
it('it redirects after click', () => {
const mockedUsedNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => mockedUsedNavigate,
}));
render(
<BrowserRouter>
<Logout/>
</BrowserRouter>
)
const logout = screen.getByText(/logout/i);
fireEvent.click(logout);
// TODO something something check useNavigate
// https://blog.logrocket.com/testing-react-router-usenavigate-hook-react-testing-library/
expect(mockedUsedNavigate).toBeCalledTimes(1);
})
})
但是失败了:
expect(jest.fn()).toBeCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
我假设我必须以某种方式将模拟传递给我的组件。我该怎么做,或者我什至必须这样做?如何检查 useNavigate
是否已重定向到 "/login"
?据我所知 <BrowserRouter />
没有历史属性。
jest.mock
应该在您的单元测试之外完成,因为它需要在您要测试的代码对其进行评估之前模拟出一个依赖项。在您的示例中,react-router-dom
库首先由 Logout
组件评估,然后您的代码尝试模拟它,但为时已晚。因此,您应该将以下代码移到 describe
:
之外
const mockedUsedNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => mockedUsedNavigate,
}));
当然,你所有的测试都将使用相同的 mockedUsedNavigate
实例,这很容易出错,所以你应该在每个单元测试之前通过将它添加到 beforeEach 来重置它,如下所示:
beforeEach(() => {
mockedUsedNavigate.mockReset();
});
我正在用 Jest 编写测试,想测试一个简单的按钮,该按钮用作注销并通过 onClick
将您重定向到 "/login"
。
import {loginService} from "../../utils/loginService";
import React from "react";
import {useNavigate} from "react-router-dom";
const Logout = () => {
const navigate = useNavigate()
const logout = e => {
loginService.logout();
navigate("/login");
}
return (
<button className={'logout'} onClick={logout}>Logout</button>
)
}
export default Logout
我能够编写第一个测试来呈现按钮并检查它是否存在。第二个测试应该检查,点击浏览器将您重定向到“/login”。
import Logout from "../../components/navbar/Logout";
import {BrowserRouter} from "react-router-dom";
import {fireEvent, render} from "@testing-library/react";
import {screen} from '@testing-library/react';
describe('Test Logout Button', () => {
it('it is rendered', () => {
render(
<BrowserRouter>
<Logout/>
</BrowserRouter>
)
expect(screen.getByText(/logout/i)).toBeInTheDocument()
})
it('it redirects after click', () => {
const mockedUsedNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => mockedUsedNavigate,
}));
render(
<BrowserRouter>
<Logout/>
</BrowserRouter>
)
const logout = screen.getByText(/logout/i);
fireEvent.click(logout);
// TODO something something check useNavigate
// https://blog.logrocket.com/testing-react-router-usenavigate-hook-react-testing-library/
expect(mockedUsedNavigate).toBeCalledTimes(1);
})
})
但是失败了:
expect(jest.fn()).toBeCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
我假设我必须以某种方式将模拟传递给我的组件。我该怎么做,或者我什至必须这样做?如何检查 useNavigate
是否已重定向到 "/login"
?据我所知 <BrowserRouter />
没有历史属性。
jest.mock
应该在您的单元测试之外完成,因为它需要在您要测试的代码对其进行评估之前模拟出一个依赖项。在您的示例中,react-router-dom
库首先由 Logout
组件评估,然后您的代码尝试模拟它,但为时已晚。因此,您应该将以下代码移到 describe
:
const mockedUsedNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => mockedUsedNavigate,
}));
当然,你所有的测试都将使用相同的 mockedUsedNavigate
实例,这很容易出错,所以你应该在每个单元测试之前通过将它添加到 beforeEach 来重置它,如下所示:
beforeEach(() => {
mockedUsedNavigate.mockReset();
});