mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 17:38:04 +08:00
fix tests
This commit is contained in:
@ -8,6 +8,8 @@
|
||||
import { cleanup, render, screen } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
let mockTheme = 'light'
|
||||
|
||||
vi.mock('#i18n', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
@ -19,16 +21,16 @@ vi.mock('@/context/i18n', () => ({
|
||||
}))
|
||||
|
||||
vi.mock('@/hooks/use-theme', () => ({
|
||||
default: () => ({ theme: 'light' }),
|
||||
default: () => ({ theme: mockTheme }),
|
||||
}))
|
||||
|
||||
vi.mock('@/i18n-config', () => ({
|
||||
renderI18nObject: (obj: Record<string, string>, locale: string) => obj[locale] || obj.en_US || '',
|
||||
}))
|
||||
|
||||
vi.mock('@/types/app', () => ({
|
||||
Theme: { dark: 'dark', light: 'light' },
|
||||
}))
|
||||
vi.mock('@/types/app', async () => {
|
||||
return vi.importActual<typeof import('@/types/app')>('@/types/app')
|
||||
})
|
||||
|
||||
vi.mock('@/utils/classnames', () => ({
|
||||
cn: (...args: unknown[]) => args.filter(a => typeof a === 'string' && a).join(' '),
|
||||
@ -100,6 +102,7 @@ type CardPayload = Parameters<typeof Card>[0]['payload']
|
||||
describe('Plugin Card Rendering Integration', () => {
|
||||
beforeEach(() => {
|
||||
cleanup()
|
||||
mockTheme = 'light'
|
||||
})
|
||||
|
||||
const makePayload = (overrides = {}) => ({
|
||||
@ -194,9 +197,7 @@ describe('Plugin Card Rendering Integration', () => {
|
||||
})
|
||||
|
||||
it('uses dark icon when theme is dark and icon_dark is provided', () => {
|
||||
vi.doMock('@/hooks/use-theme', () => ({
|
||||
default: () => ({ theme: 'dark' }),
|
||||
}))
|
||||
mockTheme = 'dark'
|
||||
|
||||
const payload = makePayload({
|
||||
icon: 'https://example.com/icon-light.png',
|
||||
@ -204,7 +205,7 @@ describe('Plugin Card Rendering Integration', () => {
|
||||
})
|
||||
|
||||
render(<Card payload={payload} />)
|
||||
expect(screen.getByTestId('card-icon')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('card-icon')).toHaveTextContent('https://example.com/icon-dark.png')
|
||||
})
|
||||
|
||||
it('shows loading placeholder when isLoading is true', () => {
|
||||
|
||||
@ -8,90 +8,149 @@ import { RETRIEVE_METHOD } from '@/types/app'
|
||||
import { IndexingType } from '../../../../create/step-two'
|
||||
import IndexingSection from '../indexing-section'
|
||||
|
||||
// Mock i18n doc link
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/i18n', () => ({
|
||||
useDocLink: () => (path: string) => `https://docs.dify.ai${path}`,
|
||||
}))
|
||||
|
||||
// Mock app-context for child components
|
||||
vi.mock('@/context/app-context', () => ({
|
||||
useSelector: (selector: (state: unknown) => unknown) => {
|
||||
const state = {
|
||||
isCurrentWorkspaceDatasetOperator: false,
|
||||
userProfile: {
|
||||
id: 'user-1',
|
||||
name: 'Current User',
|
||||
email: 'current@example.com',
|
||||
avatar_url: '',
|
||||
role: 'owner',
|
||||
},
|
||||
}
|
||||
return selector(state)
|
||||
},
|
||||
vi.mock('@/app/components/base/divider', () => ({
|
||||
default: ({ className }: { className?: string }) => (
|
||||
<div data-testid="divider" className={className} />
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/service/use-common', async () => {
|
||||
const actual = await vi.importActual<typeof import('@/service/use-common')>('@/service/use-common')
|
||||
return {
|
||||
...actual,
|
||||
useCurrentWorkspace: () => ({
|
||||
data: {
|
||||
trial_credits: 1000,
|
||||
trial_credits_used: 100,
|
||||
next_credit_reset_date: undefined,
|
||||
},
|
||||
isPending: false,
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
// Mock model-provider-page hooks
|
||||
vi.mock('@/app/components/header/account-setting/model-provider-page/hooks', () => ({
|
||||
useModelList: () => ({ data: [], mutate: vi.fn(), isLoading: false }),
|
||||
useCurrentProviderAndModel: () => ({ currentProvider: undefined, currentModel: undefined }),
|
||||
useDefaultModel: () => ({ data: undefined, mutate: vi.fn(), isLoading: false }),
|
||||
useModelListAndDefaultModel: () => ({ modelList: [], defaultModel: undefined }),
|
||||
useModelListAndDefaultModelAndCurrentProviderAndModel: () => ({
|
||||
modelList: [],
|
||||
defaultModel: undefined,
|
||||
currentProvider: undefined,
|
||||
currentModel: undefined,
|
||||
}),
|
||||
useUpdateModelList: () => vi.fn(),
|
||||
useUpdateModelProviders: () => vi.fn(),
|
||||
useLanguage: () => 'en_US',
|
||||
useSystemDefaultModelAndModelList: () => [undefined, vi.fn()],
|
||||
useProviderCredentialsAndLoadBalancing: () => ({
|
||||
credentials: undefined,
|
||||
loadBalancing: undefined,
|
||||
mutate: vi.fn(),
|
||||
isLoading: false,
|
||||
}),
|
||||
useAnthropicBuyQuota: () => vi.fn(),
|
||||
useMarketplaceAllPlugins: () => ({ plugins: [], isLoading: false }),
|
||||
useRefreshModel: () => ({ handleRefreshModel: vi.fn() }),
|
||||
useModelModalHandler: () => vi.fn(),
|
||||
vi.mock('@/app/components/datasets/settings/chunk-structure', () => ({
|
||||
default: ({ chunkStructure }: { chunkStructure: string }) => (
|
||||
<div data-testid="chunk-structure" data-mode={chunkStructure}>
|
||||
{chunkStructure}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
// Mock provider-context
|
||||
vi.mock('@/context/provider-context', () => ({
|
||||
useProviderContext: () => ({
|
||||
textGenerationModelList: [],
|
||||
embeddingsModelList: [],
|
||||
rerankModelList: [],
|
||||
agentThoughtModelList: [],
|
||||
modelProviders: [],
|
||||
textEmbeddingModelList: [],
|
||||
speech2textModelList: [],
|
||||
ttsModelList: [],
|
||||
moderationModelList: [],
|
||||
hasSettedApiKey: true,
|
||||
plan: { type: 'free' },
|
||||
enableBilling: false,
|
||||
onPlanInfoChanged: vi.fn(),
|
||||
isCurrentWorkspaceDatasetOperator: false,
|
||||
supportRetrievalMethods: ['semantic_search', 'full_text_search', 'hybrid_search'],
|
||||
}),
|
||||
vi.mock('@/app/components/datasets/settings/index-method', () => ({
|
||||
default: ({
|
||||
value,
|
||||
disabled,
|
||||
keywordNumber,
|
||||
onChange,
|
||||
onKeywordNumberChange,
|
||||
}: {
|
||||
value: string
|
||||
disabled?: boolean
|
||||
keywordNumber: number
|
||||
onChange: (value: IndexingType) => void
|
||||
onKeywordNumberChange: (value: number) => void
|
||||
}) => (
|
||||
<div
|
||||
data-testid="index-method"
|
||||
data-disabled={disabled ? 'true' : 'false'}
|
||||
data-keyword-number={String(keywordNumber)}
|
||||
data-value={value}
|
||||
>
|
||||
<button type="button" onClick={() => onChange(IndexingType.QUALIFIED)}>
|
||||
stepTwo.qualified
|
||||
</button>
|
||||
<button type="button" onClick={() => onChange(IndexingType.ECONOMICAL)}>
|
||||
form.indexMethodEconomy
|
||||
</button>
|
||||
<button type="button" onClick={() => onKeywordNumberChange(keywordNumber + 1)}>
|
||||
keyword-number-increment
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/header/account-setting/model-provider-page/model-selector', () => ({
|
||||
default: ({
|
||||
defaultModel,
|
||||
onSelect,
|
||||
}: {
|
||||
defaultModel?: DefaultModel
|
||||
onSelect?: (value: DefaultModel) => void
|
||||
}) => (
|
||||
<div
|
||||
data-testid="model-selector"
|
||||
data-model={defaultModel?.model ?? ''}
|
||||
data-provider={defaultModel?.provider ?? ''}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onSelect?.({ provider: 'cohere', model: 'embed-english-v3.0' })}
|
||||
>
|
||||
select-model
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/datasets/settings/summary-index-setting', () => ({
|
||||
default: ({
|
||||
summaryIndexSetting,
|
||||
onSummaryIndexSettingChange,
|
||||
}: {
|
||||
summaryIndexSetting?: SummaryIndexSetting
|
||||
onSummaryIndexSettingChange?: (payload: SummaryIndexSetting) => void
|
||||
}) => (
|
||||
<div data-testid="summary-index-setting" data-enabled={summaryIndexSetting?.enable ? 'true' : 'false'}>
|
||||
<button type="button" onClick={() => onSummaryIndexSettingChange?.({ enable: true })}>
|
||||
summary-enable
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/datasets/common/retrieval-method-config', () => ({
|
||||
default: ({
|
||||
showMultiModalTip,
|
||||
onChange,
|
||||
value,
|
||||
}: {
|
||||
showMultiModalTip?: boolean
|
||||
onChange: (value: RetrievalConfig) => void
|
||||
value: RetrievalConfig
|
||||
}) => (
|
||||
<div data-testid="retrieval-method-config">
|
||||
{showMultiModalTip && <span>show-multimodal-tip</span>}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
onChange({
|
||||
...value,
|
||||
top_k: 6,
|
||||
})}
|
||||
>
|
||||
update-retrieval
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/datasets/common/economical-retrieval-method-config', () => ({
|
||||
default: ({
|
||||
onChange,
|
||||
value,
|
||||
}: {
|
||||
onChange: (value: RetrievalConfig) => void
|
||||
value: RetrievalConfig
|
||||
}) => (
|
||||
<div data-testid="economical-retrieval-method-config">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
onChange({
|
||||
...value,
|
||||
search_method: RETRIEVE_METHOD.keywordSearch,
|
||||
})}
|
||||
>
|
||||
update-economy-retrieval
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
describe('IndexingSection', () => {
|
||||
@ -202,315 +261,281 @@ describe('IndexingSection', () => {
|
||||
showMultiModalTip: false,
|
||||
}
|
||||
|
||||
const renderComponent = (props: Partial<typeof defaultProps> = {}) => {
|
||||
return render(<IndexingSection {...defaultProps} {...props} />)
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render without crashing', () => {
|
||||
render(<IndexingSection {...defaultProps} />)
|
||||
expect(screen.getByText(/form\.chunkStructure\.title/i)).toBeInTheDocument()
|
||||
it('should render the chunk structure, index method, and retrieval sections for a standard dataset', () => {
|
||||
renderComponent()
|
||||
|
||||
expect(screen.getByText('form.chunkStructure.title')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('chunk-structure')).toHaveAttribute('data-mode', ChunkingMode.text)
|
||||
expect(screen.getByText('form.indexMethod')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('index-method')).toBeInTheDocument()
|
||||
expect(screen.getByText('form.retrievalSetting.title')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render chunk structure section when doc_form is set', () => {
|
||||
render(<IndexingSection {...defaultProps} />)
|
||||
expect(screen.getByText(/form\.chunkStructure\.title/i)).toBeInTheDocument()
|
||||
})
|
||||
it('should render the embedding model selector when the index method is high quality', () => {
|
||||
renderComponent()
|
||||
|
||||
it('should render index method section when conditions are met', () => {
|
||||
render(<IndexingSection {...defaultProps} />)
|
||||
// May match multiple elements (label and descriptions)
|
||||
expect(screen.getAllByText(/form\.indexMethod/i).length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('should render embedding model section when indexMethod is high_quality', () => {
|
||||
render(<IndexingSection {...defaultProps} indexMethod={IndexingType.QUALIFIED} />)
|
||||
expect(screen.getByText(/form\.embeddingModel/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render retrieval settings section', () => {
|
||||
render(<IndexingSection {...defaultProps} />)
|
||||
expect(screen.getByText(/form\.retrievalSetting\.title/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('form.embeddingModel')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('model-selector')).toHaveAttribute('data-model', 'text-embedding-ada-002')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Chunk Structure Section', () => {
|
||||
it('should not render chunk structure when doc_form is not set', () => {
|
||||
const datasetWithoutDocForm = { ...mockDataset, doc_form: undefined as unknown as ChunkingMode }
|
||||
render(<IndexingSection {...defaultProps} currentDataset={datasetWithoutDocForm} />)
|
||||
it('should hide the chunk structure section when the dataset has no doc form', () => {
|
||||
renderComponent({
|
||||
currentDataset: {
|
||||
...mockDataset,
|
||||
doc_form: undefined as unknown as ChunkingMode,
|
||||
},
|
||||
})
|
||||
|
||||
expect(screen.queryByText(/form\.chunkStructure\.title/i)).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('form.chunkStructure.title')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('chunk-structure')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render learn more link for chunk structure', () => {
|
||||
render(<IndexingSection {...defaultProps} />)
|
||||
it('should render the chunk structure learn more link and description', () => {
|
||||
renderComponent()
|
||||
|
||||
const learnMoreLink = screen.getByText(/form\.chunkStructure\.learnMore/i)
|
||||
expect(learnMoreLink).toBeInTheDocument()
|
||||
const learnMoreLink = screen.getByRole('link', { name: 'form.chunkStructure.learnMore' })
|
||||
expect(learnMoreLink).toHaveAttribute('href', expect.stringContaining('chunking-and-cleaning-text'))
|
||||
})
|
||||
|
||||
it('should render chunk structure description', () => {
|
||||
render(<IndexingSection {...defaultProps} />)
|
||||
|
||||
expect(screen.getByText(/form\.chunkStructure\.description/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('form.chunkStructure.description')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Index Method Section', () => {
|
||||
it('should not render index method for parentChild chunking mode', () => {
|
||||
const parentChildDataset = { ...mockDataset, doc_form: ChunkingMode.parentChild }
|
||||
render(<IndexingSection {...defaultProps} currentDataset={parentChildDataset} />)
|
||||
it('should hide the index method section for parent-child chunking', () => {
|
||||
renderComponent({
|
||||
currentDataset: {
|
||||
...mockDataset,
|
||||
doc_form: ChunkingMode.parentChild,
|
||||
},
|
||||
})
|
||||
|
||||
expect(screen.queryByText(/form\.indexMethod/i)).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('form.indexMethod')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('index-method')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render high quality option', () => {
|
||||
render(<IndexingSection {...defaultProps} />)
|
||||
it('should render both index method options', () => {
|
||||
renderComponent()
|
||||
|
||||
expect(screen.getByText(/stepTwo\.qualified/i)).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'stepTwo.qualified' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'form.indexMethodEconomy' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render economy option', () => {
|
||||
render(<IndexingSection {...defaultProps} />)
|
||||
|
||||
// May match multiple elements (title and tip)
|
||||
expect(screen.getAllByText(/form\.indexMethodEconomy/i).length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('should call setIndexMethod when index method changes', () => {
|
||||
it('should call setIndexMethod when the user selects a new index method', () => {
|
||||
const setIndexMethod = vi.fn()
|
||||
const { container } = render(<IndexingSection {...defaultProps} setIndexMethod={setIndexMethod} />)
|
||||
renderComponent({ setIndexMethod })
|
||||
|
||||
// Find the economy option card by looking for clickable elements containing the economy text
|
||||
const economyOptions = screen.getAllByText(/form\.indexMethodEconomy/i)
|
||||
if (economyOptions.length > 0) {
|
||||
const economyCard = economyOptions[0].closest('[class*="cursor-pointer"]')
|
||||
if (economyCard) {
|
||||
fireEvent.click(economyCard)
|
||||
}
|
||||
}
|
||||
fireEvent.click(screen.getByRole('button', { name: 'form.indexMethodEconomy' }))
|
||||
|
||||
// The handler should be properly passed - verify component renders without crashing
|
||||
expect(container).toBeInTheDocument()
|
||||
expect(setIndexMethod).toHaveBeenCalledWith(IndexingType.ECONOMICAL)
|
||||
})
|
||||
|
||||
it('should show upgrade warning when switching from economy to high quality', () => {
|
||||
const economyDataset = { ...mockDataset, indexing_technique: IndexingType.ECONOMICAL }
|
||||
render(
|
||||
<IndexingSection
|
||||
{...defaultProps}
|
||||
currentDataset={economyDataset}
|
||||
indexMethod={IndexingType.QUALIFIED}
|
||||
/>,
|
||||
)
|
||||
it('should show an upgrade warning when moving from economy to high quality', () => {
|
||||
renderComponent({
|
||||
currentDataset: {
|
||||
...mockDataset,
|
||||
indexing_technique: IndexingType.ECONOMICAL,
|
||||
},
|
||||
})
|
||||
|
||||
expect(screen.getByText(/form\.upgradeHighQualityTip/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('form.upgradeHighQualityTip')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should not show upgrade warning when already on high quality', () => {
|
||||
render(
|
||||
<IndexingSection
|
||||
{...defaultProps}
|
||||
indexMethod={IndexingType.QUALIFIED}
|
||||
/>,
|
||||
)
|
||||
it('should pass disabled state to the index method when embeddings are unavailable', () => {
|
||||
renderComponent({
|
||||
currentDataset: {
|
||||
...mockDataset,
|
||||
embedding_available: false,
|
||||
},
|
||||
})
|
||||
|
||||
expect(screen.queryByText(/form\.upgradeHighQualityTip/i)).not.toBeInTheDocument()
|
||||
expect(screen.getByTestId('index-method')).toHaveAttribute('data-disabled', 'true')
|
||||
})
|
||||
|
||||
it('should disable index method when embedding is not available', () => {
|
||||
const datasetWithoutEmbedding = { ...mockDataset, embedding_available: false }
|
||||
render(<IndexingSection {...defaultProps} currentDataset={datasetWithoutEmbedding} />)
|
||||
it('should pass the keyword number and update handler through the index method mock', () => {
|
||||
const setKeywordNumber = vi.fn()
|
||||
renderComponent({
|
||||
keywordNumber: 15,
|
||||
setKeywordNumber,
|
||||
})
|
||||
|
||||
// Index method options should be disabled
|
||||
// The exact implementation depends on the IndexMethod component
|
||||
expect(screen.getByTestId('index-method')).toHaveAttribute('data-keyword-number', '15')
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'keyword-number-increment' }))
|
||||
|
||||
expect(setKeywordNumber).toHaveBeenCalledWith(16)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Embedding Model Section', () => {
|
||||
it('should render embedding model when indexMethod is high_quality', () => {
|
||||
render(<IndexingSection {...defaultProps} indexMethod={IndexingType.QUALIFIED} />)
|
||||
it('should hide the embedding model selector for economy indexing', () => {
|
||||
renderComponent({ indexMethod: IndexingType.ECONOMICAL })
|
||||
|
||||
expect(screen.getByText(/form\.embeddingModel/i)).toBeInTheDocument()
|
||||
expect(screen.queryByText('form.embeddingModel')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('model-selector')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should not render embedding model when indexMethod is economy', () => {
|
||||
render(<IndexingSection {...defaultProps} indexMethod={IndexingType.ECONOMICAL} />)
|
||||
|
||||
expect(screen.queryByText(/form\.embeddingModel/i)).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should call setEmbeddingModel when model changes', () => {
|
||||
it('should call setEmbeddingModel when the user selects a model', () => {
|
||||
const setEmbeddingModel = vi.fn()
|
||||
render(
|
||||
<IndexingSection
|
||||
{...defaultProps}
|
||||
setEmbeddingModel={setEmbeddingModel}
|
||||
indexMethod={IndexingType.QUALIFIED}
|
||||
/>,
|
||||
)
|
||||
renderComponent({ setEmbeddingModel })
|
||||
|
||||
// The embedding model selector should be rendered
|
||||
expect(screen.getByText(/form\.embeddingModel/i)).toBeInTheDocument()
|
||||
fireEvent.click(screen.getByRole('button', { name: 'select-model' }))
|
||||
|
||||
expect(setEmbeddingModel).toHaveBeenCalledWith({
|
||||
provider: 'cohere',
|
||||
model: 'embed-english-v3.0',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Summary Index Setting Section', () => {
|
||||
it('should render summary index setting for high quality with text chunking', () => {
|
||||
render(
|
||||
<IndexingSection
|
||||
{...defaultProps}
|
||||
indexMethod={IndexingType.QUALIFIED}
|
||||
/>,
|
||||
)
|
||||
it('should render the summary index setting only for high quality text chunking', () => {
|
||||
renderComponent()
|
||||
expect(screen.getByTestId('summary-index-setting')).toBeInTheDocument()
|
||||
|
||||
// Summary index setting should be rendered based on conditions
|
||||
// The exact rendering depends on the SummaryIndexSetting component
|
||||
renderComponent({
|
||||
indexMethod: IndexingType.ECONOMICAL,
|
||||
})
|
||||
expect(screen.getAllByTestId('summary-index-setting')).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('should not render summary index setting for economy indexing', () => {
|
||||
render(
|
||||
<IndexingSection
|
||||
{...defaultProps}
|
||||
indexMethod={IndexingType.ECONOMICAL}
|
||||
/>,
|
||||
)
|
||||
|
||||
// Summary index setting should not be rendered for economy
|
||||
})
|
||||
|
||||
it('should call handleSummaryIndexSettingChange when setting changes', () => {
|
||||
it('should call handleSummaryIndexSettingChange when the summary setting changes', () => {
|
||||
const handleSummaryIndexSettingChange = vi.fn()
|
||||
render(
|
||||
<IndexingSection
|
||||
{...defaultProps}
|
||||
handleSummaryIndexSettingChange={handleSummaryIndexSettingChange}
|
||||
indexMethod={IndexingType.QUALIFIED}
|
||||
/>,
|
||||
)
|
||||
renderComponent({ handleSummaryIndexSettingChange })
|
||||
|
||||
// The handler should be properly passed
|
||||
fireEvent.click(screen.getByRole('button', { name: 'summary-enable' }))
|
||||
|
||||
expect(handleSummaryIndexSettingChange).toHaveBeenCalledWith({ enable: true })
|
||||
})
|
||||
})
|
||||
|
||||
describe('Retrieval Settings Section', () => {
|
||||
it('should render retrieval settings', () => {
|
||||
render(<IndexingSection {...defaultProps} />)
|
||||
it('should render the retrieval learn more link', () => {
|
||||
renderComponent()
|
||||
|
||||
expect(screen.getByText(/form\.retrievalSetting\.title/i)).toBeInTheDocument()
|
||||
const learnMoreLink = screen.getByRole('link', { name: 'form.retrievalSetting.learnMore' })
|
||||
expect(learnMoreLink).toHaveAttribute('href', expect.stringContaining('setting-indexing-methods'))
|
||||
expect(screen.getByText('form.retrievalSetting.description')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render learn more link for retrieval settings', () => {
|
||||
render(<IndexingSection {...defaultProps} />)
|
||||
|
||||
const learnMoreLinks = screen.getAllByText(/learnMore/i)
|
||||
const retrievalLearnMore = learnMoreLinks.find(link =>
|
||||
link.closest('a')?.href?.includes('setting-indexing-methods'),
|
||||
)
|
||||
expect(retrievalLearnMore).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render RetrievalMethodConfig for high quality indexing', () => {
|
||||
render(<IndexingSection {...defaultProps} indexMethod={IndexingType.QUALIFIED} />)
|
||||
|
||||
// RetrievalMethodConfig should be rendered
|
||||
expect(screen.getByText(/form\.retrievalSetting\.title/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render EconomicalRetrievalMethodConfig for economy indexing', () => {
|
||||
render(<IndexingSection {...defaultProps} indexMethod={IndexingType.ECONOMICAL} />)
|
||||
|
||||
// EconomicalRetrievalMethodConfig should be rendered
|
||||
expect(screen.getByText(/form\.retrievalSetting\.title/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should call setRetrievalConfig when config changes', () => {
|
||||
it('should render the high-quality retrieval config and propagate changes', () => {
|
||||
const setRetrievalConfig = vi.fn()
|
||||
render(<IndexingSection {...defaultProps} setRetrievalConfig={setRetrievalConfig} />)
|
||||
renderComponent({ setRetrievalConfig })
|
||||
|
||||
// The handler should be properly passed
|
||||
expect(screen.getByTestId('retrieval-method-config')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'update-retrieval' }))
|
||||
|
||||
expect(setRetrievalConfig).toHaveBeenCalledWith({
|
||||
...mockRetrievalConfig,
|
||||
top_k: 6,
|
||||
})
|
||||
})
|
||||
|
||||
it('should pass showMultiModalTip to RetrievalMethodConfig', () => {
|
||||
render(<IndexingSection {...defaultProps} showMultiModalTip={true} />)
|
||||
it('should render the economical retrieval config for economy indexing', () => {
|
||||
const setRetrievalConfig = vi.fn()
|
||||
renderComponent({
|
||||
indexMethod: IndexingType.ECONOMICAL,
|
||||
setRetrievalConfig,
|
||||
})
|
||||
|
||||
// The tip should be passed to the config component
|
||||
expect(screen.getByTestId('economical-retrieval-method-config')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'update-economy-retrieval' }))
|
||||
|
||||
expect(setRetrievalConfig).toHaveBeenCalledWith({
|
||||
...mockRetrievalConfig,
|
||||
search_method: RETRIEVE_METHOD.keywordSearch,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('External Provider', () => {
|
||||
it('should not render retrieval config for external provider', () => {
|
||||
const externalDataset = { ...mockDataset, provider: 'external' }
|
||||
render(<IndexingSection {...defaultProps} currentDataset={externalDataset} />)
|
||||
it('should pass the multimodal tip flag to the retrieval config', () => {
|
||||
renderComponent({ showMultiModalTip: true })
|
||||
|
||||
// Retrieval config should not be rendered for external provider
|
||||
// This is handled by the parent component, but we verify the condition
|
||||
expect(screen.getByText('show-multimodal-tip')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should hide retrieval configuration for external datasets', () => {
|
||||
renderComponent({
|
||||
currentDataset: {
|
||||
...mockDataset,
|
||||
provider: 'external',
|
||||
},
|
||||
})
|
||||
|
||||
expect(screen.queryByText('form.retrievalSetting.title')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('retrieval-method-config')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('economical-retrieval-method-config')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Conditional Rendering', () => {
|
||||
it('should show divider between sections', () => {
|
||||
const { container } = render(<IndexingSection {...defaultProps} />)
|
||||
it('should render dividers between visible sections', () => {
|
||||
renderComponent()
|
||||
|
||||
// Dividers should be present
|
||||
const dividers = container.querySelectorAll('.bg-divider-subtle')
|
||||
expect(dividers.length).toBeGreaterThan(0)
|
||||
expect(screen.getAllByTestId('divider').length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('should not render index method when indexing_technique is not set', () => {
|
||||
const datasetWithoutTechnique = { ...mockDataset, indexing_technique: undefined as unknown as IndexingType }
|
||||
render(<IndexingSection {...defaultProps} currentDataset={datasetWithoutTechnique} indexMethod={undefined} />)
|
||||
it('should hide the index method section when the dataset lacks an indexing technique', () => {
|
||||
renderComponent({
|
||||
currentDataset: {
|
||||
...mockDataset,
|
||||
indexing_technique: undefined as unknown as IndexingType,
|
||||
},
|
||||
indexMethod: undefined,
|
||||
})
|
||||
|
||||
expect(screen.queryByText(/form\.indexMethod/i)).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Keyword Number', () => {
|
||||
it('should pass keywordNumber to IndexMethod', () => {
|
||||
render(<IndexingSection {...defaultProps} keywordNumber={15} />)
|
||||
|
||||
// The keyword number should be displayed in the economy option description
|
||||
// The exact rendering depends on the IndexMethod component
|
||||
})
|
||||
|
||||
it('should call setKeywordNumber when keyword number changes', () => {
|
||||
const setKeywordNumber = vi.fn()
|
||||
render(<IndexingSection {...defaultProps} setKeywordNumber={setKeywordNumber} />)
|
||||
|
||||
// The handler should be properly passed
|
||||
expect(screen.queryByText('form.indexMethod')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('index-method')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Props Updates', () => {
|
||||
it('should update when indexMethod changes', () => {
|
||||
const { rerender } = render(<IndexingSection {...defaultProps} indexMethod={IndexingType.QUALIFIED} />)
|
||||
it('should update the embedding model section when indexMethod changes', () => {
|
||||
const { rerender } = renderComponent()
|
||||
|
||||
expect(screen.getByText(/form\.embeddingModel/i)).toBeInTheDocument()
|
||||
expect(screen.getByTestId('model-selector')).toBeInTheDocument()
|
||||
|
||||
rerender(<IndexingSection {...defaultProps} indexMethod={IndexingType.ECONOMICAL} />)
|
||||
|
||||
expect(screen.queryByText(/form\.embeddingModel/i)).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('model-selector')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should update when currentDataset changes', () => {
|
||||
const { rerender } = render(<IndexingSection {...defaultProps} />)
|
||||
it('should update the chunk structure section when currentDataset changes', () => {
|
||||
const { rerender } = renderComponent()
|
||||
|
||||
expect(screen.getByText(/form\.chunkStructure\.title/i)).toBeInTheDocument()
|
||||
expect(screen.getByTestId('chunk-structure')).toBeInTheDocument()
|
||||
|
||||
const datasetWithoutDocForm = { ...mockDataset, doc_form: undefined as unknown as ChunkingMode }
|
||||
rerender(<IndexingSection {...defaultProps} currentDataset={datasetWithoutDocForm} />)
|
||||
rerender(
|
||||
<IndexingSection
|
||||
{...defaultProps}
|
||||
currentDataset={{
|
||||
...mockDataset,
|
||||
doc_form: undefined as unknown as ChunkingMode,
|
||||
}}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.queryByText(/form\.chunkStructure\.title/i)).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('chunk-structure')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Undefined Dataset', () => {
|
||||
it('should handle undefined currentDataset gracefully', () => {
|
||||
render(<IndexingSection {...defaultProps} currentDataset={undefined} />)
|
||||
it('should render safely when currentDataset is undefined', () => {
|
||||
renderComponent({ currentDataset: undefined })
|
||||
|
||||
// Should not crash and should handle undefined gracefully
|
||||
// Most sections should not render without a dataset
|
||||
expect(screen.queryByTestId('chunk-structure')).not.toBeInTheDocument()
|
||||
expect(screen.getByTestId('model-selector')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('retrieval-method-config')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user