当挂钩具有一些导航逻辑时,我在使用
renderHook
实用程序测试挂钩时遇到一些问题。我无法在测试中模拟导航。
例如,让我们以这个示例钩子为例
export const useNavBar = () => {
const location = useLocation();
const isExpandable = useMemo(() => {
const aPath = matchPath({path: "/a-rute"}, location.pathName);
const anotherPath = matchPath({path: "/another-rute"}, location.pathName);
return !aPath && !anotherPath
},[location.pathname]);
return {isExpandable}
}
目前我想尝试当用户导航到不可扩展的路线时,它会发生变化。然而,它似乎在测试中忽略了
window.history.pushState
。
it("changes expandable accessing an invalid route", () => {
const {result} = renderHook(useNavBar, {wrapper: BrowserRouter});
expect(result.current.isExpandable).toBeTruthy();
window.history.pushState({}, '', '/a-route');
expect(result.current.isExpandable).toBeFalsy();
}
调用
window.history.pushState
不会触发重新渲染,因此不会更新值。同样手动调用 rerender
也没有效果,因为 useLocation
没有注意到这些变化。
那么,如何使用
renderHook
更新位置?
问题在于
BrowserRouter
不知道任何 window.history.pushState
,并且可能无论如何都无法在 Node.js 环境中工作。在单元测试中,我们通常使用 MemoryRouter
。
我没有太多使用
renderHook
,但我怀疑你可以创建一个包装器来呈现一个HistoryRouter
,并传递一个自定义的memoryHistory
对象(例如内存路由器),然后你可以使用它来实现效果导航动作。
示例:
import { renderHook, act } from "@testing-library/react";
import { unstable_HistoryRouter as Router } from "react-router-dom"; // <-- v6
import { createMemoryHistory } from "history"; // <-- history@5
const history = createMemoryHistory(); // defaults to `"/"`
const RouterWrapper = ({ children }) => (
<Router history={history}>
{children}
</Router>
);
it("changes expandable accessing an invalid route", () => {
const { result } = renderHook(useNavBar, { wrapper: RouterWrapper });
expect(result.current.isExpandable).toBeTruthy();
// Navigate to new path with new search params
act(() => {
history.push("/a-route");
});
expect(result.current.isExpandable).toBeFalsy();
}
这一切都假设您正在使用
react-router-dom@6
。如果您使用的是较旧的 v5 版本,请导入低级 Router
并确保您将 history@4
作为兼容性依赖项。