mirror of https://github.com/langgenius/dify.git
151 lines
5.1 KiB
TypeScript
151 lines
5.1 KiB
TypeScript
import type { ReactNode } from 'react'
|
|
import { fireEvent, render, screen } from '@testing-library/react'
|
|
import * as React from 'react'
|
|
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
|
|
import RunMode from './run-mode'
|
|
import { TriggerType } from './test-run-menu'
|
|
|
|
const mockHandleWorkflowStartRunInWorkflow = vi.fn()
|
|
const mockHandleWorkflowTriggerScheduleRunInWorkflow = vi.fn()
|
|
const mockHandleWorkflowTriggerWebhookRunInWorkflow = vi.fn()
|
|
const mockHandleWorkflowTriggerPluginRunInWorkflow = vi.fn()
|
|
const mockHandleWorkflowRunAllTriggersInWorkflow = vi.fn()
|
|
const mockHandleStopRun = vi.fn()
|
|
const mockNotify = vi.fn()
|
|
const mockTrackEvent = vi.fn()
|
|
|
|
let mockWarningNodes: Array<{ id: string }> = []
|
|
let mockWorkflowRunningData: { result: { status: WorkflowRunningStatus }, task_id: string } | undefined
|
|
let mockIsListening = false
|
|
let mockDynamicOptions = [
|
|
{ type: TriggerType.UserInput, nodeId: 'start-node' },
|
|
]
|
|
|
|
vi.mock('@/app/components/workflow/hooks', () => ({
|
|
useWorkflowStartRun: () => ({
|
|
handleWorkflowStartRunInWorkflow: mockHandleWorkflowStartRunInWorkflow,
|
|
handleWorkflowTriggerScheduleRunInWorkflow: mockHandleWorkflowTriggerScheduleRunInWorkflow,
|
|
handleWorkflowTriggerWebhookRunInWorkflow: mockHandleWorkflowTriggerWebhookRunInWorkflow,
|
|
handleWorkflowTriggerPluginRunInWorkflow: mockHandleWorkflowTriggerPluginRunInWorkflow,
|
|
handleWorkflowRunAllTriggersInWorkflow: mockHandleWorkflowRunAllTriggersInWorkflow,
|
|
}),
|
|
useWorkflowRun: () => ({
|
|
handleStopRun: mockHandleStopRun,
|
|
}),
|
|
useWorkflowRunValidation: () => ({
|
|
warningNodes: mockWarningNodes,
|
|
}),
|
|
}))
|
|
|
|
vi.mock('@/app/components/workflow/store', () => ({
|
|
useStore: (selector: (state: { workflowRunningData?: unknown, isListening: boolean }) => unknown) =>
|
|
selector({ workflowRunningData: mockWorkflowRunningData, isListening: mockIsListening }),
|
|
}))
|
|
|
|
vi.mock('../hooks/use-dynamic-test-run-options', () => ({
|
|
useDynamicTestRunOptions: () => mockDynamicOptions,
|
|
}))
|
|
|
|
vi.mock('@/app/components/base/toast/context', () => ({
|
|
useToastContext: () => ({
|
|
notify: mockNotify,
|
|
}),
|
|
}))
|
|
|
|
vi.mock('@/app/components/base/amplitude', () => ({
|
|
trackEvent: (...args: unknown[]) => mockTrackEvent(...args),
|
|
}))
|
|
|
|
vi.mock('@/context/event-emitter', () => ({
|
|
useEventEmitterContextContext: () => ({
|
|
eventEmitter: {
|
|
useSubscription: vi.fn(),
|
|
},
|
|
}),
|
|
}))
|
|
|
|
vi.mock('@/app/components/workflow/shortcuts-name', () => ({
|
|
default: () => <span data-testid="shortcuts-name">Shortcut</span>,
|
|
}))
|
|
|
|
vi.mock('@/app/components/base/icons/src/vender/line/mediaAndDevices', () => ({
|
|
StopCircle: () => <span data-testid="stop-circle" />,
|
|
}))
|
|
|
|
vi.mock('./test-run-menu', async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import('./test-run-menu')>()
|
|
return {
|
|
...actual,
|
|
default: React.forwardRef(({ children, options, onSelect }: { children: ReactNode, options: Array<{ type: TriggerType, nodeId?: string, relatedNodeIds?: string[] }>, onSelect: (option: { type: TriggerType, nodeId?: string, relatedNodeIds?: string[] }) => void }, ref) => {
|
|
React.useImperativeHandle(ref, () => ({
|
|
toggle: vi.fn(),
|
|
}))
|
|
return (
|
|
<div>
|
|
<button data-testid="trigger-option" onClick={() => onSelect(options[0])}>
|
|
Trigger option
|
|
</button>
|
|
{children}
|
|
</div>
|
|
)
|
|
}),
|
|
}
|
|
})
|
|
|
|
describe('RunMode', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
mockWarningNodes = []
|
|
mockWorkflowRunningData = undefined
|
|
mockIsListening = false
|
|
mockDynamicOptions = [
|
|
{ type: TriggerType.UserInput, nodeId: 'start-node' },
|
|
]
|
|
})
|
|
|
|
it('should render the run trigger and start the workflow when a valid trigger is selected', () => {
|
|
render(<RunMode />)
|
|
|
|
expect(screen.getByText(/run/i)).toBeInTheDocument()
|
|
fireEvent.click(screen.getByTestId('trigger-option'))
|
|
|
|
expect(mockHandleWorkflowStartRunInWorkflow).toHaveBeenCalledTimes(1)
|
|
expect(mockTrackEvent).toHaveBeenCalledWith('app_start_action_time', { action_type: 'user_input' })
|
|
})
|
|
|
|
it('should show an error toast instead of running when the selected trigger has checklist warnings', () => {
|
|
mockWarningNodes = [{ id: 'start-node' }]
|
|
|
|
render(<RunMode />)
|
|
fireEvent.click(screen.getByTestId('trigger-option'))
|
|
|
|
expect(mockNotify).toHaveBeenCalledWith({
|
|
type: 'error',
|
|
message: 'workflow.panel.checklistTip',
|
|
})
|
|
expect(mockHandleWorkflowStartRunInWorkflow).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('should render the running state and stop the workflow when it is already running', () => {
|
|
mockWorkflowRunningData = {
|
|
result: { status: WorkflowRunningStatus.Running },
|
|
task_id: 'task-1',
|
|
}
|
|
|
|
render(<RunMode />)
|
|
|
|
expect(screen.getByText(/running/i)).toBeInTheDocument()
|
|
fireEvent.click(screen.getByTestId('stop-circle').closest('button') as HTMLButtonElement)
|
|
|
|
expect(mockHandleStopRun).toHaveBeenCalledWith('task-1')
|
|
})
|
|
|
|
it('should render the listening label when the workflow is listening', () => {
|
|
mockIsListening = true
|
|
|
|
render(<RunMode />)
|
|
|
|
expect(screen.getByText(/listening/i)).toBeInTheDocument()
|
|
})
|
|
})
|