Files
ebiz-h5/tests/unit/underwriting/navigate.spec.js
hz 4d684c2797 refactor(navigate): 重构路由查找逻辑以支持任意深度嵌套
- 实现递归查找路由函数,支持多层嵌套路由的定位
- 新增通过路径和名称两种方式查找路由的功能
- 添加构建完整路由路径的工具函数
- 完善路由查找相关单元测试覆盖
- 优化路径规范化处理,去除多余斜杠
- 改进错误处理逻辑,提升代码健壮性
2025-12-19 18:08:23 +08:00

329 lines
9.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 模拟路由配置数据,基于实际项目结构
const mockRoutes = [
{
path: '/underwriting',
name: 'PreliminaryUnderwriting',
component: () => import('@/views/ebiz/underwriting/PreliminaryUnderwritingContainer.vue'),
children: [
{
path: 'list',
name: 'UnderwritingOrderList',
meta: { title: '预核保订单列表' },
component: () => import('@/views/ebiz/underwriting/OrderList.vue')
},
{
path: 'data-collection',
name: 'UnderwritingDataCollection',
meta: { title: '信息录入' },
component: () => import('@/views/ebiz/underwriting/UnderwritingDataCollection.vue')
},
{
path: 'supplementary-information',
name: 'UnderwritingSupplementaryInformation',
meta: { title: '补传资料' },
component: () => import('@/views/ebiz/underwriting/SupplementaryInformation.vue')
},
{
path: 'result',
name: 'UnderwritingResult',
meta: { title: '预核保结果' },
component: () => import('@/views/ebiz/underwriting/Result.vue')
},
{
path: 'contract-sign',
name: 'UnderwritingContractSign',
meta: { title: '签名确认' },
component: () => import('@/views/ebiz/underwriting/SignContract.vue')
},
{
path: 'document-info',
name: 'UnderwritingDocumentInfo',
meta: { title: '预核保资料' },
component: () => import('@/views/ebiz/underwriting/DocumentInfo.vue')
}
]
},
{
path: '/other',
name: 'Other',
component: () => import('@/views/other/OtherContainer.vue'),
children: [
{
path: 'nested',
name: 'Nested',
component: () => import('@/views/other/Nested.vue'),
children: [
{
path: 'deep',
name: 'DeepNested',
meta: { title: '深层嵌套路由' },
component: () => import('@/views/other/DeepNested.vue')
}
]
}
]
},
{
path: '/',
name: 'Home',
component: () => import('@/views/Home.vue')
},
{
path: '/simple',
name: 'SimpleRoute',
meta: { title: '简单路由' },
component: () => import('@/views/Simple.vue')
}
];
/**
* 递归查找具有指定路径的路由(支持多层嵌套)
* @param routes 路由数组
* @param targetPath 目标路径
* @param parentPath 父级路径
* @returns 匹配的路由信息或undefined
*/
function findRouteByPath(routes, targetPath, parentPath = '') {
if (!routes || !Array.isArray(routes)) return undefined
// 规范化目标路径,移除多余的斜杠
targetPath = targetPath.replace(/\/+/g, '/')
for (const route of routes) {
// 构造当前路由的完整路径
let currentPath = parentPath
if (currentPath && !currentPath.endsWith('/') && route.path && !route.path.startsWith('/')) {
currentPath += '/' + route.path
} else {
currentPath += route.path
}
// 移除多余的斜杠
currentPath = currentPath.replace(/\/+/g, '/')
// 检查当前路由是否匹配
if (currentPath === targetPath) {
return {
route: route,
fullPath: currentPath
}
}
// 递归检查子路由
if (route.children && route.children.length > 0) {
const matchedChild = findRouteByPath(route.children, targetPath, currentPath)
if (matchedChild) {
return matchedChild
}
}
}
return undefined
}
/**
* 递归查找具有指定名称的路由(支持多层嵌套)
* @param routes 路由数组
* @param targetName 目标名称
* @param routeStack 用于追踪路由层级的堆栈
* @returns 包含路由和路由堆栈的对象或undefined
*/
function findRouteByName(routes, targetName, routeStack = []) {
if (!routes || !Array.isArray(routes)) return undefined
for (const route of routes) {
// 创建当前路由的堆栈副本
const currentStack = [...routeStack, route]
// 检查当前路由是否匹配
if (route.name === targetName) {
return {
route: route,
routeStack: currentStack
}
}
// 递归检查子路由
if (route.children && route.children.length > 0) {
const matchedChild = findRouteByName(route.children, targetName, currentStack)
if (matchedChild) {
return matchedChild
}
}
}
return undefined
}
/**
* 根据路由堆栈构建完整路径
* @param routeStack 路由堆栈
* @returns 完整路径字符串
*/
function buildFullPath(routeStack) {
if (!routeStack || routeStack.length === 0) return ''
// 提取所有路由的路径并正确拼接
let fullPath = ''
routeStack.forEach((route, index) => {
// 特殊处理第一个路由
if (index === 0) {
fullPath += route.path
} else {
if (fullPath && !fullPath.endsWith('/') && route.path && !route.path.startsWith('/')) {
fullPath += '/' + route.path
} else if (fullPath.endsWith('/') && route.path.startsWith('/')) {
// 如果fullPath以/结尾而route.path以/开头,则需要去掉一个/
fullPath += route.path.substring(1)
} else {
fullPath += route.path
}
}
})
// 移除多余的斜杠
fullPath = fullPath.replace(/\/+/g, '/')
// 确保不会在末尾留下斜杠(除非是根路径)
if (fullPath.length > 1 && fullPath.endsWith('/')) {
fullPath = fullPath.slice(0, -1)
}
return fullPath
}
describe('Underwriting Navigate Functions', () => {
describe('findRouteByPath', () => {
it('应该能找到根路径路由', () => {
const result = findRouteByPath(mockRoutes, '/')
expect(result).not.toBeUndefined()
expect(result.route.name).toBe('Home')
})
it('应该能找到简单路径路由', () => {
const result = findRouteByPath(mockRoutes, '/simple')
expect(result).not.toBeUndefined()
expect(result.route.name).toBe('SimpleRoute')
})
it('应该能找到一级嵌套路由', () => {
const result = findRouteByPath(mockRoutes, '/underwriting')
expect(result).not.toBeUndefined()
expect(result.route.name).toBe('PreliminaryUnderwriting')
})
it('应该能找到二级嵌套路由', () => {
const result = findRouteByPath(mockRoutes, '/underwriting/list')
expect(result).not.toBeUndefined()
expect(result.route.name).toBe('UnderwritingOrderList')
})
it('应该能找到三级嵌套路由', () => {
const result = findRouteByPath(mockRoutes, '/other/nested/deep')
expect(result).not.toBeUndefined()
expect(result.route.name).toBe('DeepNested')
})
it('应该返回undefined当找不到路由时', () => {
const result = findRouteByPath(mockRoutes, '/nonexistent')
expect(result).toBeUndefined()
})
it('应该正确处理带有多个斜杠的路径', () => {
// 实际上我们查找的是 /underwriting/list只是输入路径中有多余的斜杠
const result = findRouteByPath(mockRoutes, '/underwriting///list')
expect(result).not.toBeUndefined()
expect(result.route.name).toBe('UnderwritingOrderList')
})
})
describe('findRouteByName', () => {
it('应该通过名称找到根路径路由', () => {
const result = findRouteByName(mockRoutes, 'Home')
expect(result).not.toBeUndefined()
expect(result.route.name).toBe('Home')
})
it('应该通过名称找到简单路径路由', () => {
const result = findRouteByName(mockRoutes, 'SimpleRoute')
expect(result).not.toBeUndefined()
expect(result.route.name).toBe('SimpleRoute')
})
it('应该通过名称找到一级嵌套路由', () => {
const result = findRouteByName(mockRoutes, 'PreliminaryUnderwriting')
expect(result).not.toBeUndefined()
expect(result.route.name).toBe('PreliminaryUnderwriting')
})
it('应该通过名称找到二级嵌套路由', () => {
const result = findRouteByName(mockRoutes, 'UnderwritingOrderList')
expect(result).not.toBeUndefined()
expect(result.route.name).toBe('UnderwritingOrderList')
})
it('应该通过名称找到三级嵌套路由', () => {
const result = findRouteByName(mockRoutes, 'DeepNested')
expect(result).not.toBeUndefined()
expect(result.route.name).toBe('DeepNested')
})
it('应该返回undefined当找不到路由时', () => {
const result = findRouteByName(mockRoutes, 'NonExistent')
expect(result).toBeUndefined()
})
})
describe('buildFullPath', () => {
it('应该正确构建根路径', () => {
const routeStack = [{ path: '/' }]
const result = buildFullPath(routeStack)
expect(result).toBe('/')
})
it('应该正确构建简单路径', () => {
const routeStack = [
{ path: '/' },
{ path: 'simple' }
]
const result = buildFullPath(routeStack)
expect(result).toBe('/simple')
})
it('应该正确构建嵌套路径', () => {
const routeStack = [
{ path: '/underwriting' },
{ path: 'list' }
]
const result = buildFullPath(routeStack)
expect(result).toBe('/underwriting/list')
})
it('应该正确构建深层嵌套路径', () => {
const routeStack = [
{ path: '/other' },
{ path: 'nested' },
{ path: 'deep' }
]
const result = buildFullPath(routeStack)
expect(result).toBe('/other/nested/deep')
})
it('应该正确处理空路由堆栈', () => {
const result = buildFullPath([])
expect(result).toBe('')
})
it('应该正确处理多余的斜杠', () => {
const routeStack = [
{ path: '/underwriting/' },
{ path: '/list/' }
]
const result = buildFullPath(routeStack)
// 由于路径规范化处理,结果应该是 /underwriting/list 而不是 /underwriting//list
expect(result).toBe('/underwriting/list')
})
})
})