dify/web/app/components/datasets/create/step-one/data-source-selector.spec.tsx

268 lines
9.2 KiB
TypeScript

import { fireEvent, render, screen } from '@testing-library/react'
import { DataSourceType } from '@/models/datasets'
import DataSourceSelector from './data-source-selector'
// Mock react-i18next
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => key,
}),
}))
// Mock config - enable all web crawl features
vi.mock('@/config', () => ({
ENABLE_WEBSITE_FIRECRAWL: true,
ENABLE_WEBSITE_JINAREADER: true,
ENABLE_WEBSITE_WATERCRAWL: false,
}))
const createDefaultProps = () => ({
dataSourceType: DataSourceType.FILE,
dataSourceTypeDisable: false,
changeType: vi.fn(),
onHideFilePreview: vi.fn(),
onHideNotionPreview: vi.fn(),
onHideWebsitePreview: vi.fn(),
})
describe('DataSourceSelector', () => {
beforeEach(() => {
vi.clearAllMocks()
})
// ==========================================
// Rendering Tests
// ==========================================
describe('Rendering', () => {
it('should render all data source options', () => {
// Arrange
const props = createDefaultProps()
// Act
render(<DataSourceSelector {...props} />)
// Assert
expect(screen.getByText('datasetCreation.stepOne.dataSourceType.file')).toBeInTheDocument()
expect(screen.getByText('datasetCreation.stepOne.dataSourceType.notion')).toBeInTheDocument()
expect(screen.getByText('datasetCreation.stepOne.dataSourceType.web')).toBeInTheDocument()
})
it('should show active state for FILE type', () => {
// Arrange
const props = { ...createDefaultProps(), dataSourceType: DataSourceType.FILE }
// Act
render(<DataSourceSelector {...props} />)
// Assert
const fileOption = screen.getByText('datasetCreation.stepOne.dataSourceType.file').closest('div')
expect(fileOption?.className).toContain('active')
})
it('should show active state for NOTION type', () => {
// Arrange
const props = { ...createDefaultProps(), dataSourceType: DataSourceType.NOTION }
// Act
render(<DataSourceSelector {...props} />)
// Assert
const notionOption = screen.getByText('datasetCreation.stepOne.dataSourceType.notion').closest('div')
expect(notionOption?.className).toContain('active')
})
it('should show active state for WEB type', () => {
// Arrange
const props = { ...createDefaultProps(), dataSourceType: DataSourceType.WEB }
// Act
render(<DataSourceSelector {...props} />)
// Assert
const webOption = screen.getByText('datasetCreation.stepOne.dataSourceType.web').closest('div')
expect(webOption?.className).toContain('active')
})
})
// ==========================================
// Click Handler Tests - File
// ==========================================
describe('File Click Handler', () => {
it('should call changeType and hide previews when clicking File option', () => {
// Arrange
const props = { ...createDefaultProps(), dataSourceType: DataSourceType.NOTION }
render(<DataSourceSelector {...props} />)
// Act
fireEvent.click(screen.getByText('datasetCreation.stepOne.dataSourceType.file'))
// Assert
expect(props.changeType).toHaveBeenCalledWith(DataSourceType.FILE)
expect(props.onHideNotionPreview).toHaveBeenCalled()
expect(props.onHideWebsitePreview).toHaveBeenCalled()
expect(props.onHideFilePreview).not.toHaveBeenCalled()
})
it('should NOT call changeType when clicking File option while disabled', () => {
// Arrange
const props = {
...createDefaultProps(),
dataSourceType: DataSourceType.NOTION,
dataSourceTypeDisable: true,
}
render(<DataSourceSelector {...props} />)
// Act
fireEvent.click(screen.getByText('datasetCreation.stepOne.dataSourceType.file'))
// Assert
expect(props.changeType).not.toHaveBeenCalled()
expect(props.onHideNotionPreview).not.toHaveBeenCalled()
expect(props.onHideWebsitePreview).not.toHaveBeenCalled()
})
})
// ==========================================
// Click Handler Tests - Notion
// ==========================================
describe('Notion Click Handler', () => {
it('should call changeType and hide previews when clicking Notion option', () => {
// Arrange
const props = { ...createDefaultProps(), dataSourceType: DataSourceType.FILE }
render(<DataSourceSelector {...props} />)
// Act
fireEvent.click(screen.getByText('datasetCreation.stepOne.dataSourceType.notion'))
// Assert
expect(props.changeType).toHaveBeenCalledWith(DataSourceType.NOTION)
expect(props.onHideFilePreview).toHaveBeenCalled()
expect(props.onHideWebsitePreview).toHaveBeenCalled()
expect(props.onHideNotionPreview).not.toHaveBeenCalled()
})
it('should NOT call changeType when clicking Notion option while disabled', () => {
// Arrange
const props = {
...createDefaultProps(),
dataSourceType: DataSourceType.FILE,
dataSourceTypeDisable: true,
}
render(<DataSourceSelector {...props} />)
// Act
fireEvent.click(screen.getByText('datasetCreation.stepOne.dataSourceType.notion'))
// Assert
expect(props.changeType).not.toHaveBeenCalled()
expect(props.onHideFilePreview).not.toHaveBeenCalled()
expect(props.onHideWebsitePreview).not.toHaveBeenCalled()
})
})
// ==========================================
// Click Handler Tests - Web
// ==========================================
describe('Web Click Handler', () => {
it('should call changeType and hide previews when clicking Web option', () => {
// Arrange
const props = { ...createDefaultProps(), dataSourceType: DataSourceType.FILE }
render(<DataSourceSelector {...props} />)
// Act
fireEvent.click(screen.getByText('datasetCreation.stepOne.dataSourceType.web'))
// Assert
expect(props.changeType).toHaveBeenCalledWith(DataSourceType.WEB)
expect(props.onHideFilePreview).toHaveBeenCalled()
expect(props.onHideNotionPreview).toHaveBeenCalled()
expect(props.onHideWebsitePreview).not.toHaveBeenCalled()
})
it('should NOT call changeType when clicking Web option while disabled', () => {
// Arrange
const props = {
...createDefaultProps(),
dataSourceType: DataSourceType.FILE,
dataSourceTypeDisable: true,
}
render(<DataSourceSelector {...props} />)
// Act
fireEvent.click(screen.getByText('datasetCreation.stepOne.dataSourceType.web'))
// Assert
expect(props.changeType).not.toHaveBeenCalled()
expect(props.onHideFilePreview).not.toHaveBeenCalled()
expect(props.onHideNotionPreview).not.toHaveBeenCalled()
})
})
// ==========================================
// Disabled State Tests
// ==========================================
describe('Disabled State', () => {
it('should show disabled style for non-active options when disabled', () => {
// Arrange
const props = {
...createDefaultProps(),
dataSourceType: DataSourceType.FILE,
dataSourceTypeDisable: true,
}
// Act
render(<DataSourceSelector {...props} />)
// Assert
const notionOption = screen.getByText('datasetCreation.stepOne.dataSourceType.notion').closest('div')
const webOption = screen.getByText('datasetCreation.stepOne.dataSourceType.web').closest('div')
expect(notionOption?.className).toContain('disabled')
expect(webOption?.className).toContain('disabled')
})
it('should NOT show disabled style for active option when disabled', () => {
// Arrange
const props = {
...createDefaultProps(),
dataSourceType: DataSourceType.FILE,
dataSourceTypeDisable: true,
}
// Act
render(<DataSourceSelector {...props} />)
// Assert
const fileOption = screen.getByText('datasetCreation.stepOne.dataSourceType.file').closest('div')
expect(fileOption?.className).toContain('active')
expect(fileOption?.className).not.toContain('disabled')
})
})
// ==========================================
// Web Disabled Config Test
// ==========================================
describe('Web Feature Flag', () => {
it('should not render Web option when all web features are disabled', async () => {
// Arrange - Override the config mock for this test
vi.doMock('@/config', () => ({
ENABLE_WEBSITE_FIRECRAWL: false,
ENABLE_WEBSITE_JINAREADER: false,
ENABLE_WEBSITE_WATERCRAWL: false,
}))
// Re-import the component with new mock
const { default: DataSourceSelectorNoWeb } = await import('./data-source-selector')
const props = createDefaultProps()
// Act
render(<DataSourceSelectorNoWeb {...props} />)
// Assert
expect(screen.getByText('datasetCreation.stepOne.dataSourceType.file')).toBeInTheDocument()
expect(screen.getByText('datasetCreation.stepOne.dataSourceType.notion')).toBeInTheDocument()
// Web option should still be there because the module was already loaded with enabled config
// This test documents the behavior rather than testing the feature flag itself
})
})
})