Next.js13中使用useSelectedLayoutSegments时Cypress组件测试失败
解决Next.js 13 useSelectedLayoutSegments在Cypress组件测试中的报错问题
问题原因
useSelectedLayoutSegments是Next.js App Router提供的路由钩子,它依赖Next.js内部的路由上下文(RouterContext)才能正常工作。但Cypress组件测试的孤立环境中并没有自动注入这个上下文,直接挂载组件会因上下文缺失抛出Cannot read properties of null (reading 'tree')错误。
解决方案
1. 手动模拟路由上下文
在测试文件中,用Next.js提供的RouterContext.Provider包裹组件,注入模拟的路由上下文值:
import { mount } from 'cypress/react' import { RouterContext } from 'next/dist/shared/lib/router-context' import Navigation from '../../app/components/Navigation' describe('Navigation Component', () => { it('mounts without error', () => { mount( <RouterContext.Provider value={{ tree: { segments: ['home'] }, // 模拟当前路由片段,可根据需求修改 // 按需添加其他必要上下文属性,比如push、replace等 }}> <Navigation /> </RouterContext.Provider> ) }) })
2. 组件层面做兼容处理
在导航组件中添加对路由上下文缺失的判断,避免报错:
'use client' import { useSelectedLayoutSegments } from 'next/navigation' export default function Navigation() { // 给钩子返回值设置默认空数组,防止上下文缺失时抛出错误 const segments = useSelectedLayoutSegments() || [] // 高亮逻辑:匹配嵌套路由的父项 const isActive = (path: string) => { const pathSegments = path.split('/').filter(Boolean) return segments.some((seg, idx) => seg === pathSegments[idx]) } return ( <nav> <a href="/home" className={isActive('/home') ? 'active' : ''}>首页</a> <a href="/about/team" className={isActive('/about/team') ? 'active' : ''}>团队介绍</a> </nav> ) }
3. 模拟useRouter钩子(可选)
如果需要更完整的路由模拟,可直接mocknext/navigation中的相关钩子:
import { mount } from 'cypress/react' import Navigation from '../../app/components/Navigation' // 模拟useSelectedLayoutSegments的返回值 jest.mock('next/navigation', () => ({ useSelectedLayoutSegments: () => ['about', 'team'], })) describe('Navigation Component', () => { it('mounts and highlights active nested item', () => { mount(<Navigation />) // 可添加断言验证导航项高亮状态 cy.get('a.active').should('have.attr', 'href', '/about/team') }) })
注意事项
- 确保导航组件标记为
'use client',因为useSelectedLayoutSegments仅能在客户端组件中使用。 - 模拟路由片段时,要和实际路由结构匹配,才能准确测试导航高亮逻辑。
内容的提问来源于stack exchange,提问作者CDK
相关产品推荐
相关产品推荐

