Files
dify/web/app/components/workflow/__tests__/node-contextmenu.spec.tsx
Coding On Star 7fbb1c96db feat(workflow): add selection context menu helpers and integrate with context menu component (#34013)
Co-authored-by: CodingOnStar <hanxujiang@dify.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: lif <1835304752@qq.com>
Co-authored-by: hjlarry <hjlarry@163.com>
Co-authored-by: Stephen Zhou <hi@hyoban.cc>
Co-authored-by: tmimmanuel <14046872+tmimmanuel@users.noreply.github.com>
Co-authored-by: Desel72 <pedroluiscolmenares722@gmail.com>
Co-authored-by: Renzo <170978465+RenzoMXD@users.noreply.github.com>
Co-authored-by: Krishna Chaitanya <krishnabkc15@gmail.com>
Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-25 17:21:48 +08:00

115 lines
3.5 KiB
TypeScript

import type { Node } from '../types'
import { fireEvent, render, screen } from '@testing-library/react'
import NodeContextmenu from '../node-contextmenu'
const mockUseClickAway = vi.hoisted(() => vi.fn())
const mockUseNodes = vi.hoisted(() => vi.fn())
const mockUsePanelInteractions = vi.hoisted(() => vi.fn())
const mockUseStore = vi.hoisted(() => vi.fn())
const mockPanelOperatorPopup = vi.hoisted(() => vi.fn())
vi.mock('ahooks', () => ({
useClickAway: (...args: unknown[]) => mockUseClickAway(...args),
}))
vi.mock('@/app/components/workflow/store/workflow/use-nodes', () => ({
__esModule: true,
default: () => mockUseNodes(),
}))
vi.mock('@/app/components/workflow/hooks', () => ({
usePanelInteractions: () => mockUsePanelInteractions(),
}))
vi.mock('@/app/components/workflow/store', () => ({
useStore: (selector: (state: { nodeMenu?: { nodeId: string, left: number, top: number } }) => unknown) => mockUseStore(selector),
}))
vi.mock('@/app/components/workflow/nodes/_base/components/panel-operator/panel-operator-popup', () => ({
__esModule: true,
default: (props: {
id: string
data: Node['data']
showHelpLink: boolean
onClosePopup: () => void
}) => {
mockPanelOperatorPopup(props)
return (
<button type="button" onClick={props.onClosePopup}>
{props.id}
:
{props.data.title}
</button>
)
},
}))
describe('NodeContextmenu', () => {
const mockHandleNodeContextmenuCancel = vi.fn()
let nodeMenu: { nodeId: string, left: number, top: number } | undefined
let nodes: Node[]
let clickAwayHandler: (() => void) | undefined
beforeEach(() => {
vi.clearAllMocks()
nodeMenu = undefined
nodes = [{
id: 'node-1',
type: 'custom',
position: { x: 0, y: 0 },
data: {
title: 'Node 1',
desc: '',
type: 'code' as never,
},
} as Node]
clickAwayHandler = undefined
mockUseClickAway.mockImplementation((handler: () => void) => {
clickAwayHandler = handler
})
mockUseNodes.mockImplementation(() => nodes)
mockUsePanelInteractions.mockReturnValue({
handleNodeContextmenuCancel: mockHandleNodeContextmenuCancel,
})
mockUseStore.mockImplementation((selector: (state: { nodeMenu?: { nodeId: string, left: number, top: number } }) => unknown) => selector({ nodeMenu }))
})
it('should stay hidden when the node menu is absent', () => {
render(<NodeContextmenu />)
expect(screen.queryByRole('button')).not.toBeInTheDocument()
expect(mockPanelOperatorPopup).not.toHaveBeenCalled()
})
it('should stay hidden when the referenced node cannot be found', () => {
nodeMenu = { nodeId: 'missing-node', left: 80, top: 120 }
render(<NodeContextmenu />)
expect(screen.queryByRole('button')).not.toBeInTheDocument()
expect(mockPanelOperatorPopup).not.toHaveBeenCalled()
})
it('should render the popup at the stored position and close on popup/click-away actions', () => {
nodeMenu = { nodeId: 'node-1', left: 80, top: 120 }
const { container } = render(<NodeContextmenu />)
expect(screen.getByRole('button')).toHaveTextContent('node-1:Node 1')
expect(mockPanelOperatorPopup).toHaveBeenCalledWith(expect.objectContaining({
id: 'node-1',
data: expect.objectContaining({ title: 'Node 1' }),
showHelpLink: true,
}))
expect(container.firstChild).toHaveStyle({
left: '80px',
top: '120px',
})
fireEvent.click(screen.getByRole('button'))
clickAwayHandler?.()
expect(mockHandleNodeContextmenuCancel).toHaveBeenCalledTimes(2)
})
})