mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 02:18:08 +08:00
Merge remote-tracking branch 'origin/main' into feat/support-agent-sandbox
# Conflicts: # api/uv.lock # web/app/components/apps/__tests__/app-card.spec.tsx # web/app/components/apps/__tests__/list.spec.tsx # web/app/components/datasets/create/__tests__/index.spec.tsx # web/app/components/datasets/metadata/metadata-dataset/__tests__/dataset-metadata-drawer.spec.tsx # web/app/components/plugins/readme-panel/__tests__/index.spec.tsx # web/app/components/rag-pipeline/__tests__/index.spec.tsx # web/app/components/rag-pipeline/hooks/__tests__/index.spec.ts # web/eslint-suppressions.json
This commit is contained in:
173
web/app/components/datasets/preview/__tests__/container.spec.tsx
Normal file
173
web/app/components/datasets/preview/__tests__/container.spec.tsx
Normal file
@ -0,0 +1,173 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import PreviewContainer from '../container'
|
||||
|
||||
// Tests for PreviewContainer - a layout wrapper with header and scrollable main area
|
||||
describe('PreviewContainer', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render header content in a header element', () => {
|
||||
render(<PreviewContainer header={<span>Header Title</span>}>Body</PreviewContainer>)
|
||||
|
||||
expect(screen.getByText('Header Title')).toBeInTheDocument()
|
||||
const headerEl = screen.getByText('Header Title').closest('header')
|
||||
expect(headerEl).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render children in a main element', () => {
|
||||
render(<PreviewContainer header="Header">Main content</PreviewContainer>)
|
||||
|
||||
const mainEl = screen.getByRole('main')
|
||||
expect(mainEl).toHaveTextContent('Main content')
|
||||
})
|
||||
|
||||
it('should render both header and children simultaneously', () => {
|
||||
render(
|
||||
<PreviewContainer header={<h2>My Header</h2>}>
|
||||
<p>Body paragraph</p>
|
||||
</PreviewContainer>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('My Header')).toBeInTheDocument()
|
||||
expect(screen.getByText('Body paragraph')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render without children', () => {
|
||||
render(<PreviewContainer header="Header" />)
|
||||
|
||||
expect(screen.getByRole('main')).toBeInTheDocument()
|
||||
expect(screen.getByRole('main').childElementCount).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Props', () => {
|
||||
it('should apply className to the outer wrapper div', () => {
|
||||
const { container } = render(
|
||||
<PreviewContainer header="Header" className="outer-class">Content</PreviewContainer>,
|
||||
)
|
||||
|
||||
expect(container.firstElementChild).toHaveClass('outer-class')
|
||||
})
|
||||
|
||||
it('should apply mainClassName to the main element', () => {
|
||||
render(
|
||||
<PreviewContainer header="Header" mainClassName="custom-main">Content</PreviewContainer>,
|
||||
)
|
||||
|
||||
const mainEl = screen.getByRole('main')
|
||||
expect(mainEl).toHaveClass('custom-main')
|
||||
// Default classes should still be present
|
||||
expect(mainEl).toHaveClass('w-full', 'grow', 'overflow-y-auto', 'px-6', 'py-5')
|
||||
})
|
||||
|
||||
it('should forward ref to the inner container div', () => {
|
||||
const ref = vi.fn()
|
||||
render(
|
||||
<PreviewContainer header="Header" ref={ref}>Content</PreviewContainer>,
|
||||
)
|
||||
|
||||
expect(ref).toHaveBeenCalled()
|
||||
const refArg = ref.mock.calls[0][0]
|
||||
expect(refArg).toBeInstanceOf(HTMLDivElement)
|
||||
})
|
||||
|
||||
it('should pass rest props to the inner container div', () => {
|
||||
render(
|
||||
<PreviewContainer header="Header" data-testid="inner-container" id="container-1">
|
||||
Content
|
||||
</PreviewContainer>,
|
||||
)
|
||||
|
||||
const inner = screen.getByTestId('inner-container')
|
||||
expect(inner).toHaveAttribute('id', 'container-1')
|
||||
})
|
||||
|
||||
it('should render ReactNode as header', () => {
|
||||
render(
|
||||
<PreviewContainer header={<div data-testid="complex-header"><span>Complex</span></div>}>
|
||||
Content
|
||||
</PreviewContainer>,
|
||||
)
|
||||
|
||||
expect(screen.getByTestId('complex-header')).toBeInTheDocument()
|
||||
expect(screen.getByText('Complex')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
// Layout structure tests
|
||||
describe('Layout Structure', () => {
|
||||
it('should have header with border-b styling', () => {
|
||||
render(<PreviewContainer header="Header">Content</PreviewContainer>)
|
||||
|
||||
const headerEl = screen.getByText('Header').closest('header')
|
||||
expect(headerEl).toHaveClass('border-b', 'border-divider-subtle')
|
||||
})
|
||||
|
||||
it('should have inner div with flex column layout', () => {
|
||||
render(
|
||||
<PreviewContainer header="Header" data-testid="inner">Content</PreviewContainer>,
|
||||
)
|
||||
|
||||
const inner = screen.getByTestId('inner')
|
||||
expect(inner).toHaveClass('flex', 'h-full', 'w-full', 'flex-col')
|
||||
})
|
||||
|
||||
it('should have main with overflow-y-auto for scrolling', () => {
|
||||
render(<PreviewContainer header="Header">Content</PreviewContainer>)
|
||||
|
||||
expect(screen.getByRole('main')).toHaveClass('overflow-y-auto')
|
||||
})
|
||||
})
|
||||
|
||||
// DisplayName test
|
||||
describe('DisplayName', () => {
|
||||
it('should have correct displayName', () => {
|
||||
expect(PreviewContainer.displayName).toBe('PreviewContainer')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
it('should render with empty string header', () => {
|
||||
render(<PreviewContainer header="">Content</PreviewContainer>)
|
||||
|
||||
const headerEl = screen.getByRole('banner')
|
||||
expect(headerEl).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render with null children', () => {
|
||||
render(<PreviewContainer header="Header">{null}</PreviewContainer>)
|
||||
|
||||
expect(screen.getByRole('main')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render with multiple children', () => {
|
||||
render(
|
||||
<PreviewContainer header="Header">
|
||||
<div>Child 1</div>
|
||||
<div>Child 2</div>
|
||||
<div>Child 3</div>
|
||||
</PreviewContainer>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('Child 1')).toBeInTheDocument()
|
||||
expect(screen.getByText('Child 2')).toBeInTheDocument()
|
||||
expect(screen.getByText('Child 3')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should not crash on re-render with different props', () => {
|
||||
const { rerender } = render(
|
||||
<PreviewContainer header="First" className="a">Content A</PreviewContainer>,
|
||||
)
|
||||
|
||||
rerender(
|
||||
<PreviewContainer header="Second" className="b" mainClassName="new-main">Content B</PreviewContainer>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('Second')).toBeInTheDocument()
|
||||
expect(screen.getByText('Content B')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
141
web/app/components/datasets/preview/__tests__/header.spec.tsx
Normal file
141
web/app/components/datasets/preview/__tests__/header.spec.tsx
Normal file
@ -0,0 +1,141 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { PreviewHeader } from '../header'
|
||||
|
||||
// Tests for PreviewHeader - displays a title and optional children
|
||||
describe('PreviewHeader', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render the title text', () => {
|
||||
render(<PreviewHeader title="Preview Title" />)
|
||||
|
||||
expect(screen.getByText('Preview Title')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render children below the title', () => {
|
||||
render(
|
||||
<PreviewHeader title="Title">
|
||||
<span>Child content</span>
|
||||
</PreviewHeader>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('Title')).toBeInTheDocument()
|
||||
expect(screen.getByText('Child content')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render without children', () => {
|
||||
const { container } = render(<PreviewHeader title="Solo Title" />)
|
||||
|
||||
expect(container.firstElementChild).toBeInTheDocument()
|
||||
expect(screen.getByText('Solo Title')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render title in an inner div with uppercase styling', () => {
|
||||
render(<PreviewHeader title="Styled Title" />)
|
||||
|
||||
const titleEl = screen.getByText('Styled Title')
|
||||
expect(titleEl).toHaveClass('uppercase', 'mb-1', 'px-1', 'text-text-accent')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Props', () => {
|
||||
it('should apply custom className to outer div', () => {
|
||||
render(<PreviewHeader title="Title" className="custom-header" data-testid="header" />)
|
||||
|
||||
expect(screen.getByTestId('header')).toHaveClass('custom-header')
|
||||
})
|
||||
|
||||
it('should pass rest props to the outer div', () => {
|
||||
render(<PreviewHeader title="Title" data-testid="header" id="header-1" aria-label="preview header" />)
|
||||
|
||||
const el = screen.getByTestId('header')
|
||||
expect(el).toHaveAttribute('id', 'header-1')
|
||||
expect(el).toHaveAttribute('aria-label', 'preview header')
|
||||
})
|
||||
|
||||
it('should render with empty string title', () => {
|
||||
render(<PreviewHeader title="" data-testid="header" />)
|
||||
|
||||
const header = screen.getByTestId('header')
|
||||
// Title div exists but is empty
|
||||
const titleDiv = header.querySelector('.uppercase')
|
||||
expect(titleDiv).toBeInTheDocument()
|
||||
expect(titleDiv?.textContent).toBe('')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Structure', () => {
|
||||
it('should render as a div element', () => {
|
||||
render(<PreviewHeader title="Title" data-testid="header" />)
|
||||
|
||||
expect(screen.getByTestId('header').tagName).toBe('DIV')
|
||||
})
|
||||
|
||||
it('should have title div as the first child', () => {
|
||||
render(<PreviewHeader title="Title" data-testid="header" />)
|
||||
|
||||
const header = screen.getByTestId('header')
|
||||
const firstChild = header.firstElementChild
|
||||
expect(firstChild).toHaveTextContent('Title')
|
||||
})
|
||||
|
||||
it('should place children after the title div', () => {
|
||||
render(
|
||||
<PreviewHeader title="Title" data-testid="header">
|
||||
<button>Action</button>
|
||||
</PreviewHeader>,
|
||||
)
|
||||
|
||||
const header = screen.getByTestId('header')
|
||||
const children = Array.from(header.children)
|
||||
expect(children).toHaveLength(2)
|
||||
expect(children[0]).toHaveTextContent('Title')
|
||||
expect(children[1]).toHaveTextContent('Action')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
it('should handle special characters in title', () => {
|
||||
render(<PreviewHeader title="Test & <Special> 'Characters'" />)
|
||||
|
||||
expect(screen.getByText('Test & <Special> \'Characters\'')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should handle long titles', () => {
|
||||
const longTitle = 'A'.repeat(500)
|
||||
render(<PreviewHeader title={longTitle} />)
|
||||
|
||||
expect(screen.getByText(longTitle)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render multiple children', () => {
|
||||
render(
|
||||
<PreviewHeader title="Title">
|
||||
<span>First</span>
|
||||
<span>Second</span>
|
||||
</PreviewHeader>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('First')).toBeInTheDocument()
|
||||
expect(screen.getByText('Second')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render with null children', () => {
|
||||
render(<PreviewHeader title="Title">{null}</PreviewHeader>)
|
||||
|
||||
expect(screen.getByText('Title')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should not crash on re-render with different title', () => {
|
||||
const { rerender } = render(<PreviewHeader title="First Title" />)
|
||||
|
||||
rerender(<PreviewHeader title="Second Title" />)
|
||||
|
||||
expect(screen.queryByText('First Title')).not.toBeInTheDocument()
|
||||
expect(screen.getByText('Second Title')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,6 +1,6 @@
|
||||
import { cleanup, render } from '@testing-library/react'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import DatasetPreview from './index'
|
||||
import DatasetPreview from '../index'
|
||||
|
||||
afterEach(() => {
|
||||
cleanup()
|
||||
Reference in New Issue
Block a user