如何测试读取URL查询参数的React组件?
测试读取URL查询参数的React组件:Mock useSearchParams方案
确实需要mock react-router-dom 的 useSearchParams 钩子——测试环境没有真实的浏览器路由上下文,没法直接通过传入URL的方式传递参数,mock是最直接可靠的方案。
以下是具体实现步骤和示例:
1. 基础Mock配置
用Vitest的 vi.mock 直接mock useSearchParams,保留react-router-dom其他未mock的导出:
// 测试文件顶部 import { vi } from 'vitest'; import { useSearchParams } from 'react-router-dom'; vi.mock('react-router-dom', () => ({ ...vi.importActual('react-router-dom'), useSearchParams: vi.fn(), }));
2. 编写测试用例
假设你的组件简化逻辑如下:
// ListComponent.jsx import { useSearchParams } from 'react-router-dom'; export default function ListComponent() { const [searchParams] = useSearchParams(); const ids = searchParams.get('ids')?.split(',') || []; return <div>{ids.join(' | ')}</div>; }
对应的测试代码:
// ListComponent.test.jsx import { render, screen } from '@testing-library/react'; import { vi } from 'vitest'; import { useSearchParams } from 'react-router-dom'; import ListComponent from './ListComponent'; describe('ListComponent', () => { it('正确拆分URL中的ids参数', () => { // 模拟带ids参数的searchParams对象 const mockSearchParams = { get: vi.fn((key) => key === 'ids' ? '001,002' : null), }; vi.mocked(useSearchParams).mockReturnValue([mockSearchParams, vi.fn()]); render(<ListComponent />); // 断言拆分结果 expect(screen.getByText('001 | 002')).toBeInTheDocument(); expect(mockSearchParams.get).toHaveBeenCalledWith('ids'); }); it('处理ids参数不存在的边界情况', () => { const mockSearchParams = { get: vi.fn(() => null), }; vi.mocked(useSearchParams).mockReturnValue([mockSearchParams, vi.fn()]); render(<ListComponent />); expect(screen.getByText('')).toBeInTheDocument(); }); });
3. 动态调整Mock参数
每个测试用例中可以独立设置mock的返回值,Vitest会自动隔离不同测试的mock状态,比如要测试ids=003的场景,只需在对应测试用例里重新定义mockSearchParams即可。
注意事项
- 真实的
useSearchParams返回的是数组(第一个元素是URLSearchParams实例,第二个是更新参数的函数),mock时必须保持这个结构,避免组件因解构报错。 - 如果组件用到了react-router-dom的其他API,
...vi.importActual('react-router-dom')会保留这些导出,不影响其他逻辑。
内容的提问来源于stack exchange,提问作者Lemour
相关产品推荐
相关产品推荐

