import { fireEvent, render, screen, waitFor } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' import List from './index' // Mock next/navigation const mockPush = vi.fn() const mockReplace = vi.fn() vi.mock('next/navigation', () => ({ useRouter: () => ({ push: mockPush, replace: mockReplace, }), })) // Mock ahooks vi.mock('ahooks', async (importOriginal) => { const actual = await importOriginal() return { ...actual, useBoolean: () => [false, { toggle: vi.fn(), setTrue: vi.fn(), setFalse: vi.fn() }], useDebounceFn: (fn: () => void) => ({ run: fn }), useHover: () => false, } }) // Mock app context vi.mock('@/context/app-context', () => ({ useAppContext: () => ({ currentWorkspace: { role: 'admin' }, isCurrentWorkspaceOwner: true, }), useSelector: () => true, })) // Mock global public context vi.mock('@/context/global-public-context', () => ({ useGlobalPublicStore: () => ({ systemFeatures: { branding: { enabled: false }, }, }), })) // Mock external api panel context const mockSetShowExternalApiPanel = vi.fn() vi.mock('@/context/external-api-panel-context', () => ({ useExternalApiPanel: () => ({ showExternalApiPanel: false, setShowExternalApiPanel: mockSetShowExternalApiPanel, }), })) // Mock tag management store vi.mock('@/app/components/base/tag-management/store', () => ({ useStore: () => false, })) // Mock useDocumentTitle hook vi.mock('@/hooks/use-document-title', () => ({ default: vi.fn(), })) // Mock useFormatTimeFromNow hook vi.mock('@/hooks/use-format-time-from-now', () => ({ useFormatTimeFromNow: () => ({ formatTimeFromNow: (timestamp: number) => new Date(timestamp).toLocaleDateString(), }), })) // Mock useKnowledge hook vi.mock('@/hooks/use-knowledge', () => ({ useKnowledge: () => ({ formatIndexingTechniqueAndMethod: () => 'High Quality', }), })) // Mock service hooks vi.mock('@/service/knowledge/use-dataset', () => ({ useDatasetList: vi.fn(() => ({ data: { pages: [{ data: [] }] }, fetchNextPage: vi.fn(), hasNextPage: false, isFetching: false, isFetchingNextPage: false, })), useInvalidDatasetList: () => vi.fn(), useDatasetApiBaseUrl: () => ({ data: { api_base_url: 'https://api.example.com' }, }), })) // Mock Datasets component vi.mock('./datasets', () => ({ default: ({ tags, keywords, includeAll }: { tags: string[], keywords: string, includeAll: boolean }) => (
{tags.join(',')} {keywords} {includeAll ? 'true' : 'false'}
), })) // Mock DatasetFooter component vi.mock('./dataset-footer', () => ({ default: () => , })) // Mock ExternalAPIPanel component vi.mock('../external-api/external-api-panel', () => ({ default: ({ onClose }: { onClose: () => void }) => (
), })) // Mock TagManagementModal vi.mock('@/app/components/base/tag-management', () => ({ default: () =>
, })) // Mock TagFilter vi.mock('@/app/components/base/tag-management/filter', () => ({ default: ({ onChange }: { value: string[], onChange: (val: string[]) => void }) => (
), })) // Mock CheckboxWithLabel vi.mock('@/app/components/datasets/create/website/base/checkbox-with-label', () => ({ default: ({ isChecked, onChange, label }: { isChecked: boolean, onChange: () => void, label: string }) => ( ), })) describe('List', () => { beforeEach(() => { vi.clearAllMocks() }) describe('Rendering', () => { it('should render without crashing', () => { render() expect(screen.getByTestId('datasets-component')).toBeInTheDocument() }) it('should render the search input', () => { render() expect(screen.getByRole('textbox')).toBeInTheDocument() }) it('should render tag filter', () => { render() expect(screen.getByTestId('tag-filter')).toBeInTheDocument() }) it('should render external API panel button', () => { render() expect(screen.getByText(/externalAPIPanelTitle/)).toBeInTheDocument() }) it('should render dataset footer when branding is disabled', () => { render() expect(screen.getByTestId('dataset-footer')).toBeInTheDocument() }) }) describe('Props', () => { it('should pass includeAll prop to Datasets', () => { render() expect(screen.getByTestId('include-all')).toHaveTextContent('false') }) it('should pass empty keywords initially', () => { render() expect(screen.getByTestId('keywords')).toHaveTextContent('') }) it('should pass empty tags initially', () => { render() expect(screen.getByTestId('tags')).toHaveTextContent('') }) }) describe('User Interactions', () => { it('should open external API panel when button is clicked', () => { render() const button = screen.getByText(/externalAPIPanelTitle/) fireEvent.click(button) expect(mockSetShowExternalApiPanel).toHaveBeenCalledWith(true) }) it('should update search input value', () => { render() const input = screen.getByRole('textbox') fireEvent.change(input, { target: { value: 'test search' } }) expect(input).toHaveValue('test search') }) it('should trigger tag filter change', () => { render() // Tag filter is rendered and interactive const selectTagsBtn = screen.getByText('Select Tags') expect(selectTagsBtn).toBeInTheDocument() fireEvent.click(selectTagsBtn) // The onChange callback was triggered (debounced) }) }) describe('Conditional Rendering', () => { it('should show include all checkbox for workspace owner', () => { render() expect(screen.getByTestId('include-all-checkbox')).toBeInTheDocument() }) }) describe('Styles', () => { it('should have correct container styling', () => { const { container } = render() const mainContainer = container.firstChild as HTMLElement expect(mainContainer).toHaveClass('scroll-container', 'relative', 'flex', 'grow', 'flex-col') }) }) describe('Edge Cases', () => { it('should handle empty state gracefully', () => { render() // Should render without errors even with empty data expect(screen.getByTestId('datasets-component')).toBeInTheDocument() }) }) describe('Branch Coverage', () => { it('should redirect normal role users to /apps', async () => { // Re-mock useAppContext with normal role vi.doMock('@/context/app-context', () => ({ useAppContext: () => ({ currentWorkspace: { role: 'normal' }, isCurrentWorkspaceOwner: false, }), useSelector: () => true, })) // Clear module cache and re-import vi.resetModules() const { default: ListComponent } = await import('./index') render() await waitFor(() => { expect(mockReplace).toHaveBeenCalledWith('/apps') }) }) it('should clear search input when onClear is called', () => { render() const input = screen.getByRole('textbox') // First set a value fireEvent.change(input, { target: { value: 'test search' } }) expect(input).toHaveValue('test search') // Find and click the clear button const clearButton = document.querySelector('[class*="clear"], button[aria-label*="clear"]') if (clearButton) { fireEvent.click(clearButton) expect(input).toHaveValue('') } }) it('should show ExternalAPIPanel when showExternalApiPanel is true', async () => { // Re-mock to show external API panel vi.doMock('@/context/external-api-panel-context', () => ({ useExternalApiPanel: () => ({ showExternalApiPanel: true, setShowExternalApiPanel: mockSetShowExternalApiPanel, }), })) vi.resetModules() const { default: ListComponent } = await import('./index') render() expect(screen.getByTestId('external-api-panel')).toBeInTheDocument() }) it('should close ExternalAPIPanel when onClose is called', async () => { vi.doMock('@/context/external-api-panel-context', () => ({ useExternalApiPanel: () => ({ showExternalApiPanel: true, setShowExternalApiPanel: mockSetShowExternalApiPanel, }), })) vi.resetModules() const { default: ListComponent } = await import('./index') render() const closeButton = screen.getByText('Close Panel') fireEvent.click(closeButton) expect(mockSetShowExternalApiPanel).toHaveBeenCalledWith(false) }) it('should show TagManagementModal when showTagManagementModal is true', async () => { vi.doMock('@/app/components/base/tag-management/store', () => ({ useStore: () => true, // showTagManagementModal is true })) vi.resetModules() const { default: ListComponent } = await import('./index') render() expect(screen.getByTestId('tag-management-modal')).toBeInTheDocument() }) it('should not show DatasetFooter when branding is enabled', async () => { vi.doMock('@/context/global-public-context', () => ({ useGlobalPublicStore: () => ({ systemFeatures: { branding: { enabled: true }, }, }), })) vi.resetModules() const { default: ListComponent } = await import('./index') render() expect(screen.queryByTestId('dataset-footer')).not.toBeInTheDocument() }) it('should not show include all checkbox when not workspace owner', async () => { vi.doMock('@/context/app-context', () => ({ useAppContext: () => ({ currentWorkspace: { role: 'editor' }, isCurrentWorkspaceOwner: false, }), useSelector: () => true, })) vi.resetModules() const { default: ListComponent } = await import('./index') render() expect(screen.queryByTestId('include-all-checkbox')).not.toBeInTheDocument() }) }) })