mirror of https://github.com/langgenius/dify.git
209 lines
8.2 KiB
TypeScript
209 lines
8.2 KiB
TypeScript
import { fireEvent, render, screen } from '@testing-library/react'
|
|
import { IndexingType } from '../../create/step-two'
|
|
import IndexMethod from './index'
|
|
|
|
// Note: react-i18next is globally mocked in vitest.setup.ts
|
|
|
|
describe('IndexMethod', () => {
|
|
const defaultProps = {
|
|
value: IndexingType.QUALIFIED,
|
|
onChange: vi.fn(),
|
|
keywordNumber: 10,
|
|
onKeywordNumberChange: vi.fn(),
|
|
}
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
describe('Rendering', () => {
|
|
it('should render without crashing', () => {
|
|
render(<IndexMethod {...defaultProps} />)
|
|
expect(screen.getByText(/stepTwo\.qualified/)).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render High Quality option', () => {
|
|
render(<IndexMethod {...defaultProps} />)
|
|
expect(screen.getByText(/stepTwo\.qualified/)).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render Economy option', () => {
|
|
render(<IndexMethod {...defaultProps} />)
|
|
expect(screen.getAllByText(/form\.indexMethodEconomy/).length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it('should render High Quality description', () => {
|
|
render(<IndexMethod {...defaultProps} />)
|
|
expect(screen.getByText(/form\.indexMethodHighQualityTip/)).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render Economy description', () => {
|
|
render(<IndexMethod {...defaultProps} />)
|
|
expect(screen.getByText(/form\.indexMethodEconomyTip/)).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render recommended badge on High Quality', () => {
|
|
render(<IndexMethod {...defaultProps} />)
|
|
expect(screen.getByText(/stepTwo\.recommend/)).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('Active State', () => {
|
|
it('should mark High Quality as active when value is QUALIFIED', () => {
|
|
const { container } = render(<IndexMethod {...defaultProps} value={IndexingType.QUALIFIED} />)
|
|
const activeCards = container.querySelectorAll('.ring-\\[1px\\]')
|
|
expect(activeCards).toHaveLength(1)
|
|
})
|
|
|
|
it('should mark Economy as active when value is ECONOMICAL', () => {
|
|
const { container } = render(<IndexMethod {...defaultProps} value={IndexingType.ECONOMICAL} />)
|
|
const activeCards = container.querySelectorAll('.ring-\\[1px\\]')
|
|
expect(activeCards).toHaveLength(1)
|
|
})
|
|
})
|
|
|
|
describe('User Interactions', () => {
|
|
it('should call onChange with QUALIFIED when High Quality is clicked', () => {
|
|
const handleChange = vi.fn()
|
|
render(<IndexMethod {...defaultProps} value={IndexingType.ECONOMICAL} onChange={handleChange} />)
|
|
|
|
// Find and click High Quality option
|
|
const highQualityTitle = screen.getByText(/stepTwo\.qualified/)
|
|
const card = highQualityTitle.closest('div')?.parentElement?.parentElement?.parentElement
|
|
fireEvent.click(card!)
|
|
|
|
expect(handleChange).toHaveBeenCalledWith(IndexingType.QUALIFIED)
|
|
})
|
|
|
|
it('should call onChange with ECONOMICAL when Economy is clicked', () => {
|
|
const handleChange = vi.fn()
|
|
render(<IndexMethod {...defaultProps} value={IndexingType.QUALIFIED} onChange={handleChange} currentValue={IndexingType.ECONOMICAL} />)
|
|
|
|
// Find and click Economy option - use getAllByText and get the first one (title)
|
|
const economyTitles = screen.getAllByText(/form\.indexMethodEconomy/)
|
|
const economyTitle = economyTitles[0]
|
|
const card = economyTitle.closest('div')?.parentElement?.parentElement?.parentElement
|
|
fireEvent.click(card!)
|
|
|
|
expect(handleChange).toHaveBeenCalledWith(IndexingType.ECONOMICAL)
|
|
})
|
|
|
|
it('should not call onChange when clicking already active option', () => {
|
|
const handleChange = vi.fn()
|
|
render(<IndexMethod {...defaultProps} value={IndexingType.QUALIFIED} onChange={handleChange} />)
|
|
|
|
// Click on already active High Quality
|
|
const highQualityTitle = screen.getByText(/stepTwo\.qualified/)
|
|
const card = highQualityTitle.closest('div')?.parentElement?.parentElement?.parentElement
|
|
fireEvent.click(card!)
|
|
|
|
expect(handleChange).not.toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
describe('Disabled State', () => {
|
|
it('should disable both options when disabled is true', () => {
|
|
const { container } = render(<IndexMethod {...defaultProps} disabled={true} />)
|
|
const disabledCards = container.querySelectorAll('.cursor-not-allowed')
|
|
expect(disabledCards.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it('should disable Economy option when currentValue is QUALIFIED', () => {
|
|
const handleChange = vi.fn()
|
|
render(<IndexMethod {...defaultProps} currentValue={IndexingType.QUALIFIED} onChange={handleChange} value={IndexingType.ECONOMICAL} />)
|
|
|
|
// Try to click Economy option - use getAllByText and get the first one (title)
|
|
const economyTitles = screen.getAllByText(/form\.indexMethodEconomy/)
|
|
const economyTitle = economyTitles[0]
|
|
const card = economyTitle.closest('div')?.parentElement?.parentElement?.parentElement
|
|
fireEvent.click(card!)
|
|
|
|
// Should not call onChange because Economy is disabled when current is QUALIFIED
|
|
expect(handleChange).not.toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
describe('KeywordNumber', () => {
|
|
it('should render KeywordNumber component inside Economy option', () => {
|
|
render(<IndexMethod {...defaultProps} />)
|
|
// KeywordNumber has a slider
|
|
expect(screen.getByRole('slider')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should pass keywordNumber to KeywordNumber component', () => {
|
|
render(<IndexMethod {...defaultProps} keywordNumber={25} />)
|
|
const input = screen.getByRole('spinbutton')
|
|
expect(input).toHaveValue(25)
|
|
})
|
|
|
|
it('should call onKeywordNumberChange when KeywordNumber changes', () => {
|
|
const handleKeywordChange = vi.fn()
|
|
render(<IndexMethod {...defaultProps} onKeywordNumberChange={handleKeywordChange} />)
|
|
|
|
const input = screen.getByRole('spinbutton')
|
|
fireEvent.change(input, { target: { value: '30' } })
|
|
|
|
expect(handleKeywordChange).toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
describe('Tooltip', () => {
|
|
it('should show tooltip when hovering over disabled Economy option', () => {
|
|
// The tooltip is shown via PortalToFollowElem when hovering
|
|
// This is controlled by useHover hook
|
|
render(<IndexMethod {...defaultProps} currentValue={IndexingType.QUALIFIED} />)
|
|
// The tooltip content should exist in DOM but may not be visible
|
|
// We just verify the component renders without error
|
|
expect(screen.getAllByText(/form\.indexMethodEconomy/).length).toBeGreaterThan(0)
|
|
})
|
|
})
|
|
|
|
describe('Effect Colors', () => {
|
|
it('should show orange effect color for High Quality option', () => {
|
|
const { container } = render(<IndexMethod {...defaultProps} />)
|
|
const orangeEffect = container.querySelector('.bg-util-colors-orange-orange-500')
|
|
expect(orangeEffect).toBeInTheDocument()
|
|
})
|
|
|
|
it('should show indigo effect color for Economy option', () => {
|
|
const { container } = render(<IndexMethod {...defaultProps} />)
|
|
const indigoEffect = container.querySelector('.bg-util-colors-indigo-indigo-600')
|
|
expect(indigoEffect).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('Props', () => {
|
|
it('should update active state when value prop changes', () => {
|
|
const { rerender, container } = render(<IndexMethod {...defaultProps} value={IndexingType.QUALIFIED} />)
|
|
|
|
let activeCards = container.querySelectorAll('.ring-\\[1px\\]')
|
|
expect(activeCards).toHaveLength(1)
|
|
|
|
rerender(<IndexMethod {...defaultProps} value={IndexingType.ECONOMICAL} currentValue={IndexingType.ECONOMICAL} />)
|
|
|
|
activeCards = container.querySelectorAll('.ring-\\[1px\\]')
|
|
expect(activeCards).toHaveLength(1)
|
|
})
|
|
})
|
|
|
|
describe('Edge Cases', () => {
|
|
it('should handle undefined currentValue', () => {
|
|
render(<IndexMethod {...defaultProps} currentValue={undefined} />)
|
|
// Should render without error
|
|
expect(screen.getByText(/stepTwo\.qualified/)).toBeInTheDocument()
|
|
})
|
|
|
|
it('should handle keywordNumber of 0', () => {
|
|
render(<IndexMethod {...defaultProps} keywordNumber={0} />)
|
|
const input = screen.getByRole('spinbutton')
|
|
expect(input).toHaveValue(0)
|
|
})
|
|
|
|
it('should handle max keywordNumber', () => {
|
|
render(<IndexMethod {...defaultProps} keywordNumber={50} />)
|
|
const input = screen.getByRole('spinbutton')
|
|
expect(input).toHaveValue(50)
|
|
})
|
|
})
|
|
})
|