You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试调用useLocation的自定义Hook?解决测试报错问题

解决useLocation在自定义Hook测试中报错的问题

这个报错的核心原因是:useLocation属于React Router的Hook,必须在React Router提供的上下文环境中调用,你的测试代码没有将自定义Hook包裹在这个上下文里,所以触发了限制。

下面是具体的解决方案和测试示例:

1. 基础测试方案(固定路由场景)

假设你的自定义Hook实现如下:

// useMyHook.js
import { useLocation } from 'react-router-dom';

export function useMyHook() {
  const location = useLocation();
  return {
    currentPath: location.pathname,
    searchParams: new URLSearchParams(location.search)
  };
}

对应的测试代码需要通过wrapper参数给Hook提供React Router上下文:

// useMyHook.test.js
import { renderHook } from '@testing-library/react';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
import { useMyHook } from './useMyHook';

// 自定义Wrapper,提供React Router上下文
const RouterWrapper = ({ children }) => {
  return (
    <MemoryRouter initialEntries={['/test-page?key=value']}>
      <Routes>
        <Route path="*" element={<>{children}</>} />
      </Routes>
    </MemoryRouter>
  );
};

test('useMyHook返回正确的路径和查询参数', () => {
  const { result } = renderHook(() => useMyHook(), {
    wrapper: RouterWrapper
  });

  expect(result.current.currentPath).toBe('/test-page');
  expect(result.current.searchParams.get('key')).toBe('value');
});

2. 测试路由变化场景

如果需要验证路由更新时Hook的状态变化,可以通过暴露导航方法或直接操控history对象实现:

import { renderHook, act } from '@testing-library/react';
import { MemoryRouter, useNavigate } from 'react-router-dom';

const RouterWrapperWithNavigate = ({ children }) => {
  const navigate = useNavigate();
  return (
    <MemoryRouter initialEntries={['/initial']}>
      {children}
      {/* 暴露导航触发元素供测试调用 */}
      <button data-testid="navigate-btn" onClick={() => navigate('/new-route')} />
    </MemoryRouter>
  );
};

test('路由变化时useMyHook状态更新', () => {
  const { result, container } = renderHook(() => useMyHook(), {
    wrapper: RouterWrapperWithNavigate
  });

  // 初始状态验证
  expect(result.current.currentPath).toBe('/initial');

  // 触发路由跳转
  act(() => {
    container.querySelector('[data-testid="navigate-btn"]').click();
  });

  // 验证更新后的状态
  expect(result.current.currentPath).toBe('/new-route');
});

3. 灵活控制History对象

如果需要更精细地操控路由历史,可以使用createMemoryHistory配合Router组件:

import { renderHook, act } from '@testing-library/react';
import { createMemoryHistory } from 'history';
import { Router } from 'react-router-dom';
import { useMyHook } from './useMyHook';

test('手动控制History对象测试useMyHook', () => {
  const history = createMemoryHistory({ initialEntries: ['/custom-path'] });
  
  const { result } = renderHook(() => useMyHook(), {
    wrapper: ({ children }) => (
      <Router location={history.location} navigator={history}>
        {children}
      </Router>
    )
  });

  expect(result.current.currentPath).toBe('/custom-path');

  // 手动更新路由
  act(() => {
    history.push('/updated-path');
  });

  expect(result.current.currentPath).toBe('/updated-path');
});

核心总结

只要确保自定义Hook在测试时处于React Router的上下文环境中(通过renderHook的wrapper参数提供包含MemoryRouter或Router的组件),就能解决useLocation() may be used only in the context of a component.的报错。

内容的提问来源于stack exchange,提问作者Saito Asuka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 21:40:01