dify/web/app/components/plugins/plugin-detail-panel/__tests__/operation-dropdown.spec.tsx

160 lines
5.9 KiB
TypeScript

import type { ReactElement } from 'react'
import { fireEvent, screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { PluginSource } from '../../types'
import { OperationDropdown } from '../operation-dropdown'
const render = (ui: ReactElement, enableMarketplace = true) =>
renderWithConsoleQuery(ui, { systemFeatures: { enable_marketplace: enableMarketplace } })
const openDropdown = () => {
fireEvent.click(screen.getByRole('button', { name: 'plugin.detailPanel.operation.moreActions' }))
}
describe('OperationDropdown', () => {
const mockOnInfo = vi.fn()
const mockOnCheckVersion = vi.fn()
const mockOnRemove = vi.fn()
const mockOnViewReadme = vi.fn()
const defaultProps = {
source: PluginSource.github,
detailUrl: 'https://github.com/test/repo',
onInfo: mockOnInfo,
onCheckVersion: mockOnCheckVersion,
onRemove: mockOnRemove,
}
beforeEach(() => {
vi.clearAllMocks()
})
describe('Rendering', () => {
it('should render the actions trigger', () => {
render(<OperationDropdown {...defaultProps} />)
expect(
screen.getByRole('button', { name: 'plugin.detailPanel.operation.moreActions' }),
).toBeInTheDocument()
})
it('should render GitHub actions when marketplace is enabled', () => {
render(<OperationDropdown {...defaultProps} source={PluginSource.github} />)
openDropdown()
expect(screen.getByText('plugin.detailPanel.operation.info')).toBeInTheDocument()
expect(screen.getByText('plugin.detailPanel.operation.checkUpdate')).toBeInTheDocument()
expect(screen.getByText('plugin.detailPanel.operation.viewDetail')).toBeInTheDocument()
expect(screen.getByText('plugin.detailPanel.operation.remove')).toBeInTheDocument()
})
it('should render marketplace detail action for marketplace source', () => {
render(<OperationDropdown {...defaultProps} source={PluginSource.marketplace} />)
openDropdown()
expect(screen.queryByText('plugin.detailPanel.operation.info')).not.toBeInTheDocument()
expect(screen.queryByText('plugin.detailPanel.operation.checkUpdate')).not.toBeInTheDocument()
expect(screen.getByText('plugin.detailPanel.operation.viewDetail')).toBeInTheDocument()
expect(screen.getByText('plugin.detailPanel.operation.remove')).toBeInTheDocument()
})
it('should render README action only when provided', () => {
const { unmount } = render(<OperationDropdown {...defaultProps} />)
openDropdown()
expect(screen.queryByText('plugin.detailPanel.operation.viewReadme')).not.toBeInTheDocument()
unmount()
render(<OperationDropdown {...defaultProps} onViewReadme={mockOnViewReadme} />)
openDropdown()
expect(screen.getByText('plugin.detailPanel.operation.viewReadme')).toBeInTheDocument()
})
it('should not render marketplace detail when source cannot open a detail page', () => {
render(<OperationDropdown {...defaultProps} source={PluginSource.local} />)
openDropdown()
expect(screen.queryByText('plugin.detailPanel.operation.viewDetail')).not.toBeInTheDocument()
expect(screen.getByText('plugin.detailPanel.operation.remove')).toBeInTheDocument()
})
it('should not render the trigger when every action is unavailable', () => {
render(
<OperationDropdown
{...defaultProps}
source={PluginSource.local}
showRemove={false}
showCheckVersion={false}
/>,
)
expect(
screen.queryByRole('button', { name: 'plugin.detailPanel.operation.moreActions' }),
).not.toBeInTheDocument()
})
})
describe('User Interactions', () => {
it('should call onInfo when the info action is clicked', () => {
render(<OperationDropdown {...defaultProps} source={PluginSource.github} />)
openDropdown()
fireEvent.click(screen.getByText('plugin.detailPanel.operation.info'))
expect(mockOnInfo).toHaveBeenCalledTimes(1)
})
it('should call onCheckVersion when the check update action is clicked', () => {
render(<OperationDropdown {...defaultProps} source={PluginSource.github} />)
openDropdown()
fireEvent.click(screen.getByText('plugin.detailPanel.operation.checkUpdate'))
expect(mockOnCheckVersion).toHaveBeenCalledTimes(1)
})
it('should call onRemove when the remove action is clicked', () => {
render(<OperationDropdown {...defaultProps} source={PluginSource.github} />)
openDropdown()
fireEvent.click(screen.getByText('plugin.detailPanel.operation.remove'))
expect(mockOnRemove).toHaveBeenCalledTimes(1)
})
it('should call onViewReadme when README action is clicked', () => {
render(<OperationDropdown {...defaultProps} onViewReadme={mockOnViewReadme} />)
openDropdown()
fireEvent.click(screen.getByText('plugin.detailPanel.operation.viewReadme'))
expect(mockOnViewReadme).toHaveBeenCalledTimes(1)
})
it('should render view detail as an external link', () => {
render(<OperationDropdown {...defaultProps} source={PluginSource.github} />)
openDropdown()
const link = screen.getByText('plugin.detailPanel.operation.viewDetail').closest('a')
expect(link).toHaveAttribute('href', 'https://github.com/test/repo')
expect(link).toHaveAttribute('target', '_blank')
expect(link).toHaveAttribute('rel', 'noopener noreferrer')
})
})
describe('Feature Flags', () => {
it('should hide marketplace detail when marketplace is disabled', () => {
render(<OperationDropdown {...defaultProps} source={PluginSource.github} />, false)
openDropdown()
expect(screen.queryByText('plugin.detailPanel.operation.viewDetail')).not.toBeInTheDocument()
expect(screen.getByText('plugin.detailPanel.operation.info')).toBeInTheDocument()
})
})
})