javascript - 如何在 react-router-dom 中模拟 useNavigate 钩子
问题描述
我有一个自定义钩子,它使用useNavigate
来自react-router-dom
. 我只想添加一个测试来检查是否将预期值传递给了钩子。该钩子仅在 URL 中存储和检索查询参数的值。
这是我的自定义钩子的样子 -
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useSearchParam } from 'react-use';
// Default value for the tokens
export const END_PAGE_TOKEN = '';
// Stores pagination tokens in react state and URL query param
export const usePaginationParams = () => {
// Gets 'token' query param from the URL
const token = useSearchParam('token');
const navigate = useNavigate();
return {
getCurrentPageToken: () => decodeURIComponent(token || END_PAGE_TOKEN),
setCurrentPageToken: (pageToken: string) => {
if (pageToken && pageToken !== END_PAGE_TOKEN) {
// Sets 'token' query param to the URL
navigate(`?token=${encodeURIComponent(pageToken)}`);
} else {
// Go to the first page
navigate('');
}
},
};
};
这就是我测试它的方式 -
import { renderHook } from '@testing-library/react-hooks';
import { usePaginationParams } from './usePaginationParams';
import { useNavigate } from 'react-router-dom';
import { useSearchParam } from 'react-use';
let mockedNavigate = jest.fn();
jest.mock('react-router-dom', () => {
mockedNavigate = jest.fn();
return {
__esModule: true,
useNavigate: mockedNavigate,
};
});
jest.mock('react-use', () => ({
useSearchParam: jest.fn(),
}));
const mockedUseSearchParam = useSearchParam as jest.MockedFunction<typeof useSearchParam>;
const mockedUseNavigate = useNavigate as jest.MockedFunction<typeof useNavigate>;
const TEST_TOKEN = 'TEST_TOKEN';
describe('usePaginationParams', () => {
beforeEach(() => {
if (mockedUseNavigate) {
mockedUseNavigate.mockClear();
}
if (mockedNavigate) {
mockedNavigate.mockClear();
}
if (mockedUseSearchParam) {
mockedUseSearchParam.mockClear();
}
});
it('reads query param correctly from URL', () => {
mockedUseSearchParam.mockReturnValueOnce(TEST_TOKEN);
const { result } = renderHook(() => {
const { getCurrentPageToken } = usePaginationParams();
return getCurrentPageToken();
});
expect(mockedUseSearchParam).toBeCalledTimes(1);
expect(mockedUseNavigate).toBeCalledTimes(1);
expect(result.current).toBe(TEST_TOKEN);
});
it('sets query param correctly to URL', () => {
mockedNavigate.mockImplementationOnce((to: string) => {
console.log('mocked to ', to);
});
renderHook(() => {
const { setCurrentPageToken } = usePaginationParams();
setCurrentPageToken(TEST_TOKEN);
});
// expect(mockedNavigate).toBeCalledTimes(1);
expect(mockedNavigate).toBeCalledWith(`?token=${TEST_TOKEN}`);
});
});
第一个测试通过,但第二个测试失败并出现以下错误 -
expect(jest.fn()).toBeCalledWith(...expected)
Expected: "?token=TEST_TOKEN"
Number of calls: 0
这意味着mockedNavigate
没有被调用并且console.log
永远不会被打印。有什么方法可以用预期的参数测试钩子的调用吗?
解决方案
我正在测试错误的模拟。钩子返回一个函数,因此useNavigate()
我必须直接模拟它。我只是将其更改为以下代码并开始传递。
it('sets query param correctly to URL', () => {
const mockImpl = jest.fn().mockImplementation((to: any) => {
console.log('mocked to ', to);
});
mockedUseNavigate.mockImplementationOnce(() => mockImpl);
renderHook(() => {
const { setCurrentPageToken } = usePaginationParams();
setCurrentPageToken(TEST_TOKEN);
});
expect(mockImpl).toBeCalledTimes(1);
expect(mockImpl).toBeCalledWith(`?token=${TEST_TOKEN}`);
});
推荐阅读
- thymeleaf - Thymeleaf - 如何写 th:text?
- lucene - Apache Jena Textsearch 在多个字段上非常慢
- javascript - 任何人都可以修改此代码以使其可用于类,因为如果我编写 getElementsByClassName 代码将不起作用所以请帮助我
- google-apps-script - 为什么 Google App Script 突然不起作用
- mongodb - 在 MongoDB 上加入多个集合
- python-3.x - 如何将作为元素列表的字典的值转换为(坐标元组)的元组?
- amazon-web-services - 如何在不上传 zip 文件或使用 EFS 的情况下在 AWS Lambda 中获取 python 包?
- python - 有没有办法在熊猫上合并重复的行和求和值?
- javascript - 从服务器加载 pdf 并嵌入 Vue 应用程序
- c# - 共享 JWT 认证/授权