mirror of
https://github.com/langgenius/dify.git
synced 2026-11-11 22:02:23 +08:00
227 lines
7.2 KiB
TypeScript
227 lines
7.2 KiB
TypeScript
/**
|
|
* Test suite for app redirection utility functions
|
|
* Tests navigation path generation based on user permissions and app modes
|
|
*/
|
|
|
|
import { AppACLPermission } from '@/utils/permission'
|
|
import { getRedirection, getRedirectionPath } from './app-redirection'
|
|
|
|
describe('app-redirection', () => {
|
|
/**
|
|
* Tests getRedirectionPath which determines the correct path based on:
|
|
* - App ACL layout access permissions
|
|
* - App ACL monitor, deploy, and access config permissions
|
|
* - App mode (workflow, advanced-chat, chat, completion, agent-chat)
|
|
*/
|
|
describe('getRedirectionPath', () => {
|
|
it('returns access point path when it is the only accessible app page', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'chat' as const,
|
|
permission_keys: [AppACLPermission.AccessPointView],
|
|
}
|
|
const result = getRedirectionPath(app)
|
|
expect(result).toBe('/app/app-123/access-point')
|
|
})
|
|
|
|
it('returns the app list when no app page is accessible', () => {
|
|
const app = { id: 'app-123', mode: 'chat' as const, permission_keys: [] }
|
|
|
|
expect(getRedirectionPath(app)).toBe('/apps')
|
|
})
|
|
|
|
it('does not redirect Access Point managers to a page they cannot view', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'chat' as const,
|
|
permission_keys: [AppACLPermission.AccessPointManage],
|
|
}
|
|
|
|
expect(getRedirectionPath(app)).toBe('/apps')
|
|
})
|
|
|
|
it('returns workflow path for workflow mode when app ACL can access layout', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'workflow' as const,
|
|
permission_keys: [AppACLPermission.ViewLayout],
|
|
}
|
|
const result = getRedirectionPath(app)
|
|
expect(result).toBe('/app/app-123/workflow')
|
|
})
|
|
|
|
it('returns workflow path for advanced-chat mode when app ACL can access layout', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'advanced-chat' as const,
|
|
permission_keys: [AppACLPermission.TestAndRun],
|
|
}
|
|
const result = getRedirectionPath(app)
|
|
expect(result).toBe('/app/app-123/workflow')
|
|
})
|
|
|
|
it('returns configuration path for chat mode when app ACL can access layout', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'chat' as const,
|
|
permission_keys: [AppACLPermission.Edit],
|
|
}
|
|
const result = getRedirectionPath(app)
|
|
expect(result).toBe('/app/app-123/configuration')
|
|
})
|
|
|
|
it('returns configuration path for completion mode when app ACL can access layout', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'completion' as const,
|
|
permission_keys: [AppACLPermission.ViewLayout],
|
|
}
|
|
const result = getRedirectionPath(app)
|
|
expect(result).toBe('/app/app-123/configuration')
|
|
})
|
|
|
|
it('returns configuration path for agent-chat mode when app ACL can access layout', () => {
|
|
const app = {
|
|
id: 'app-456',
|
|
mode: 'agent-chat' as const,
|
|
permission_keys: [AppACLPermission.ViewLayout],
|
|
}
|
|
const result = getRedirectionPath(app)
|
|
expect(result).toBe('/app/app-456/configuration')
|
|
})
|
|
|
|
it('returns the Agent configure path when the backing Agent ID is available', () => {
|
|
const app = {
|
|
id: 'app-1',
|
|
mode: 'agent' as const,
|
|
permission_keys: [AppACLPermission.ViewLayout],
|
|
bound_agent_id: 'agent-1',
|
|
}
|
|
|
|
expect(getRedirectionPath(app)).toBe('/agents/agent-1/configure')
|
|
})
|
|
|
|
it('falls back to the Agent roster when the backing Agent ID is unavailable', () => {
|
|
const app = {
|
|
id: 'app-1',
|
|
mode: 'agent' as const,
|
|
permission_keys: [AppACLPermission.ViewLayout],
|
|
}
|
|
|
|
expect(getRedirectionPath(app)).toBe('/agents')
|
|
})
|
|
|
|
it('returns layout path when the app maintainer has app.create_and_management permission without app ACL keys', () => {
|
|
const app = { id: 'app-123', mode: 'chat' as const, permission_keys: [] }
|
|
|
|
expect(
|
|
getRedirectionPath(app, {
|
|
currentUserId: 'user-1',
|
|
resourceMaintainer: 'user-1',
|
|
workspacePermissionKeys: ['app.create_and_management'],
|
|
}),
|
|
).toBe('/app/app-123/configuration')
|
|
})
|
|
|
|
it('returns access config path when app ACL can only configure access', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'chat' as const,
|
|
permission_keys: [AppACLPermission.AccessConfig],
|
|
}
|
|
|
|
expect(getRedirectionPath(app, { isRbacEnabled: true })).toBe('/app/app-123/access-config')
|
|
})
|
|
|
|
it('returns access point path when RBAC is disabled and Access Point remains accessible', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'chat' as const,
|
|
permission_keys: [AppACLPermission.AccessConfig, AppACLPermission.AccessPointView],
|
|
}
|
|
|
|
expect(getRedirectionPath(app, { isRbacEnabled: false })).toBe('/app/app-123/access-point')
|
|
})
|
|
|
|
it('returns overview path when app ACL can only monitor the app', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'chat' as const,
|
|
permission_keys: [AppACLPermission.Monitor],
|
|
}
|
|
|
|
expect(getRedirectionPath(app)).toBe('/app/app-123/overview')
|
|
})
|
|
|
|
it('returns logs path when app ACL can only access logs and annotations', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'chat' as const,
|
|
permission_keys: [AppACLPermission.LogAndAnnotation],
|
|
}
|
|
|
|
expect(getRedirectionPath(app)).toBe('/app/app-123/logs')
|
|
})
|
|
|
|
it('returns deploy path when a workflow app ACL can only deploy', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'workflow' as const,
|
|
permission_keys: [AppACLPermission.Deploy],
|
|
}
|
|
|
|
expect(getRedirectionPath(app)).toBe('/app/app-123/deploy')
|
|
})
|
|
})
|
|
|
|
/**
|
|
* Tests getRedirection which combines path generation with a redirect callback
|
|
*/
|
|
describe('getRedirection', () => {
|
|
/**
|
|
* Tests that the redirection function is called with the correct path
|
|
*/
|
|
it('calls redirection function with access point path when it is accessible', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'chat' as const,
|
|
permission_keys: [AppACLPermission.AccessPointView],
|
|
}
|
|
const mockRedirect = vi.fn()
|
|
|
|
getRedirection(app, mockRedirect)
|
|
|
|
expect(mockRedirect).toHaveBeenCalledWith('/app/app-123/access-point')
|
|
expect(mockRedirect).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('calls redirection function with workflow path when app ACL can access layout', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'workflow' as const,
|
|
permission_keys: [AppACLPermission.ViewLayout],
|
|
}
|
|
const mockRedirect = vi.fn()
|
|
|
|
getRedirection(app, mockRedirect)
|
|
|
|
expect(mockRedirect).toHaveBeenCalledWith('/app/app-123/workflow')
|
|
expect(mockRedirect).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('calls redirection function with configuration path for chat mode with layout access', () => {
|
|
const app = {
|
|
id: 'app-123',
|
|
mode: 'chat' as const,
|
|
permission_keys: [AppACLPermission.ViewLayout],
|
|
}
|
|
const mockRedirect = vi.fn()
|
|
|
|
getRedirection(app, mockRedirect)
|
|
|
|
expect(mockRedirect).toHaveBeenCalledWith('/app/app-123/configuration')
|
|
expect(mockRedirect).toHaveBeenCalledTimes(1)
|
|
})
|
|
})
|
|
})
|