fix: 修复页签路由切换页面未更新
- 拆分页签分组与页面渲染身份,确保列表和详情正确切换 - 让禁用缓存的路由绕过 KeepAlive,并补充资源切换回归测试
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router';
|
||||
|
||||
import { getTabKey } from '@easyflow/stores';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { getRouteViewKey, shouldUseKeepAlive } from './route-view';
|
||||
|
||||
interface RouteOptions {
|
||||
fullPath: string;
|
||||
id?: string;
|
||||
keepAlive?: boolean;
|
||||
name: string;
|
||||
navTitle?: string;
|
||||
pageKey?: string;
|
||||
paramId?: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
function createRoute(
|
||||
options: RouteOptions,
|
||||
): RouteLocationNormalizedLoadedGeneric {
|
||||
const query: Record<string, string> = {};
|
||||
if (options.id) {
|
||||
query.id = options.id;
|
||||
}
|
||||
if (options.navTitle) {
|
||||
query.navTitle = options.navTitle;
|
||||
}
|
||||
if (options.pageKey) {
|
||||
query.pageKey = options.pageKey;
|
||||
}
|
||||
return {
|
||||
fullPath: options.fullPath,
|
||||
hash: '',
|
||||
matched: [],
|
||||
meta: {
|
||||
keepAlive: options.keepAlive,
|
||||
title: options.name,
|
||||
},
|
||||
name: options.name,
|
||||
params: options.paramId ? { id: options.paramId } : {},
|
||||
path: options.path,
|
||||
query,
|
||||
redirectedFrom: undefined,
|
||||
} as RouteLocationNormalizedLoadedGeneric;
|
||||
}
|
||||
|
||||
describe('route view identity', () => {
|
||||
it('separates list and detail rendering while preserving one tab key', () => {
|
||||
const listRoute = createRoute({
|
||||
fullPath: '/ai/workflow',
|
||||
keepAlive: false,
|
||||
name: 'WorkflowList',
|
||||
path: '/ai/workflow',
|
||||
});
|
||||
const designRoute = createRoute({
|
||||
fullPath:
|
||||
'/ai/workflow/design?id=1&pageKey=/ai/workflow&navTitle=Workflow',
|
||||
id: '1',
|
||||
name: 'WorkflowDesign',
|
||||
navTitle: 'Workflow',
|
||||
pageKey: '/ai/workflow',
|
||||
path: '/ai/workflow/design',
|
||||
});
|
||||
|
||||
expect(getTabKey(listRoute)).toBe('/ai/workflow');
|
||||
expect(getTabKey(designRoute)).toBe('/ai/workflow');
|
||||
expect(getRouteViewKey(listRoute)).not.toBe(getRouteViewKey(designRoute));
|
||||
});
|
||||
|
||||
it('keeps title-only query changes on the same component instance', () => {
|
||||
const firstRoute = createRoute({
|
||||
fullPath: '/ai/workflow/design?id=1&pageKey=/ai/workflow&navTitle=First',
|
||||
id: '1',
|
||||
name: 'WorkflowDesign',
|
||||
navTitle: 'First',
|
||||
pageKey: '/ai/workflow',
|
||||
path: '/ai/workflow/design',
|
||||
});
|
||||
const renamedRoute = createRoute({
|
||||
fullPath:
|
||||
'/ai/workflow/design?id=1&pageKey=/ai/workflow&navTitle=Renamed',
|
||||
id: '1',
|
||||
name: 'WorkflowDesign',
|
||||
navTitle: 'Renamed',
|
||||
pageKey: '/ai/workflow',
|
||||
path: '/ai/workflow/design',
|
||||
});
|
||||
|
||||
expect(getRouteViewKey(firstRoute)).toBe(getRouteViewKey(renamedRoute));
|
||||
});
|
||||
|
||||
it('replaces the component instance when the resource id changes', () => {
|
||||
const firstRoute = createRoute({
|
||||
fullPath: '/ai/workflow/design?id=1&pageKey=/ai/workflow',
|
||||
id: '1',
|
||||
name: 'WorkflowDesign',
|
||||
pageKey: '/ai/workflow',
|
||||
path: '/ai/workflow/design',
|
||||
});
|
||||
const secondRoute = createRoute({
|
||||
fullPath: '/ai/workflow/design?id=2&pageKey=/ai/workflow',
|
||||
id: '2',
|
||||
name: 'WorkflowDesign',
|
||||
pageKey: '/ai/workflow',
|
||||
path: '/ai/workflow/design',
|
||||
});
|
||||
|
||||
expect(getRouteViewKey(firstRoute)).not.toBe(getRouteViewKey(secondRoute));
|
||||
});
|
||||
|
||||
it('separates path-param resources that share a tab key', () => {
|
||||
const firstRoute = createRoute({
|
||||
fullPath: '/ai/agents/designer/1?pageKey=/ai/agents',
|
||||
name: 'AgentDesigner',
|
||||
pageKey: '/ai/agents',
|
||||
paramId: '1',
|
||||
path: '/ai/agents/designer/1',
|
||||
});
|
||||
const secondRoute = createRoute({
|
||||
fullPath: '/ai/agents/designer/2?pageKey=/ai/agents',
|
||||
name: 'AgentDesigner',
|
||||
pageKey: '/ai/agents',
|
||||
paramId: '2',
|
||||
path: '/ai/agents/designer/2',
|
||||
});
|
||||
|
||||
expect(getRouteViewKey(firstRoute)).not.toBe(getRouteViewKey(secondRoute));
|
||||
});
|
||||
|
||||
it('bypasses KeepAlive only when caching is explicitly disabled', () => {
|
||||
const uncachedRoute = createRoute({
|
||||
fullPath: '/ai/workflow',
|
||||
keepAlive: false,
|
||||
name: 'WorkflowList',
|
||||
path: '/ai/workflow',
|
||||
});
|
||||
const defaultRoute = createRoute({
|
||||
fullPath: '/ai/workflow/design?id=1',
|
||||
id: '1',
|
||||
name: 'WorkflowDesign',
|
||||
path: '/ai/workflow/design',
|
||||
});
|
||||
|
||||
expect(shouldUseKeepAlive(uncachedRoute, true)).toBe(false);
|
||||
expect(shouldUseKeepAlive(defaultRoute, true)).toBe(true);
|
||||
expect(shouldUseKeepAlive(defaultRoute, false)).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user