import type { DataSet } from '@/models/datasets' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import DatasetSidebarDropdown from '../dataset-sidebar-dropdown' let mockDataset: DataSet vi.mock('@/context/dataset-detail', () => ({ useDatasetDetailContextWithSelector: (selector: (state: { dataset: DataSet }) => unknown) => selector({ dataset: mockDataset }), })) vi.mock('@/service/knowledge/use-dataset', () => ({ useDatasetRelatedApps: () => ({ data: [] }), })) vi.mock('@/hooks/use-knowledge', () => ({ useKnowledge: () => ({ formatIndexingTechniqueAndMethod: () => 'method-text', }), })) vi.mock('@langgenius/dify-ui/dropdown-menu', () => { const DropdownMenuContext = React.createContext<{ isOpen: boolean, setOpen: (open: boolean) => void } | null>(null) const useDropdownMenuContext = () => { const context = React.use(DropdownMenuContext) if (!context) throw new Error('DropdownMenu components must be wrapped in DropdownMenu') return context } return { DropdownMenu: ({ children, open, onOpenChange }: { children: React.ReactNode, open: boolean, onOpenChange?: (open: boolean) => void }) => (
{children}
), DropdownMenuTrigger: ({ children, onClick }: { children: React.ReactNode, onClick?: React.MouseEventHandler }) => { const { isOpen, setOpen } = useDropdownMenuContext() return ( ) }, DropdownMenuContent: ({ children }: { children: React.ReactNode }) =>
{children}
, } }) vi.mock('../../base/app-icon', () => ({ default: ({ size, icon }: { size: string, icon: string }) => (
), })) vi.mock('../../base/divider', () => ({ default: () =>
, })) vi.mock('../../base/effect', () => ({ default: ({ className }: { className?: string }) =>
, })) vi.mock('../../datasets/extra-info', () => ({ default: ({ expand, documentCount }: { relatedApps?: unknown[] expand: boolean documentCount: number }) => (
), })) vi.mock('../dataset-info/dropdown', () => ({ default: ({ expand }: { expand: boolean }) => (
), })) vi.mock('../nav-link', () => ({ default: ({ name, href, mode, disabled }: { name: string, href: string, mode?: string, disabled?: boolean }) => ( {name} ), })) const MockIcon = (props: React.SVGProps) => const createDataset = (overrides: Partial = {}): DataSet => ({ id: 'dataset-1', name: 'Test Dataset', description: 'A test dataset', provider: 'internal', icon_info: { icon: '📙', icon_type: 'emoji', icon_background: '#FFF4ED', icon_url: '', }, doc_form: 'text_model' as DataSet['doc_form'], indexing_technique: 'high_quality' as DataSet['indexing_technique'], document_count: 10, runtime_mode: 'general', retrieval_model_dict: { search_method: 'semantic_search' as DataSet['retrieval_model_dict']['search_method'], reranking_enable: false, reranking_model: { reranking_provider_name: '', reranking_model_name: '' }, top_k: 5, score_threshold_enabled: false, score_threshold: 0, }, ...overrides, } as DataSet) const navigation = [ { name: 'Documents', href: '/documents', icon: MockIcon, selectedIcon: MockIcon }, { name: 'Settings', href: '/settings', icon: MockIcon, selectedIcon: MockIcon, disabled: true }, ] describe('DatasetSidebarDropdown', () => { beforeEach(() => { vi.clearAllMocks() mockDataset = createDataset() }) it('should render trigger with dataset icon', () => { render() const icons = screen.getAllByTestId('app-icon') const smallIcon = icons.find(i => i.getAttribute('data-size') === 'small') expect(smallIcon).toBeInTheDocument() expect(smallIcon).toHaveAttribute('data-icon', '📙') }) it('should display dataset name in dropdown content', () => { render() expect(screen.getByText('Test Dataset')).toBeInTheDocument() }) it('should display dataset description', () => { render() expect(screen.getByText('A test dataset')).toBeInTheDocument() }) it('should not display description when empty', () => { mockDataset = createDataset({ description: '' }) render() expect(screen.queryByText('A test dataset')).not.toBeInTheDocument() }) it('should render navigation links', () => { render() expect(screen.getByTestId('nav-link-Documents')).toBeInTheDocument() expect(screen.getByTestId('nav-link-Settings')).toBeInTheDocument() }) it('should render ExtraInfo', () => { render() const extraInfo = screen.getByTestId('extra-info') expect(extraInfo).toHaveAttribute('data-expand', 'true') expect(extraInfo).toHaveAttribute('data-doc-count', '10') }) it('should render Effect component', () => { render() expect(screen.getByTestId('effect')).toBeInTheDocument() }) it('should render Dropdown component with expand=true', () => { render() expect(screen.getByTestId('dataset-dropdown')).toHaveAttribute('data-expand', 'true') }) it('should show external tag for external provider', () => { mockDataset = createDataset({ provider: 'external' }) render() expect(screen.getByText('dataset.externalTag')).toBeInTheDocument() }) it('should use fallback icon info when icon_info is missing', () => { mockDataset = createDataset({ icon_info: undefined as unknown as DataSet['icon_info'] }) render() const icons = screen.getAllByTestId('app-icon') const fallbackIcon = icons.find(i => i.getAttribute('data-icon') === '📙') expect(fallbackIcon).toBeInTheDocument() }) it('should toggle dropdown open state on trigger click', async () => { const user = userEvent.setup() render() const trigger = screen.getByTestId('dropdown-trigger') await user.click(trigger) expect(screen.getByTestId('dropdown-menu')).toHaveAttribute('data-open', 'true') }) it('should render divider', () => { render() expect(screen.getByTestId('divider')).toBeInTheDocument() }) it('should render medium app icon in content area', () => { render() const icons = screen.getAllByTestId('app-icon') const mediumIcon = icons.find(i => i.getAttribute('data-size') === 'medium') expect(mediumIcon).toBeInTheDocument() }) })