mirror of https://github.com/langgenius/dify.git
194 lines
6.9 KiB
TypeScript
194 lines
6.9 KiB
TypeScript
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('@/app/components/base/portal-to-follow-elem', () => ({
|
|
PortalToFollowElem: ({ children, open }: { children: React.ReactNode, open: boolean }) => (
|
|
<div data-testid="portal-elem" data-open={open}>{children}</div>
|
|
),
|
|
PortalToFollowElemTrigger: ({ children, onClick }: { children: React.ReactNode, onClick?: () => void }) => (
|
|
<div data-testid="portal-trigger" onClick={onClick}>{children}</div>
|
|
),
|
|
PortalToFollowElemContent: ({ children }: { children: React.ReactNode }) => (
|
|
<div data-testid="portal-content">{children}</div>
|
|
),
|
|
}))
|
|
|
|
vi.mock('../../base/app-icon', () => ({
|
|
default: ({ size, icon }: { size: string, icon: string }) => (
|
|
<div data-testid="app-icon" data-size={size} data-icon={icon} />
|
|
),
|
|
}))
|
|
|
|
vi.mock('../../base/divider', () => ({
|
|
default: () => <hr data-testid="divider" />,
|
|
}))
|
|
|
|
vi.mock('../../base/effect', () => ({
|
|
default: ({ className }: { className?: string }) => <div data-testid="effect" className={className} />,
|
|
}))
|
|
|
|
vi.mock('../../datasets/extra-info', () => ({
|
|
default: ({ expand, documentCount }: {
|
|
relatedApps?: unknown[]
|
|
expand: boolean
|
|
documentCount: number
|
|
}) => (
|
|
<div data-testid="extra-info" data-expand={expand} data-doc-count={documentCount} />
|
|
),
|
|
}))
|
|
|
|
vi.mock('../dataset-info/dropdown', () => ({
|
|
default: ({ expand }: { expand: boolean }) => (
|
|
<div data-testid="dataset-dropdown" data-expand={expand} />
|
|
),
|
|
}))
|
|
|
|
vi.mock('../nav-link', () => ({
|
|
default: ({ name, href, mode, disabled }: { name: string, href: string, mode?: string, disabled?: boolean }) => (
|
|
<a data-testid={`nav-link-${name}`} href={href} data-mode={mode} data-disabled={disabled}>{name}</a>
|
|
),
|
|
}))
|
|
|
|
const MockIcon = (props: React.SVGProps<SVGSVGElement>) => <svg {...props} />
|
|
|
|
const createDataset = (overrides: Partial<DataSet> = {}): 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(<DatasetSidebarDropdown navigation={navigation} />)
|
|
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(<DatasetSidebarDropdown navigation={navigation} />)
|
|
expect(screen.getByText('Test Dataset')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should display dataset description', () => {
|
|
render(<DatasetSidebarDropdown navigation={navigation} />)
|
|
expect(screen.getByText('A test dataset')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should not display description when empty', () => {
|
|
mockDataset = createDataset({ description: '' })
|
|
render(<DatasetSidebarDropdown navigation={navigation} />)
|
|
expect(screen.queryByText('A test dataset')).not.toBeInTheDocument()
|
|
})
|
|
|
|
it('should render navigation links', () => {
|
|
render(<DatasetSidebarDropdown navigation={navigation} />)
|
|
expect(screen.getByTestId('nav-link-Documents')).toBeInTheDocument()
|
|
expect(screen.getByTestId('nav-link-Settings')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render ExtraInfo', () => {
|
|
render(<DatasetSidebarDropdown navigation={navigation} />)
|
|
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(<DatasetSidebarDropdown navigation={navigation} />)
|
|
expect(screen.getByTestId('effect')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render Dropdown component with expand=true', () => {
|
|
render(<DatasetSidebarDropdown navigation={navigation} />)
|
|
expect(screen.getByTestId('dataset-dropdown')).toHaveAttribute('data-expand', 'true')
|
|
})
|
|
|
|
it('should show external tag for external provider', () => {
|
|
mockDataset = createDataset({ provider: 'external' })
|
|
render(<DatasetSidebarDropdown navigation={navigation} />)
|
|
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(<DatasetSidebarDropdown navigation={navigation} />)
|
|
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(<DatasetSidebarDropdown navigation={navigation} />)
|
|
|
|
const trigger = screen.getByTestId('portal-trigger')
|
|
await user.click(trigger)
|
|
|
|
expect(screen.getByTestId('portal-elem')).toHaveAttribute('data-open', 'true')
|
|
})
|
|
|
|
it('should render divider', () => {
|
|
render(<DatasetSidebarDropdown navigation={navigation} />)
|
|
expect(screen.getByTestId('divider')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render medium app icon in content area', () => {
|
|
render(<DatasetSidebarDropdown navigation={navigation} />)
|
|
const icons = screen.getAllByTestId('app-icon')
|
|
const mediumIcon = icons.find(i => i.getAttribute('data-size') === 'medium')
|
|
expect(mediumIcon).toBeInTheDocument()
|
|
})
|
|
})
|