import { fireEvent, render, screen } from '@testing-library/react' import React from 'react' import FilePreview from './file-preview' import type { CustomFile as File } from '@/models/datasets' // Uses __mocks__/react-i18next.ts automatically // Mock useFilePreview hook - needs to be mocked to control return values const mockUseFilePreview = jest.fn() jest.mock('@/service/use-common', () => ({ useFilePreview: (fileID: string) => mockUseFilePreview(fileID), })) // Test data factory const createMockFile = (overrides?: Partial): File => ({ id: 'file-123', name: 'test-document.pdf', size: 2048, 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 File) const createMockFilePreviewData = (content: string = 'This is the file content') => ({ content, }) const defaultProps = { file: createMockFile(), hidePreview: jest.fn(), } describe('FilePreview', () => { beforeEach(() => { jest.clearAllMocks() mockUseFilePreview.mockReturnValue({ data: undefined, isFetching: false, }) }) describe('Rendering', () => { it('should render the component with file information', () => { render() // i18n mock returns key by default expect(screen.getByText('datasetPipeline.addDocuments.stepOne.preview')).toBeInTheDocument() expect(screen.getByText('test-document.pdf')).toBeInTheDocument() }) it('should display file extension in uppercase via CSS class', () => { render() // The extension is displayed in the info section (as uppercase via CSS class) const extensionElement = screen.getByText('pdf') expect(extensionElement).toBeInTheDocument() expect(extensionElement).toHaveClass('uppercase') }) it('should display formatted file size', () => { render() // Real formatFileSize: 2048 bytes => "2.00 KB" expect(screen.getByText('2.00 KB')).toBeInTheDocument() }) it('should render close button', () => { render() expect(screen.getByRole('button')).toBeInTheDocument() }) it('should call useFilePreview with correct fileID', () => { const file = createMockFile({ id: 'specific-file-id' }) render() expect(mockUseFilePreview).toHaveBeenCalledWith('specific-file-id') }) }) describe('File Name Processing', () => { it('should extract file name without extension', () => { const file = createMockFile({ name: 'my-document.pdf', extension: 'pdf' }) render() // The displayed text is `${fileName}.${extension}`, where fileName is name without ext // my-document.pdf -> fileName = 'my-document', displayed as 'my-document.pdf' expect(screen.getByText('my-document.pdf')).toBeInTheDocument() }) it('should handle file name with multiple dots', () => { const file = createMockFile({ name: 'my.file.name.pdf', extension: 'pdf' }) render() // fileName = arr.slice(0, -1).join() = 'my,file,name', then displayed as 'my,file,name.pdf' expect(screen.getByText('my,file,name.pdf')).toBeInTheDocument() }) it('should handle empty file name', () => { const file = createMockFile({ name: '', extension: '' }) render() // fileName = '', displayed as '.' expect(screen.getByText('.')).toBeInTheDocument() }) it('should handle file without extension in name', () => { const file = createMockFile({ name: 'noextension', extension: '' }) render() // fileName = '' (slice returns empty for single element array), displayed as '.' expect(screen.getByText('.')).toBeInTheDocument() }) }) describe('Loading State', () => { it('should render loading component when fetching', () => { mockUseFilePreview.mockReturnValue({ data: undefined, isFetching: true, }) render() // Loading component renders skeleton expect(document.querySelector('.overflow-hidden')).toBeInTheDocument() }) it('should not render content when loading', () => { mockUseFilePreview.mockReturnValue({ data: createMockFilePreviewData('Some content'), isFetching: true, }) render() expect(screen.queryByText('Some content')).not.toBeInTheDocument() }) }) describe('Content Display', () => { it('should render file content when loaded', () => { mockUseFilePreview.mockReturnValue({ data: createMockFilePreviewData('This is the file content'), isFetching: false, }) render() expect(screen.getByText('This is the file content')).toBeInTheDocument() }) it('should display character count when data is available', () => { mockUseFilePreview.mockReturnValue({ data: createMockFilePreviewData('Hello'), // 5 characters isFetching: false, }) render() // Real formatNumberAbbreviated returns "5" for numbers < 1000 expect(screen.getByText(/5/)).toBeInTheDocument() }) it('should format large character counts', () => { const longContent = 'a'.repeat(2500) mockUseFilePreview.mockReturnValue({ data: createMockFilePreviewData(longContent), isFetching: false, }) render() // Real formatNumberAbbreviated uses lowercase 'k': "2.5k" expect(screen.getByText(/2\.5k/)).toBeInTheDocument() }) it('should not display character count when data is not available', () => { mockUseFilePreview.mockReturnValue({ data: undefined, isFetching: false, }) render() // No character text shown expect(screen.queryByText(/datasetPipeline\.addDocuments\.characters/)).not.toBeInTheDocument() }) }) describe('User Interactions', () => { it('should call hidePreview when close button is clicked', () => { const hidePreview = jest.fn() render() const closeButton = screen.getByRole('button') fireEvent.click(closeButton) expect(hidePreview).toHaveBeenCalledTimes(1) }) }) describe('File Size Formatting', () => { it('should format small file sizes in bytes', () => { const file = createMockFile({ size: 500 }) render() // Real formatFileSize: 500 => "500.00 bytes" expect(screen.getByText('500.00 bytes')).toBeInTheDocument() }) it('should format kilobyte file sizes', () => { const file = createMockFile({ size: 5120 }) render() // Real formatFileSize: 5120 => "5.00 KB" expect(screen.getByText('5.00 KB')).toBeInTheDocument() }) it('should format megabyte file sizes', () => { const file = createMockFile({ size: 2097152 }) render() // Real formatFileSize: 2097152 => "2.00 MB" expect(screen.getByText('2.00 MB')).toBeInTheDocument() }) }) describe('Edge Cases', () => { it('should handle undefined file id', () => { const file = createMockFile({ id: undefined }) render() expect(mockUseFilePreview).toHaveBeenCalledWith('') }) it('should handle empty extension', () => { const file = createMockFile({ extension: undefined }) render() expect(screen.getByRole('button')).toBeInTheDocument() }) it('should handle zero file size', () => { const file = createMockFile({ size: 0 }) render() // Real formatFileSize returns 0 for falsy values // The component still renders expect(screen.getByRole('button')).toBeInTheDocument() }) it('should handle very long file content', () => { const veryLongContent = 'a'.repeat(1000000) mockUseFilePreview.mockReturnValue({ data: createMockFilePreviewData(veryLongContent), isFetching: false, }) render() // Real formatNumberAbbreviated: 1000000 => "1M" expect(screen.getByText(/1M/)).toBeInTheDocument() }) it('should handle empty content', () => { mockUseFilePreview.mockReturnValue({ data: createMockFilePreviewData(''), isFetching: false, }) render() // Real formatNumberAbbreviated: 0 => "0" // Find the element that contains character count info expect(screen.getByText(/0 datasetPipeline/)).toBeInTheDocument() }) }) describe('useMemo for fileName', () => { it('should extract file name when file exists', () => { // When file exists, it should extract the name without extension const file = createMockFile({ name: 'document.txt', extension: 'txt' }) render() expect(screen.getByText('document.txt')).toBeInTheDocument() }) it('should memoize fileName based on file prop', () => { const file = createMockFile({ name: 'test.pdf', extension: 'pdf' }) const { rerender } = render() // Same file should produce same result rerender() expect(screen.getByText('test.pdf')).toBeInTheDocument() }) }) })