mirror of
https://mirror.skon.top/github.com/langgenius/dify.git
synced 2026-04-20 15:20:15 +08:00
Co-authored-by: CodingOnStar <hanxujiang@dify.ai> Co-authored-by: CodingOnStar <hanxujiang@dify.com>
280 lines
9.2 KiB
TypeScript
280 lines
9.2 KiB
TypeScript
import type { Datasource } from '@/app/components/rag-pipeline/components/panel/test-run/types'
|
|
import type { DataSourceNodeType } from '@/app/components/workflow/nodes/data-source/types'
|
|
import type { NotionPage } from '@/models/common'
|
|
import type { CrawlResultItem, CustomFile, FileIndexingEstimateResponse, FileItem } from '@/models/datasets'
|
|
import type { OnlineDriveFile } from '@/models/pipeline'
|
|
import { render, screen } from '@testing-library/react'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { DatasourceType } from '@/models/pipeline'
|
|
import { StepOnePreview, StepTwoPreview } from './preview-panel'
|
|
|
|
// Mock context hooks (底层依赖)
|
|
vi.mock('@/context/dataset-detail', () => ({
|
|
useDatasetDetailContextWithSelector: vi.fn((selector: (state: unknown) => unknown) => {
|
|
const mockState = {
|
|
dataset: {
|
|
id: 'mock-dataset-id',
|
|
doc_form: 'text_model',
|
|
pipeline_id: 'mock-pipeline-id',
|
|
},
|
|
}
|
|
return selector(mockState)
|
|
}),
|
|
}))
|
|
|
|
// Mock API hooks (底层依赖)
|
|
vi.mock('@/service/use-common', () => ({
|
|
useFilePreview: vi.fn(() => ({
|
|
data: { content: 'Mock file content for testing' },
|
|
isFetching: false,
|
|
})),
|
|
}))
|
|
|
|
vi.mock('@/service/use-pipeline', () => ({
|
|
usePreviewOnlineDocument: vi.fn(() => ({
|
|
mutateAsync: vi.fn().mockResolvedValue({ content: 'Mock document content' }),
|
|
isPending: false,
|
|
})),
|
|
}))
|
|
|
|
// Mock data source store
|
|
vi.mock('../data-source/store', () => ({
|
|
useDataSourceStore: vi.fn(() => ({
|
|
getState: () => ({ currentCredentialId: 'mock-credential-id' }),
|
|
})),
|
|
}))
|
|
|
|
describe('StepOnePreview', () => {
|
|
const mockDatasource: Datasource = {
|
|
nodeId: 'test-node-id',
|
|
nodeData: { type: 'data-source' } as unknown as DataSourceNodeType,
|
|
}
|
|
|
|
const mockLocalFile: CustomFile = {
|
|
id: 'file-1',
|
|
name: 'test-file.txt',
|
|
type: 'text/plain',
|
|
size: 1024,
|
|
progress: 100,
|
|
extension: 'txt',
|
|
} as unknown as CustomFile
|
|
|
|
const mockWebsite: CrawlResultItem = {
|
|
source_url: 'https://example.com',
|
|
title: 'Example Site',
|
|
markdown: 'Mock markdown content',
|
|
} as CrawlResultItem
|
|
|
|
const defaultProps = {
|
|
datasource: mockDatasource,
|
|
currentLocalFile: undefined,
|
|
currentDocument: undefined,
|
|
currentWebsite: undefined,
|
|
hidePreviewLocalFile: vi.fn(),
|
|
hidePreviewOnlineDocument: vi.fn(),
|
|
hideWebsitePreview: vi.fn(),
|
|
}
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
describe('Rendering', () => {
|
|
it('should render without crashing', () => {
|
|
const { container } = render(<StepOnePreview {...defaultProps} />)
|
|
expect(container.querySelector('.h-full')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render container with correct structure', () => {
|
|
const { container } = render(<StepOnePreview {...defaultProps} />)
|
|
expect(container.querySelector('.flex.h-full.flex-col')).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('Conditional Rendering - FilePreview', () => {
|
|
it('should render FilePreview when currentLocalFile is provided', () => {
|
|
render(<StepOnePreview {...defaultProps} currentLocalFile={mockLocalFile} />)
|
|
// FilePreview renders a preview header with file name
|
|
expect(screen.getByText(/test-file/i)).toBeInTheDocument()
|
|
})
|
|
|
|
it('should not render FilePreview when currentLocalFile is undefined', () => {
|
|
const { container } = render(<StepOnePreview {...defaultProps} currentLocalFile={undefined} />)
|
|
// Container should still render but without file preview content
|
|
expect(container.querySelector('.h-full')).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('Conditional Rendering - WebsitePreview', () => {
|
|
it('should render WebsitePreview when currentWebsite is provided', () => {
|
|
render(<StepOnePreview {...defaultProps} currentWebsite={mockWebsite} />)
|
|
// WebsitePreview displays the website title and URL
|
|
expect(screen.getByText('Example Site')).toBeInTheDocument()
|
|
expect(screen.getByText('https://example.com')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should not render WebsitePreview when currentWebsite is undefined', () => {
|
|
const { container } = render(<StepOnePreview {...defaultProps} currentWebsite={undefined} />)
|
|
expect(container.querySelector('.h-full')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should call hideWebsitePreview when close button is clicked', () => {
|
|
const hideWebsitePreview = vi.fn()
|
|
render(
|
|
<StepOnePreview
|
|
{...defaultProps}
|
|
currentWebsite={mockWebsite}
|
|
hideWebsitePreview={hideWebsitePreview}
|
|
/>,
|
|
)
|
|
|
|
// Find and click the close button (RiCloseLine icon)
|
|
const closeButton = screen.getByRole('button')
|
|
closeButton.click()
|
|
|
|
expect(hideWebsitePreview).toHaveBeenCalledTimes(1)
|
|
})
|
|
})
|
|
|
|
describe('Edge Cases', () => {
|
|
it('should handle website with long markdown content', () => {
|
|
const longWebsite: CrawlResultItem = {
|
|
...mockWebsite,
|
|
markdown: 'A'.repeat(10000),
|
|
}
|
|
render(<StepOnePreview {...defaultProps} currentWebsite={longWebsite} />)
|
|
expect(screen.getByText('Example Site')).toBeInTheDocument()
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('StepTwoPreview', () => {
|
|
const mockFileList: FileItem[] = [
|
|
{
|
|
file: {
|
|
id: 'file-1',
|
|
name: 'file1.txt',
|
|
extension: 'txt',
|
|
size: 1024,
|
|
} as CustomFile,
|
|
progress: 100,
|
|
},
|
|
{
|
|
file: {
|
|
id: 'file-2',
|
|
name: 'file2.txt',
|
|
extension: 'txt',
|
|
size: 2048,
|
|
} as CustomFile,
|
|
progress: 100,
|
|
},
|
|
] as FileItem[]
|
|
|
|
const mockOnlineDocuments: (NotionPage & { workspace_id: string })[] = [
|
|
{
|
|
page_id: 'page-1',
|
|
page_name: 'Page 1',
|
|
type: 'page',
|
|
workspace_id: 'workspace-1',
|
|
page_icon: null,
|
|
is_bound: false,
|
|
parent_id: '',
|
|
},
|
|
]
|
|
|
|
const mockWebsitePages: CrawlResultItem[] = [
|
|
{ source_url: 'https://example.com', title: 'Example', markdown: 'Content' } as CrawlResultItem,
|
|
]
|
|
|
|
const mockOnlineDriveFiles: OnlineDriveFile[] = [
|
|
{ id: 'drive-1', name: 'drive-file.txt' } as OnlineDriveFile,
|
|
]
|
|
|
|
const mockEstimateData: FileIndexingEstimateResponse = {
|
|
tokens: 1000,
|
|
total_price: 0.01,
|
|
total_segments: 10,
|
|
} as FileIndexingEstimateResponse
|
|
|
|
const defaultProps = {
|
|
datasourceType: DatasourceType.localFile,
|
|
localFileList: mockFileList,
|
|
onlineDocuments: mockOnlineDocuments,
|
|
websitePages: mockWebsitePages,
|
|
selectedOnlineDriveFileList: mockOnlineDriveFiles,
|
|
isIdle: true,
|
|
isPendingPreview: false,
|
|
estimateData: mockEstimateData,
|
|
onPreview: vi.fn(),
|
|
handlePreviewFileChange: vi.fn(),
|
|
handlePreviewOnlineDocumentChange: vi.fn(),
|
|
handlePreviewWebsitePageChange: vi.fn(),
|
|
handlePreviewOnlineDriveFileChange: vi.fn(),
|
|
}
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
describe('Rendering', () => {
|
|
it('should render without crashing', () => {
|
|
const { container } = render(<StepTwoPreview {...defaultProps} />)
|
|
expect(container.querySelector('.h-full')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render ChunkPreview component structure', () => {
|
|
const { container } = render(<StepTwoPreview {...defaultProps} />)
|
|
expect(container.querySelector('.flex.h-full.flex-col')).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('Props Passing', () => {
|
|
it('should render preview button when isIdle is true', () => {
|
|
render(<StepTwoPreview {...defaultProps} isIdle={true} />)
|
|
// ChunkPreview shows a preview button when idle
|
|
const previewButton = screen.queryByRole('button')
|
|
expect(previewButton).toBeInTheDocument()
|
|
})
|
|
|
|
it('should call onPreview when preview button is clicked', () => {
|
|
const onPreview = vi.fn()
|
|
render(<StepTwoPreview {...defaultProps} isIdle={true} onPreview={onPreview} />)
|
|
|
|
// Find and click the preview button
|
|
const buttons = screen.getAllByRole('button')
|
|
const previewButton = buttons.find(btn => btn.textContent?.toLowerCase().includes('preview'))
|
|
if (previewButton) {
|
|
previewButton.click()
|
|
expect(onPreview).toHaveBeenCalled()
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('Edge Cases', () => {
|
|
it('should handle empty localFileList', () => {
|
|
const { container } = render(<StepTwoPreview {...defaultProps} localFileList={[]} />)
|
|
expect(container.querySelector('.h-full')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should handle empty onlineDocuments', () => {
|
|
const { container } = render(<StepTwoPreview {...defaultProps} onlineDocuments={[]} />)
|
|
expect(container.querySelector('.h-full')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should handle empty websitePages', () => {
|
|
const { container } = render(<StepTwoPreview {...defaultProps} websitePages={[]} />)
|
|
expect(container.querySelector('.h-full')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should handle empty onlineDriveFiles', () => {
|
|
const { container } = render(<StepTwoPreview {...defaultProps} selectedOnlineDriveFileList={[]} />)
|
|
expect(container.querySelector('.h-full')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should handle undefined estimateData', () => {
|
|
const { container } = render(<StepTwoPreview {...defaultProps} estimateData={undefined} />)
|
|
expect(container.querySelector('.h-full')).toBeInTheDocument()
|
|
})
|
|
})
|
|
})
|