mirror of
https://github.com/langgenius/dify.git
synced 2026-04-25 21:26:15 +08:00
288 lines
9.9 KiB
TypeScript
288 lines
9.9 KiB
TypeScript
import type { TriggerEvent } from '@/app/components/plugins/types'
|
|
import type { TriggerProviderApiEntity } from '@/app/components/workflow/block-selector/types'
|
|
import { fireEvent, render, screen } from '@testing-library/react'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { EventDetailDrawer } from './event-detail-drawer'
|
|
|
|
vi.mock('react-i18next', () => ({
|
|
useTranslation: () => ({
|
|
t: (key: string) => key,
|
|
}),
|
|
}))
|
|
|
|
vi.mock('@/app/components/header/account-setting/model-provider-page/hooks', () => ({
|
|
useLanguage: () => 'en_US',
|
|
}))
|
|
|
|
vi.mock('@/utils/classnames', () => ({
|
|
cn: (...args: (string | undefined | false | null)[]) => args.filter(Boolean).join(' '),
|
|
}))
|
|
|
|
vi.mock('@/app/components/plugins/card/base/card-icon', () => ({
|
|
default: () => <span data-testid="card-icon" />,
|
|
}))
|
|
|
|
vi.mock('@/app/components/plugins/card/base/description', () => ({
|
|
default: ({ text }: { text: string }) => <div data-testid="description">{text}</div>,
|
|
}))
|
|
|
|
vi.mock('@/app/components/plugins/card/base/org-info', () => ({
|
|
default: ({ orgName }: { orgName: string }) => <div data-testid="org-info">{orgName}</div>,
|
|
}))
|
|
|
|
vi.mock('@/app/components/tools/utils/to-form-schema', () => ({
|
|
triggerEventParametersToFormSchemas: (params: Array<Record<string, unknown>>) =>
|
|
params.map(p => ({
|
|
label: (p.label as Record<string, string>) || { en_US: p.name as string },
|
|
type: (p.type as string) || 'text-input',
|
|
required: (p.required as boolean) || false,
|
|
description: p.description as Record<string, string> | undefined,
|
|
})),
|
|
}))
|
|
|
|
vi.mock('@/app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/show/field', () => ({
|
|
default: ({ name }: { name: string }) => <div data-testid="output-field">{name}</div>,
|
|
}))
|
|
|
|
const mockEventInfo = {
|
|
name: 'test-event',
|
|
identity: {
|
|
author: 'test-author',
|
|
name: 'test-event',
|
|
label: { en_US: 'Test Event' },
|
|
},
|
|
description: { en_US: 'Test event description' },
|
|
parameters: [
|
|
{
|
|
name: 'param1',
|
|
label: { en_US: 'Parameter 1' },
|
|
type: 'text-input',
|
|
auto_generate: null,
|
|
template: null,
|
|
scope: null,
|
|
required: true,
|
|
multiple: false,
|
|
default: null,
|
|
min: null,
|
|
max: null,
|
|
precision: null,
|
|
description: { en_US: 'A test parameter' },
|
|
},
|
|
],
|
|
output_schema: {
|
|
properties: {
|
|
result: { type: 'string', description: 'Result' },
|
|
},
|
|
required: ['result'],
|
|
},
|
|
} as unknown as TriggerEvent
|
|
|
|
const mockProviderInfo = {
|
|
provider: 'test-provider',
|
|
author: 'test-author',
|
|
name: 'test-provider/test-name',
|
|
icon: 'icon.png',
|
|
description: { en_US: 'Provider desc' },
|
|
supported_creation_methods: [],
|
|
} as unknown as TriggerProviderApiEntity
|
|
|
|
describe('EventDetailDrawer', () => {
|
|
const mockOnClose = vi.fn()
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
describe('Rendering', () => {
|
|
it('should render drawer', () => {
|
|
render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByRole('dialog')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render event title', () => {
|
|
render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('Test Event')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render event description', () => {
|
|
render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByTestId('description')).toHaveTextContent('Test event description')
|
|
})
|
|
|
|
it('should render org info', () => {
|
|
render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByTestId('org-info')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render parameters section', () => {
|
|
render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('setBuiltInTools.parameters')).toBeInTheDocument()
|
|
expect(screen.getByText('Parameter 1')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render output section', () => {
|
|
render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('events.output')).toBeInTheDocument()
|
|
expect(screen.getByTestId('output-field')).toHaveTextContent('result')
|
|
})
|
|
|
|
it('should render back button', () => {
|
|
render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('detailPanel.operation.back')).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('User Interactions', () => {
|
|
it('should call onClose when close button clicked', () => {
|
|
render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
// Find the close button (ActionButton with action-btn class)
|
|
const closeButton = screen.getAllByRole('button').find(btn => btn.classList.contains('action-btn'))
|
|
if (closeButton)
|
|
fireEvent.click(closeButton)
|
|
|
|
expect(mockOnClose).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('should call onClose when back clicked', () => {
|
|
render(<EventDetailDrawer eventInfo={mockEventInfo} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
fireEvent.click(screen.getByText('detailPanel.operation.back'))
|
|
|
|
expect(mockOnClose).toHaveBeenCalledTimes(1)
|
|
})
|
|
})
|
|
|
|
describe('Edge Cases', () => {
|
|
it('should handle no parameters', () => {
|
|
const eventWithNoParams = { ...mockEventInfo, parameters: [] }
|
|
render(<EventDetailDrawer eventInfo={eventWithNoParams} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('events.item.noParameters')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should handle no output schema', () => {
|
|
const eventWithNoOutput = { ...mockEventInfo, output_schema: {} }
|
|
render(<EventDetailDrawer eventInfo={eventWithNoOutput} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('events.output')).toBeInTheDocument()
|
|
expect(screen.queryByTestId('output-field')).not.toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('Parameter Types', () => {
|
|
it('should display correct type for number-input', () => {
|
|
const eventWithNumber = {
|
|
...mockEventInfo,
|
|
parameters: [{ ...mockEventInfo.parameters[0], type: 'number-input' }],
|
|
}
|
|
render(<EventDetailDrawer eventInfo={eventWithNumber} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('setBuiltInTools.number')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should display correct type for checkbox', () => {
|
|
const eventWithCheckbox = {
|
|
...mockEventInfo,
|
|
parameters: [{ ...mockEventInfo.parameters[0], type: 'checkbox' }],
|
|
}
|
|
render(<EventDetailDrawer eventInfo={eventWithCheckbox} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('boolean')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should display correct type for file', () => {
|
|
const eventWithFile = {
|
|
...mockEventInfo,
|
|
parameters: [{ ...mockEventInfo.parameters[0], type: 'file' }],
|
|
}
|
|
render(<EventDetailDrawer eventInfo={eventWithFile} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('setBuiltInTools.file')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should display original type for unknown types', () => {
|
|
const eventWithUnknown = {
|
|
...mockEventInfo,
|
|
parameters: [{ ...mockEventInfo.parameters[0], type: 'custom-type' }],
|
|
}
|
|
render(<EventDetailDrawer eventInfo={eventWithUnknown} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('custom-type')).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('Output Schema Conversion', () => {
|
|
it('should handle array type in output schema', () => {
|
|
const eventWithArrayOutput = {
|
|
...mockEventInfo,
|
|
output_schema: {
|
|
properties: {
|
|
items: { type: 'array', items: { type: 'string' }, description: 'Array items' },
|
|
},
|
|
required: [],
|
|
},
|
|
}
|
|
render(<EventDetailDrawer eventInfo={eventWithArrayOutput} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('events.output')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should handle nested properties in output schema', () => {
|
|
const eventWithNestedOutput = {
|
|
...mockEventInfo,
|
|
output_schema: {
|
|
properties: {
|
|
nested: {
|
|
type: 'object',
|
|
properties: { inner: { type: 'string' } },
|
|
required: ['inner'],
|
|
},
|
|
},
|
|
required: [],
|
|
},
|
|
}
|
|
render(<EventDetailDrawer eventInfo={eventWithNestedOutput} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('events.output')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should handle enum in output schema', () => {
|
|
const eventWithEnumOutput = {
|
|
...mockEventInfo,
|
|
output_schema: {
|
|
properties: {
|
|
status: { type: 'string', enum: ['active', 'inactive'], description: 'Status' },
|
|
},
|
|
required: [],
|
|
},
|
|
}
|
|
render(<EventDetailDrawer eventInfo={eventWithEnumOutput} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('events.output')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should handle array type schema', () => {
|
|
const eventWithArrayType = {
|
|
...mockEventInfo,
|
|
output_schema: {
|
|
properties: {
|
|
multi: { type: ['string', 'null'], description: 'Multi type' },
|
|
},
|
|
required: [],
|
|
},
|
|
}
|
|
render(<EventDetailDrawer eventInfo={eventWithArrayType} providerInfo={mockProviderInfo} onClose={mockOnClose} />)
|
|
|
|
expect(screen.getByText('events.output')).toBeInTheDocument()
|
|
})
|
|
})
|
|
})
|