Files
dify/web/app/components/app/overview/__tests__/toggle-logic.test.ts
Coding On Star dbecba710b frontend auto testing rules (#28679)
Co-authored-by: CodingOnStar <hanxujiang@dify.ai>
Co-authored-by: 姜涵煦 <hanxujiang@jianghanxudeMacBook-Pro.local>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-11-26 15:18:07 +08:00

233 lines
6.9 KiB
TypeScript

import { getWorkflowEntryNode } from '@/app/components/workflow/utils/workflow-entry'
import type { Node } from '@/app/components/workflow/types'
// Mock the getWorkflowEntryNode function
jest.mock('@/app/components/workflow/utils/workflow-entry', () => ({
getWorkflowEntryNode: jest.fn(),
}))
const mockGetWorkflowEntryNode = getWorkflowEntryNode as jest.MockedFunction<typeof getWorkflowEntryNode>
// Mock entry node for testing (truthy value)
const mockEntryNode = { id: 'start-node', data: { type: 'start' } } as Node
describe('App Card Toggle Logic', () => {
beforeEach(() => {
jest.clearAllMocks()
})
// Helper function that mirrors the actual logic from app-card.tsx
const calculateToggleState = (
appMode: string,
currentWorkflow: any,
isCurrentWorkspaceEditor: boolean,
isCurrentWorkspaceManager: boolean,
cardType: 'webapp' | 'api',
) => {
const isWorkflowApp = appMode === 'workflow'
const appUnpublished = isWorkflowApp && !currentWorkflow?.graph
const hasEntryNode = mockGetWorkflowEntryNode(currentWorkflow?.graph?.nodes || [])
const missingEntryNode = isWorkflowApp && !hasEntryNode
const hasInsufficientPermissions = cardType === 'webapp' ? !isCurrentWorkspaceEditor : !isCurrentWorkspaceManager
const toggleDisabled = hasInsufficientPermissions || appUnpublished || missingEntryNode
const isMinimalState = appUnpublished || missingEntryNode
return {
toggleDisabled,
isMinimalState,
appUnpublished,
missingEntryNode,
hasInsufficientPermissions,
}
}
describe('Entry Node Detection Logic', () => {
it('should disable toggle when workflow missing entry node', () => {
mockGetWorkflowEntryNode.mockReturnValue(undefined)
const result = calculateToggleState(
'workflow',
{ graph: { nodes: [] } },
true,
true,
'webapp',
)
expect(result.toggleDisabled).toBe(true)
expect(result.missingEntryNode).toBe(true)
expect(result.isMinimalState).toBe(true)
})
it('should enable toggle when workflow has entry node', () => {
mockGetWorkflowEntryNode.mockReturnValue(mockEntryNode)
const result = calculateToggleState(
'workflow',
{ graph: { nodes: [{ data: { type: 'start' } }] } },
true,
true,
'webapp',
)
expect(result.toggleDisabled).toBe(false)
expect(result.missingEntryNode).toBe(false)
expect(result.isMinimalState).toBe(false)
})
})
describe('Published State Logic', () => {
it('should disable toggle when workflow unpublished (no graph)', () => {
const result = calculateToggleState(
'workflow',
null, // No workflow data = unpublished
true,
true,
'webapp',
)
expect(result.toggleDisabled).toBe(true)
expect(result.appUnpublished).toBe(true)
expect(result.isMinimalState).toBe(true)
})
it('should disable toggle when workflow unpublished (empty graph)', () => {
const result = calculateToggleState(
'workflow',
{}, // No graph property = unpublished
true,
true,
'webapp',
)
expect(result.toggleDisabled).toBe(true)
expect(result.appUnpublished).toBe(true)
expect(result.isMinimalState).toBe(true)
})
it('should consider published state when workflow has graph', () => {
mockGetWorkflowEntryNode.mockReturnValue(mockEntryNode)
const result = calculateToggleState(
'workflow',
{ graph: { nodes: [] } },
true,
true,
'webapp',
)
expect(result.appUnpublished).toBe(false)
})
})
describe('Permissions Logic', () => {
it('should disable webapp toggle when user lacks editor permissions', () => {
mockGetWorkflowEntryNode.mockReturnValue(mockEntryNode)
const result = calculateToggleState(
'workflow',
{ graph: { nodes: [] } },
false, // No editor permission
true,
'webapp',
)
expect(result.toggleDisabled).toBe(true)
expect(result.hasInsufficientPermissions).toBe(true)
})
it('should disable api toggle when user lacks manager permissions', () => {
mockGetWorkflowEntryNode.mockReturnValue(mockEntryNode)
const result = calculateToggleState(
'workflow',
{ graph: { nodes: [] } },
true,
false, // No manager permission
'api',
)
expect(result.toggleDisabled).toBe(true)
expect(result.hasInsufficientPermissions).toBe(true)
})
it('should enable toggle when user has proper permissions', () => {
mockGetWorkflowEntryNode.mockReturnValue(mockEntryNode)
const webappResult = calculateToggleState(
'workflow',
{ graph: { nodes: [] } },
true, // Has editor permission
false,
'webapp',
)
const apiResult = calculateToggleState(
'workflow',
{ graph: { nodes: [] } },
false,
true, // Has manager permission
'api',
)
expect(webappResult.toggleDisabled).toBe(false)
expect(apiResult.toggleDisabled).toBe(false)
})
})
describe('Combined Conditions Logic', () => {
it('should handle multiple disable conditions correctly', () => {
mockGetWorkflowEntryNode.mockReturnValue(undefined)
const result = calculateToggleState(
'workflow',
null, // Unpublished
false, // No permissions
false,
'webapp',
)
// All three conditions should be true
expect(result.appUnpublished).toBe(true)
expect(result.missingEntryNode).toBe(true)
expect(result.hasInsufficientPermissions).toBe(true)
expect(result.toggleDisabled).toBe(true)
expect(result.isMinimalState).toBe(true)
})
it('should enable when all conditions are satisfied', () => {
mockGetWorkflowEntryNode.mockReturnValue(mockEntryNode)
const result = calculateToggleState(
'workflow',
{ graph: { nodes: [{ data: { type: 'start' } }] } }, // Published
true, // Has permissions
true,
'webapp',
)
expect(result.appUnpublished).toBe(false)
expect(result.missingEntryNode).toBe(false)
expect(result.hasInsufficientPermissions).toBe(false)
expect(result.toggleDisabled).toBe(false)
expect(result.isMinimalState).toBe(false)
})
})
describe('Non-Workflow Apps', () => {
it('should not check workflow-specific conditions for non-workflow apps', () => {
const result = calculateToggleState(
'chat', // Non-workflow mode
null,
true,
true,
'webapp',
)
expect(result.appUnpublished).toBe(false) // isWorkflowApp is false
expect(result.missingEntryNode).toBe(false) // isWorkflowApp is false
expect(result.toggleDisabled).toBe(false)
expect(result.isMinimalState).toBe(false)
})
})
})