151 lines
4.3 KiB
TypeScript
151 lines
4.3 KiB
TypeScript
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);
|
|
});
|
|
});
|