import { fireEvent, render, screen } from '@testing-library/react' import React from 'react' import ChunkPreview from './chunk-preview' import { ChunkingMode } from '@/models/datasets' import type { CrawlResultItem, CustomFile, FileIndexingEstimateResponse } from '@/models/datasets' import type { NotionPage } from '@/models/common' import type { OnlineDriveFile } from '@/models/pipeline' import { DatasourceType, OnlineDriveFileType } from '@/models/pipeline' // Uses __mocks__/react-i18next.ts automatically // Mock dataset-detail context - needs mock to control return values const mockDocForm = jest.fn() jest.mock('@/context/dataset-detail', () => ({ useDatasetDetailContextWithSelector: (_selector: (s: { dataset: { doc_form: ChunkingMode } }) => ChunkingMode) => { return mockDocForm() }, })) // Mock document picker - needs mock for simplified interaction testing jest.mock('../../../common/document-picker/preview-document-picker', () => ({ __esModule: true, default: ({ files, onChange, value }: { files: Array<{ id: string; name: string; extension: string }> onChange: (selected: { id: string; name: string; extension: string }) => void value: { id: string; name: string; extension: string } }) => (
{value?.name || 'No selection'}
), })) // Test data factories const createMockLocalFile = (overrides?: Partial): CustomFile => ({ id: 'file-1', name: 'test-file.pdf', size: 1024, type: 'application/pdf', extension: 'pdf', lastModified: Date.now(), webkitRelativePath: '', arrayBuffer: jest.fn() as () => Promise, bytes: jest.fn() as () => Promise, slice: jest.fn() as (start?: number, end?: number, contentType?: string) => Blob, stream: jest.fn() as () => ReadableStream, text: jest.fn() as () => Promise, ...overrides, } as CustomFile) const createMockNotionPage = (overrides?: Partial): NotionPage => ({ page_id: 'page-1', page_name: 'Test Page', workspace_id: 'workspace-1', type: 'page', page_icon: null, parent_id: 'parent-1', is_bound: true, ...overrides, }) const createMockCrawlResult = (overrides?: Partial): CrawlResultItem => ({ title: 'Test Website', markdown: 'Test content', description: 'Test description', source_url: 'https://example.com', ...overrides, }) const createMockOnlineDriveFile = (overrides?: Partial): OnlineDriveFile => ({ id: 'drive-file-1', name: 'test-drive-file.docx', size: 2048, type: OnlineDriveFileType.file, ...overrides, }) const createMockEstimateData = (overrides?: Partial): FileIndexingEstimateResponse => ({ total_nodes: 5, tokens: 1000, total_price: 0.01, currency: 'USD', total_segments: 10, preview: [ { content: 'Chunk content 1', child_chunks: ['child 1', 'child 2'] }, { content: 'Chunk content 2', child_chunks: ['child 3'] }, ], qa_preview: [ { question: 'Q1', answer: 'A1' }, { question: 'Q2', answer: 'A2' }, ], ...overrides, }) const defaultProps = { dataSourceType: DatasourceType.localFile, localFiles: [createMockLocalFile()], onlineDocuments: [createMockNotionPage()], websitePages: [createMockCrawlResult()], onlineDriveFiles: [createMockOnlineDriveFile()], isIdle: false, isPending: false, estimateData: undefined, onPreview: jest.fn(), handlePreviewFileChange: jest.fn(), handlePreviewOnlineDocumentChange: jest.fn(), handlePreviewWebsitePageChange: jest.fn(), handlePreviewOnlineDriveFileChange: jest.fn(), } describe('ChunkPreview', () => { beforeEach(() => { jest.clearAllMocks() mockDocForm.mockReturnValue(ChunkingMode.text) }) describe('Rendering', () => { it('should render the component with preview container', () => { render() // i18n mock returns key by default expect(screen.getByText('datasetCreation.stepTwo.preview')).toBeInTheDocument() }) it('should render document picker for local files', () => { render() expect(screen.getByTestId('document-picker')).toBeInTheDocument() }) it('should render document picker for online documents', () => { render() expect(screen.getByTestId('document-picker')).toBeInTheDocument() }) it('should render document picker for website pages', () => { render() expect(screen.getByTestId('document-picker')).toBeInTheDocument() }) it('should render document picker for online drive files', () => { render() expect(screen.getByTestId('document-picker')).toBeInTheDocument() }) it('should render badge with chunk count for non-QA mode', () => { const estimateData = createMockEstimateData({ total_segments: 15 }) mockDocForm.mockReturnValue(ChunkingMode.text) render() // Badge shows chunk count via i18n key with count option expect(screen.getByText(/previewChunkCount.*15/)).toBeInTheDocument() }) it('should not render badge for QA mode', () => { mockDocForm.mockReturnValue(ChunkingMode.qa) const estimateData = createMockEstimateData() render() // No badge with total_segments expect(screen.queryByText(/10/)).not.toBeInTheDocument() }) }) describe('Idle State', () => { it('should render idle state with preview tip and button', () => { render() // i18n mock returns keys expect(screen.getByText('datasetCreation.stepTwo.previewChunkTip')).toBeInTheDocument() expect(screen.getByText('datasetPipeline.addDocuments.stepTwo.previewChunks')).toBeInTheDocument() }) it('should call onPreview when preview button is clicked', () => { const onPreview = jest.fn() render() const button = screen.getByRole('button', { name: /previewChunks/i }) fireEvent.click(button) expect(onPreview).toHaveBeenCalledTimes(1) }) }) describe('Loading State', () => { it('should render skeleton loading when isPending is true', () => { render() // Skeleton loading renders multiple skeleton containers expect(document.querySelector('.space-y-6')).toBeInTheDocument() }) it('should not render preview content when loading', () => { const estimateData = createMockEstimateData() render() expect(screen.queryByText('Chunk content 1')).not.toBeInTheDocument() }) }) describe('QA Mode Preview', () => { it('should render QA preview chunks when doc_form is qa', () => { mockDocForm.mockReturnValue(ChunkingMode.qa) const estimateData = createMockEstimateData({ qa_preview: [ { question: 'Question 1?', answer: 'Answer 1' }, { question: 'Question 2?', answer: 'Answer 2' }, ], }) render() expect(screen.getByText('Question 1?')).toBeInTheDocument() expect(screen.getByText('Answer 1')).toBeInTheDocument() expect(screen.getByText('Question 2?')).toBeInTheDocument() expect(screen.getByText('Answer 2')).toBeInTheDocument() }) }) describe('Text Mode Preview', () => { it('should render text preview chunks when doc_form is text', () => { mockDocForm.mockReturnValue(ChunkingMode.text) const estimateData = createMockEstimateData({ preview: [ { content: 'Text chunk 1', child_chunks: [] }, { content: 'Text chunk 2', child_chunks: [] }, ], }) render() expect(screen.getByText('Text chunk 1')).toBeInTheDocument() expect(screen.getByText('Text chunk 2')).toBeInTheDocument() }) }) describe('Parent-Child Mode Preview', () => { it('should render parent-child preview chunks', () => { mockDocForm.mockReturnValue(ChunkingMode.parentChild) const estimateData = createMockEstimateData({ preview: [ { content: 'Parent chunk 1', child_chunks: ['Child 1', 'Child 2'] }, ], }) render() expect(screen.getByText('Child 1')).toBeInTheDocument() expect(screen.getByText('Child 2')).toBeInTheDocument() }) }) describe('Document Selection', () => { it('should handle local file selection change', () => { const handlePreviewFileChange = jest.fn() const localFiles = [ createMockLocalFile({ id: 'file-1', name: 'file1.pdf' }), createMockLocalFile({ id: 'file-2', name: 'file2.pdf' }), ] render( , ) const select = screen.getByTestId('picker-select') fireEvent.change(select, { target: { value: 'file-2' } }) expect(handlePreviewFileChange).toHaveBeenCalled() }) it('should handle online document selection change', () => { const handlePreviewOnlineDocumentChange = jest.fn() const onlineDocuments = [ createMockNotionPage({ page_id: 'page-1', page_name: 'Page 1' }), createMockNotionPage({ page_id: 'page-2', page_name: 'Page 2' }), ] render( , ) const select = screen.getByTestId('picker-select') fireEvent.change(select, { target: { value: 'page-2' } }) expect(handlePreviewOnlineDocumentChange).toHaveBeenCalled() }) it('should handle website page selection change', () => { const handlePreviewWebsitePageChange = jest.fn() const websitePages = [ createMockCrawlResult({ source_url: 'https://example1.com', title: 'Site 1' }), createMockCrawlResult({ source_url: 'https://example2.com', title: 'Site 2' }), ] render( , ) const select = screen.getByTestId('picker-select') fireEvent.change(select, { target: { value: 'https://example2.com' } }) expect(handlePreviewWebsitePageChange).toHaveBeenCalled() }) it('should handle online drive file selection change', () => { const handlePreviewOnlineDriveFileChange = jest.fn() const onlineDriveFiles = [ createMockOnlineDriveFile({ id: 'drive-1', name: 'file1.docx' }), createMockOnlineDriveFile({ id: 'drive-2', name: 'file2.docx' }), ] render( , ) const select = screen.getByTestId('picker-select') fireEvent.change(select, { target: { value: 'drive-2' } }) expect(handlePreviewOnlineDriveFileChange).toHaveBeenCalled() }) }) describe('Edge Cases', () => { it('should handle empty estimate data', () => { mockDocForm.mockReturnValue(ChunkingMode.text) render() expect(screen.queryByText('Chunk content')).not.toBeInTheDocument() }) it('should handle empty preview array', () => { mockDocForm.mockReturnValue(ChunkingMode.text) const estimateData = createMockEstimateData({ preview: [] }) render() expect(screen.queryByText('Chunk content')).not.toBeInTheDocument() }) it('should handle empty qa_preview array', () => { mockDocForm.mockReturnValue(ChunkingMode.qa) const estimateData = createMockEstimateData({ qa_preview: [] }) render() expect(screen.queryByText('Q1')).not.toBeInTheDocument() }) it('should handle empty child_chunks in parent-child mode', () => { mockDocForm.mockReturnValue(ChunkingMode.parentChild) const estimateData = createMockEstimateData({ preview: [{ content: 'Parent', child_chunks: [] }], }) render() expect(screen.queryByText('Child')).not.toBeInTheDocument() }) it('should handle badge showing 0 chunks', () => { mockDocForm.mockReturnValue(ChunkingMode.text) const estimateData = createMockEstimateData({ total_segments: 0 }) render() // Badge with 0 expect(screen.getByText(/0/)).toBeInTheDocument() }) it('should handle undefined online document properties', () => { const onlineDocuments = [createMockNotionPage({ page_id: '', page_name: '' })] render( , ) expect(screen.getByTestId('document-picker')).toBeInTheDocument() }) it('should handle undefined website page properties', () => { const websitePages = [createMockCrawlResult({ source_url: '', title: '' })] render( , ) expect(screen.getByTestId('document-picker')).toBeInTheDocument() }) it('should handle undefined online drive file properties', () => { const onlineDriveFiles = [createMockOnlineDriveFile({ id: '', name: '' })] render( , ) expect(screen.getByTestId('document-picker')).toBeInTheDocument() }) }) describe('Component Memoization', () => { it('should be exported as a memoized component', () => { // ChunkPreview is wrapped with React.memo // We verify this by checking the component type expect(typeof ChunkPreview).toBe('object') expect(ChunkPreview.$$typeof?.toString()).toBe('Symbol(react.memo)') }) }) })