Files
dify/web/utils/app-redirection.spec.ts
T

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)
})
})
})