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

使用Remix时Jest测试Accordion组件遇useLocation上下文错误

解决Jest测试Accordion组件时的useLocation上下文错误

我在Jest中测试Accordion组件时,即便用BrowserRouter包裹了组件,仍持续收到错误提示:useLocation() may be used only in the context of a <Router> component。组件内部在第19行调用useLocation()获取pathname。

测试代码

import { render, screen } from '@testing-library/react'
import Accordion from '../Accordion'

import { BrowserRouter } from 'react-router-dom'

describe('Accordion component', () => {
    const props = {
       title: 'Test Title',
       subtitle: 'Test Subtitle',
       svg: '/test.svg',
       className: 'test-class',
       id: 'test-accordion',
       completed: true,
    }
}


it('renders accordion title and subtitle', () => {
    render(
        <BrowserRouter>
            <Accordion {...props}>Content</Accordion>
        </BrowserRouter>
    )
    expect(screen.getByText('Test Title')).toBeInTheDocument()
    expect(screen.getByText('Test Subtitle')).toBeInTheDocument()
})})

报错信息

FAIL  app/components/Accordion/tests/Accordion.test.tsx
Accordion component
✕ renders accordion title and subtitle (189 ms)

● Accordion component › renders accordion title and subtitle

useLocation() may be used only in the context of a <Router> component.

  17 | }: AccordionProps) => {
  18 |     const [isOpen, setIsOpen] = useState(false)
> 19 |     const { pathname } = useLocation()
     |                                     ^
  20 |
  21 |     useEffect(() => {
  22 |         const isOpenInStorage = localStorage.getItem('isOpen')

解决方案

1. 修正测试代码的语法错误

你的测试代码存在语法问题:describe块的闭合括号位置错误,导致it测试用例写在了describe块外部,props变量无法在it中正确访问,组件也没有被正确纳入Router上下文。修正后将it放在describe内部:

import { render, screen } from '@testing-library/react'
import Accordion from '../Accordion'
import { BrowserRouter } from 'react-router-dom'

describe('Accordion component', () => {
    const props = {
       title: 'Test Title',
       subtitle: 'Test Subtitle',
       svg: '/test.svg',
       className: 'test-class',
       id: 'test-accordion',
       completed: true,
    }

    it('renders accordion title and subtitle', () => {
        render(
            <BrowserRouter>
                <Accordion {...props}>Content</Accordion>
            </BrowserRouter>
        )
        expect(screen.getByText('Test Title')).toBeInTheDocument()
        expect(screen.getByText('Test Subtitle')).toBeInTheDocument()
    })
})

2. 自定义render函数简化测试

如果需要多次测试依赖Router的组件,可以创建一个自动包裹Router的自定义render函数,避免重复编写BrowserRouter代码:

import { render as rtlRender } from '@testing-library/react'
import { BrowserRouter } from 'react-router-dom'

// 自定义render函数,默认用BrowserRouter作为包裹层
const render = (ui, options) => {
  return rtlRender(ui, { wrapper: BrowserRouter, ...options })
}

// 测试中直接使用该函数
describe('Accordion component', () => {
    const props = {
       title: 'Test Title',
       subtitle: 'Test Subtitle',
       svg: '/test.svg',
       className: 'test-class',
       id: 'test-accordion',
       completed: true,
    }

    it('renders accordion title and subtitle', () => {
        render(<Accordion {...props}>Content</Accordion>)
        expect(screen.getByText('Test Title')).toBeInTheDocument()
        expect(screen.getByText('Test Subtitle')).toBeInTheDocument()
    })
})

3. 确认react-router-dom版本兼容性

如果你使用的是react-router-dom v6+,确保导入的BrowserRouter是正确的,不要混用v5版本的Router组件(v5的Router需要手动传入history对象,而v6的BrowserRouter已经内置了history)。

内容的提问来源于stack exchange,提问作者Max Silva

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 17:03:40