diff --git a/web/app/components/datasets/create-from-pipeline/list/index.spec.tsx b/web/app/components/datasets/create-from-pipeline/list/index.spec.tsx
new file mode 100644
index 0000000000..b37833973d
--- /dev/null
+++ b/web/app/components/datasets/create-from-pipeline/list/index.spec.tsx
@@ -0,0 +1,842 @@
+import { render, screen } from '@testing-library/react'
+import List from './index'
+import type { PipelineTemplate, PipelineTemplateListResponse } from '@/models/pipeline'
+import { ChunkingMode } from '@/models/datasets'
+
+// Mock i18n context
+let mockLocale = 'en-US'
+jest.mock('@/context/i18n', () => ({
+ useI18N: () => ({
+ locale: mockLocale,
+ }),
+}))
+
+// Mock global public store
+let mockEnableMarketplace = true
+jest.mock('@/context/global-public-context', () => ({
+ useGlobalPublicStore: (selector: (state: { systemFeatures: { enable_marketplace: boolean } }) => boolean) =>
+ selector({ systemFeatures: { enable_marketplace: mockEnableMarketplace } }),
+}))
+
+// Mock pipeline service hooks
+let mockBuiltInPipelineData: PipelineTemplateListResponse | undefined
+let mockBuiltInIsLoading = false
+let mockCustomizedPipelineData: PipelineTemplateListResponse | undefined
+let mockCustomizedIsLoading = false
+
+jest.mock('@/service/use-pipeline', () => ({
+ usePipelineTemplateList: (params: { type: 'built-in' | 'customized'; language?: string }, enabled?: boolean) => {
+ if (params.type === 'built-in') {
+ return {
+ data: enabled !== false ? mockBuiltInPipelineData : undefined,
+ isLoading: mockBuiltInIsLoading,
+ }
+ }
+ return {
+ data: mockCustomizedPipelineData,
+ isLoading: mockCustomizedIsLoading,
+ }
+ },
+}))
+
+// Mock CreateCard component to avoid deep service dependencies
+jest.mock('./create-card', () => ({
+ __esModule: true,
+ default: () => (
+
+ datasetPipeline.creation.createFromScratch.title
+ datasetPipeline.creation.createFromScratch.description
+
+ ),
+}))
+
+// Mock TemplateCard component to avoid deep service dependencies
+jest.mock('./template-card', () => ({
+ __esModule: true,
+ default: ({ pipeline, type, showMoreOperations }: {
+ pipeline: PipelineTemplate
+ type: 'built-in' | 'customized'
+ showMoreOperations?: boolean
+ }) => (
+
+ {pipeline.name}
+ {pipeline.description}
+ {pipeline.chunk_structure}
+
+ ),
+}))
+
+// Factory function for creating mock pipeline templates
+const createMockPipelineTemplate = (overrides: Partial = {}): PipelineTemplate => ({
+ id: 'template-1',
+ name: 'Test Pipeline',
+ description: 'Test pipeline description',
+ icon: {
+ icon_type: 'emoji',
+ icon: '🔧',
+ icon_background: '#FFEAD5',
+ icon_url: '',
+ },
+ position: 1,
+ chunk_structure: ChunkingMode.text,
+ ...overrides,
+})
+
+describe('List', () => {
+ beforeEach(() => {
+ jest.clearAllMocks()
+ mockLocale = 'en-US'
+ mockEnableMarketplace = true
+ mockBuiltInPipelineData = undefined
+ mockBuiltInIsLoading = false
+ mockCustomizedPipelineData = undefined
+ mockCustomizedIsLoading = false
+ })
+
+ /**
+ * List Component Container
+ * Tests for the main List wrapper component rendering and styling
+ */
+ describe('List Component Container', () => {
+ it('should render without crashing', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ expect(mainContainer).toBeInTheDocument()
+ })
+
+ it('should render the main container as a div element', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ expect(mainContainer.tagName).toBe('DIV')
+ })
+
+ it('should render the main container with grow class for flex expansion', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ expect(mainContainer).toHaveClass('grow')
+ })
+
+ it('should render the main container with gap-y-1 class for vertical spacing', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ expect(mainContainer).toHaveClass('gap-y-1')
+ })
+
+ it('should render the main container with overflow-y-auto for vertical scrolling', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ expect(mainContainer).toHaveClass('overflow-y-auto')
+ })
+
+ it('should render the main container with horizontal padding px-16', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ expect(mainContainer).toHaveClass('px-16')
+ })
+
+ it('should render the main container with bottom padding pb-[60px]', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ expect(mainContainer).toHaveClass('pb-[60px]')
+ })
+
+ it('should render the main container with top padding pt-1', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ expect(mainContainer).toHaveClass('pt-1')
+ })
+
+ it('should have all required styling classes applied', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ expect(mainContainer).toHaveClass('grow')
+ expect(mainContainer).toHaveClass('gap-y-1')
+ expect(mainContainer).toHaveClass('overflow-y-auto')
+ expect(mainContainer).toHaveClass('px-16')
+ expect(mainContainer).toHaveClass('pb-[60px]')
+ expect(mainContainer).toHaveClass('pt-1')
+ })
+
+ it('should render both BuiltInPipelineList and CustomizedList as children when customized data exists', () => {
+ mockCustomizedPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate({ id: 'custom-child-test' })],
+ }
+
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ // BuiltInPipelineList always renders (1 child)
+ // CustomizedList renders when it has data (adds more children: title + grid)
+ // So we should have at least 2 children when customized data exists
+ expect(mainContainer.children.length).toBeGreaterThanOrEqual(2)
+ })
+
+ it('should render only BuiltInPipelineList when customized list is empty', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ // CustomizedList returns null when empty, so only BuiltInPipelineList renders
+ expect(mainContainer.children.length).toBe(1)
+ })
+ })
+
+ /**
+ * BuiltInPipelineList Integration
+ * Tests for built-in pipeline templates list including CreateCard and TemplateCards
+ */
+ describe('BuiltInPipelineList Integration', () => {
+ it('should render CreateCard component', () => {
+ render(
)
+
+ expect(screen.getByTestId('create-card')).toBeInTheDocument()
+ expect(screen.getByText('datasetPipeline.creation.createFromScratch.title')).toBeInTheDocument()
+ expect(screen.getByText('datasetPipeline.creation.createFromScratch.description')).toBeInTheDocument()
+ })
+
+ it('should render grid container with correct responsive classes', () => {
+ const { container } = render(
)
+
+ const gridContainer = container.querySelector('.grid')
+ expect(gridContainer).toBeInTheDocument()
+ expect(gridContainer).toHaveClass('grid-cols-1')
+ expect(gridContainer).toHaveClass('gap-3')
+ expect(gridContainer).toHaveClass('py-2')
+ expect(gridContainer).toHaveClass('sm:grid-cols-2')
+ expect(gridContainer).toHaveClass('md:grid-cols-3')
+ expect(gridContainer).toHaveClass('lg:grid-cols-4')
+ })
+
+ it('should not render built-in template cards when loading', () => {
+ mockBuiltInIsLoading = true
+ mockBuiltInPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate()],
+ }
+
+ render(
)
+
+ expect(screen.queryByTestId('template-card-template-1')).not.toBeInTheDocument()
+ })
+
+ it('should render built-in template cards when data is loaded', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'built-1', name: 'Pipeline 1' }),
+ createMockPipelineTemplate({ id: 'built-2', name: 'Pipeline 2' }),
+ ],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('template-card-built-1')).toBeInTheDocument()
+ expect(screen.getByTestId('template-card-built-2')).toBeInTheDocument()
+ expect(screen.getByText('Pipeline 1')).toBeInTheDocument()
+ expect(screen.getByText('Pipeline 2')).toBeInTheDocument()
+ })
+
+ it('should render empty state when no built-in templates (only CreateCard visible)', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('create-card')).toBeInTheDocument()
+ expect(screen.queryByTestId(/^template-card-/)).not.toBeInTheDocument()
+ })
+
+ it('should handle undefined pipeline_templates gracefully', () => {
+ mockBuiltInPipelineData = {} as PipelineTemplateListResponse
+
+ render(
)
+
+ expect(screen.getByTestId('create-card')).toBeInTheDocument()
+ })
+
+ it('should pass type=built-in to TemplateCard', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate({ id: 'built-type-test' })],
+ }
+
+ render(
)
+
+ const templateCard = screen.getByTestId('template-card-built-type-test')
+ expect(templateCard).toHaveAttribute('data-type', 'built-in')
+ })
+
+ it('should pass showMoreOperations=false to built-in TemplateCards', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate({ id: 'built-ops-test' })],
+ }
+
+ render(
)
+
+ const templateCard = screen.getByTestId('template-card-built-ops-test')
+ expect(templateCard).toHaveAttribute('data-show-more', 'false')
+ })
+
+ it('should render multiple built-in templates in order', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'first', name: 'First' }),
+ createMockPipelineTemplate({ id: 'second', name: 'Second' }),
+ createMockPipelineTemplate({ id: 'third', name: 'Third' }),
+ ],
+ }
+
+ const { container } = render(
)
+
+ const gridContainer = container.querySelector('.grid')
+ const cards = gridContainer?.querySelectorAll('[data-testid^="template-card-"]')
+
+ expect(cards?.length).toBe(3)
+ })
+ })
+
+ /**
+ * CustomizedList Integration
+ * Tests for customized pipeline templates list including conditional rendering
+ */
+ describe('CustomizedList Integration', () => {
+ it('should return null when loading', () => {
+ mockCustomizedIsLoading = true
+
+ render(
)
+
+ expect(screen.queryByText('datasetPipeline.templates.customized')).not.toBeInTheDocument()
+ })
+
+ it('should return null when list is empty', () => {
+ mockCustomizedPipelineData = {
+ pipeline_templates: [],
+ }
+
+ render(
)
+
+ expect(screen.queryByText('datasetPipeline.templates.customized')).not.toBeInTheDocument()
+ })
+
+ it('should return null when pipeline_templates is undefined', () => {
+ mockCustomizedPipelineData = {} as PipelineTemplateListResponse
+
+ render(
)
+
+ expect(screen.queryByText('datasetPipeline.templates.customized')).not.toBeInTheDocument()
+ })
+
+ it('should render customized section title when data is available', () => {
+ mockCustomizedPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate({ id: 'custom-1' })],
+ }
+
+ render(
)
+
+ expect(screen.getByText('datasetPipeline.templates.customized')).toBeInTheDocument()
+ })
+
+ it('should render customized title with correct styling', () => {
+ mockCustomizedPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate()],
+ }
+
+ const { container } = render(
)
+
+ const title = container.querySelector('.system-sm-semibold-uppercase')
+ expect(title).toBeInTheDocument()
+ expect(title).toHaveClass('pt-2')
+ expect(title).toHaveClass('text-text-tertiary')
+ })
+
+ it('should render customized template cards', () => {
+ mockCustomizedPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'custom-1', name: 'Custom Pipeline 1' }),
+ ],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('template-card-custom-1')).toBeInTheDocument()
+ expect(screen.getByText('Custom Pipeline 1')).toBeInTheDocument()
+ })
+
+ it('should render multiple customized templates', () => {
+ mockCustomizedPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'custom-1', name: 'Custom 1' }),
+ createMockPipelineTemplate({ id: 'custom-2', name: 'Custom 2' }),
+ createMockPipelineTemplate({ id: 'custom-3', name: 'Custom 3' }),
+ ],
+ }
+
+ render(
)
+
+ expect(screen.getByText('Custom 1')).toBeInTheDocument()
+ expect(screen.getByText('Custom 2')).toBeInTheDocument()
+ expect(screen.getByText('Custom 3')).toBeInTheDocument()
+ })
+
+ it('should pass type=customized to TemplateCard', () => {
+ mockCustomizedPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate({ id: 'custom-type-test' })],
+ }
+
+ render(
)
+
+ const templateCard = screen.getByTestId('template-card-custom-type-test')
+ expect(templateCard).toHaveAttribute('data-type', 'customized')
+ })
+
+ it('should not pass showMoreOperations prop to customized TemplateCards (defaults to true)', () => {
+ mockCustomizedPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate({ id: 'custom-ops-test' })],
+ }
+
+ render(
)
+
+ const templateCard = screen.getByTestId('template-card-custom-ops-test')
+ // showMoreOperations is not passed, so data-show-more should be undefined
+ expect(templateCard).not.toHaveAttribute('data-show-more', 'false')
+ })
+
+ it('should render customized grid with responsive classes', () => {
+ mockCustomizedPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate()],
+ }
+
+ const { container } = render(
)
+
+ // Find the second grid (customized list grid)
+ const grids = container.querySelectorAll('.grid')
+ expect(grids.length).toBe(2) // built-in grid and customized grid
+ expect(grids[1]).toHaveClass('grid-cols-1')
+ expect(grids[1]).toHaveClass('gap-3')
+ expect(grids[1]).toHaveClass('py-2')
+ })
+ })
+
+ /**
+ * Language Handling
+ * Tests for locale-based language selection in BuiltInPipelineList
+ */
+ describe('Language Handling', () => {
+ it('should use zh-Hans locale when set', () => {
+ mockLocale = 'zh-Hans'
+ mockBuiltInPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate()],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('create-card')).toBeInTheDocument()
+ })
+
+ it('should use ja-JP locale when set', () => {
+ mockLocale = 'ja-JP'
+ mockBuiltInPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate()],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('create-card')).toBeInTheDocument()
+ })
+
+ it('should fallback to default language for unsupported locales', () => {
+ mockLocale = 'fr-FR'
+ mockBuiltInPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate()],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('create-card')).toBeInTheDocument()
+ })
+
+ it('should handle ko-KR locale (fallback)', () => {
+ mockLocale = 'ko-KR'
+
+ render(
)
+
+ expect(screen.getByTestId('create-card')).toBeInTheDocument()
+ })
+ })
+
+ /**
+ * Marketplace Feature Flag
+ * Tests for enable_marketplace system feature affecting built-in templates fetching
+ */
+ describe('Marketplace Feature Flag', () => {
+ it('should not fetch built-in templates when marketplace is disabled', () => {
+ mockEnableMarketplace = false
+ mockBuiltInPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate({ name: 'Should Not Show' })],
+ }
+
+ render(
)
+
+ // CreateCard should render but template should not (enabled=false)
+ expect(screen.getByTestId('create-card')).toBeInTheDocument()
+ expect(screen.queryByText('Should Not Show')).not.toBeInTheDocument()
+ })
+
+ it('should fetch built-in templates when marketplace is enabled', () => {
+ mockEnableMarketplace = true
+ mockBuiltInPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate({ id: 'marketplace', name: 'Marketplace Template' })],
+ }
+
+ render(
)
+
+ expect(screen.getByText('Marketplace Template')).toBeInTheDocument()
+ })
+ })
+
+ /**
+ * Template Data Rendering
+ * Tests for correct rendering of template properties (name, description, chunk_structure)
+ */
+ describe('Template Data Rendering', () => {
+ it('should render template name correctly', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'name-test', name: 'My Custom Pipeline Name' }),
+ ],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('template-name-name-test')).toHaveTextContent('My Custom Pipeline Name')
+ })
+
+ it('should render template description correctly', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'desc-test', description: 'This is a detailed description' }),
+ ],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('template-description-desc-test')).toHaveTextContent('This is a detailed description')
+ })
+
+ it('should render template with text chunk structure', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'chunk-text', chunk_structure: ChunkingMode.text }),
+ ],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('template-chunk-structure-chunk-text')).toHaveTextContent(ChunkingMode.text)
+ })
+
+ it('should render template with qa chunk structure', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'chunk-qa', chunk_structure: ChunkingMode.qa }),
+ ],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('template-chunk-structure-chunk-qa')).toHaveTextContent(ChunkingMode.qa)
+ })
+
+ it('should render template with parentChild chunk structure', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'chunk-pc', chunk_structure: ChunkingMode.parentChild }),
+ ],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('template-chunk-structure-chunk-pc')).toHaveTextContent(ChunkingMode.parentChild)
+ })
+ })
+
+ /**
+ * Edge Cases
+ * Tests for boundary conditions, special characters, and component lifecycle
+ */
+ describe('Edge Cases', () => {
+ it('should handle component mounting without errors', () => {
+ expect(() => render(
)).not.toThrow()
+ })
+
+ it('should handle component unmounting without errors', () => {
+ const { unmount } = render(
)
+
+ expect(() => unmount()).not.toThrow()
+ })
+
+ it('should handle multiple rerenders without issues', () => {
+ const { rerender } = render(
)
+
+ rerender(
)
+ rerender(
)
+ rerender(
)
+
+ expect(screen.getByTestId('create-card')).toBeInTheDocument()
+ })
+
+ it('should maintain consistent DOM structure across rerenders', () => {
+ const { container, rerender } = render(
)
+
+ const initialChildCount = (container.firstChild as HTMLElement)?.children.length
+
+ rerender(
)
+
+ const afterRerenderChildCount = (container.firstChild as HTMLElement)?.children.length
+ expect(afterRerenderChildCount).toBe(initialChildCount)
+ })
+
+ it('should handle concurrent built-in and customized templates', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'built-in-1', name: 'Built-in Template' }),
+ ],
+ }
+ mockCustomizedPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'custom-1', name: 'Customized Template' }),
+ ],
+ }
+
+ render(
)
+
+ expect(screen.getByText('Built-in Template')).toBeInTheDocument()
+ expect(screen.getByText('Customized Template')).toBeInTheDocument()
+ expect(screen.getByText('datasetPipeline.templates.customized')).toBeInTheDocument()
+ })
+
+ it('should handle templates with long names gracefully', () => {
+ const longName = 'A'.repeat(100)
+ mockBuiltInPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'long-name', name: longName }),
+ ],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('template-name-long-name')).toHaveTextContent(longName)
+ })
+
+ it('should handle templates with empty description', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'empty-desc', description: '' }),
+ ],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('template-description-empty-desc')).toHaveTextContent('')
+ })
+
+ it('should handle templates with special characters in name', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [
+ createMockPipelineTemplate({ id: 'special', name: 'Test <>&"\'Pipeline' }),
+ ],
+ }
+
+ render(
)
+
+ expect(screen.getByTestId('template-name-special')).toHaveTextContent('Test <>&"\'Pipeline')
+ })
+
+ it('should handle rapid mount/unmount cycles', () => {
+ for (let i = 0; i < 5; i++) {
+ const { unmount } = render(
)
+ unmount()
+ }
+
+ expect(true).toBe(true)
+ })
+ })
+
+ /**
+ * Loading States
+ * Tests for component behavior during data loading
+ */
+ describe('Loading States', () => {
+ it('should handle both lists loading simultaneously', () => {
+ mockBuiltInIsLoading = true
+ mockCustomizedIsLoading = true
+
+ render(
)
+
+ expect(screen.getByTestId('create-card')).toBeInTheDocument()
+ expect(screen.queryByText('datasetPipeline.templates.customized')).not.toBeInTheDocument()
+ })
+
+ it('should handle built-in loading while customized is loaded', () => {
+ mockBuiltInIsLoading = true
+ mockCustomizedPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate({ id: 'custom-only', name: 'Customized Only' })],
+ }
+
+ render(
)
+
+ expect(screen.getByText('Customized Only')).toBeInTheDocument()
+ })
+
+ it('should handle customized loading while built-in is loaded', () => {
+ mockCustomizedIsLoading = true
+ mockBuiltInPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate({ id: 'built-only', name: 'Built-in Only' })],
+ }
+
+ render(
)
+
+ expect(screen.getByText('Built-in Only')).toBeInTheDocument()
+ expect(screen.queryByText('datasetPipeline.templates.customized')).not.toBeInTheDocument()
+ })
+
+ it('should transition from loading to loaded state', () => {
+ mockBuiltInIsLoading = true
+ const { rerender } = render(
)
+
+ expect(screen.queryByTestId('template-card-transition')).not.toBeInTheDocument()
+
+ // Simulate data loaded
+ mockBuiltInIsLoading = false
+ mockBuiltInPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate({ id: 'transition', name: 'After Load' })],
+ }
+
+ rerender(
)
+
+ expect(screen.getByText('After Load')).toBeInTheDocument()
+ })
+ })
+
+ /**
+ * Component Stability
+ * Tests for consistent rendering and state management
+ */
+ describe('Component Stability', () => {
+ it('should render same structure on initial render and rerender', () => {
+ const { container, rerender } = render(
)
+
+ const initialHTML = container.innerHTML
+
+ rerender(
)
+
+ const rerenderHTML = container.innerHTML
+ expect(rerenderHTML).toBe(initialHTML)
+ })
+
+ it('should not cause memory leaks on unmount', () => {
+ const { unmount } = render(
)
+
+ unmount()
+
+ expect(true).toBe(true)
+ })
+
+ it('should handle state changes correctly', () => {
+ mockBuiltInPipelineData = undefined
+
+ const { rerender } = render(
)
+
+ // Add data
+ mockBuiltInPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate({ id: 'state-test', name: 'State Test' })],
+ }
+
+ rerender(
)
+
+ expect(screen.getByText('State Test')).toBeInTheDocument()
+ })
+ })
+
+ /**
+ * Accessibility
+ * Tests for semantic structure and keyboard navigation support
+ */
+ describe('Accessibility', () => {
+ it('should use semantic div structure for main container', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ expect(mainContainer.tagName).toBe('DIV')
+ })
+
+ it('should have scrollable container for keyboard navigation', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ expect(mainContainer).toHaveClass('overflow-y-auto')
+ })
+
+ it('should have appropriate spacing for readability', () => {
+ const { container } = render(
)
+
+ const mainContainer = container.firstChild as HTMLElement
+ expect(mainContainer).toHaveClass('gap-y-1')
+ expect(mainContainer).toHaveClass('px-16')
+ })
+
+ it('should render grid structure for template cards', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: [createMockPipelineTemplate()],
+ }
+
+ const { container } = render(
)
+
+ const grid = container.querySelector('.grid')
+ expect(grid).toBeInTheDocument()
+ })
+ })
+
+ /**
+ * Large Datasets
+ * Tests for performance with many templates
+ */
+ describe('Large Datasets', () => {
+ it('should handle many built-in templates', () => {
+ mockBuiltInPipelineData = {
+ pipeline_templates: Array.from({ length: 50 }, (_, i) =>
+ createMockPipelineTemplate({ id: `built-${i}`, name: `Pipeline ${i}` }),
+ ),
+ }
+
+ render(
)
+
+ expect(screen.getByText('Pipeline 0')).toBeInTheDocument()
+ expect(screen.getByText('Pipeline 49')).toBeInTheDocument()
+ })
+
+ it('should handle many customized templates', () => {
+ mockCustomizedPipelineData = {
+ pipeline_templates: Array.from({ length: 50 }, (_, i) =>
+ createMockPipelineTemplate({ id: `custom-${i}`, name: `Custom ${i}` }),
+ ),
+ }
+
+ render(
)
+
+ expect(screen.getByText('Custom 0')).toBeInTheDocument()
+ expect(screen.getByText('Custom 49')).toBeInTheDocument()
+ })
+ })
+})