使用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
相关产品推荐
相关产品推荐

