refactor(web): migrate to Vitest and esm (#29974)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
This commit is contained in:
Stephen Zhou
2025-12-22 16:35:22 +08:00
committed by GitHub
parent 42f7ecda12
commit eabdc5f0eb
268 changed files with 5455 additions and 6307 deletions

View File

@ -3,26 +3,27 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import type { ExternalAPIItem } from '@/models/datasets'
import ExternalKnowledgeBaseCreate from './index'
import RetrievalSettings from './RetrievalSettings'
// Mock next/navigation
const mockReplace = jest.fn()
const mockRefresh = jest.fn()
jest.mock('next/navigation', () => ({
const mockReplace = vi.fn()
const mockRefresh = vi.fn()
vi.mock('next/navigation', () => ({
useRouter: () => ({
replace: mockReplace,
push: jest.fn(),
push: vi.fn(),
refresh: mockRefresh,
}),
}))
// Mock useDocLink hook
jest.mock('@/context/i18n', () => ({
vi.mock('@/context/i18n', () => ({
useDocLink: () => (path?: string) => `https://docs.dify.ai/en${path || ''}`,
}))
// Mock external context providers (these are external dependencies)
const mockSetShowExternalKnowledgeAPIModal = jest.fn()
jest.mock('@/context/modal-context', () => ({
const mockSetShowExternalKnowledgeAPIModal = vi.fn()
vi.mock('@/context/modal-context', () => ({
useModalContext: () => ({
setShowExternalKnowledgeAPIModal: mockSetShowExternalKnowledgeAPIModal,
}),
@ -58,10 +59,10 @@ const createDefaultMockApiList = (): ExternalAPIItem[] => [
}),
]
const mockMutateExternalKnowledgeApis = jest.fn()
const mockMutateExternalKnowledgeApis = vi.fn()
let mockExternalKnowledgeApiList: ExternalAPIItem[] = createDefaultMockApiList()
jest.mock('@/context/external-knowledge-api-context', () => ({
vi.mock('@/context/external-knowledge-api-context', () => ({
useExternalKnowledgeApi: () => ({
externalKnowledgeApiList: mockExternalKnowledgeApiList,
mutateExternalKnowledgeApis: mockMutateExternalKnowledgeApis,
@ -72,7 +73,7 @@ jest.mock('@/context/external-knowledge-api-context', () => ({
// Helper to render component with default props
const renderComponent = (props: Partial<React.ComponentProps<typeof ExternalKnowledgeBaseCreate>> = {}) => {
const defaultProps = {
onConnect: jest.fn(),
onConnect: vi.fn(),
loading: false,
}
return render(<ExternalKnowledgeBaseCreate {...defaultProps} {...props} />)
@ -80,7 +81,7 @@ const renderComponent = (props: Partial<React.ComponentProps<typeof ExternalKnow
describe('ExternalKnowledgeBaseCreate', () => {
beforeEach(() => {
jest.clearAllMocks()
vi.clearAllMocks()
// Reset API list to default using factory function
mockExternalKnowledgeApiList = createDefaultMockApiList()
})
@ -162,7 +163,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
it('should call onConnect with form data when connect button is clicked', async () => {
const user = userEvent.setup()
const onConnect = jest.fn()
const onConnect = vi.fn()
renderComponent({ onConnect })
// Fill in name field (using the actual Input component)
@ -194,7 +195,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
it('should not call onConnect when form is invalid and button is disabled', async () => {
const user = userEvent.setup()
const onConnect = jest.fn()
const onConnect = vi.fn()
renderComponent({ onConnect })
const connectButton = screen.getByText('dataset.externalKnowledgeForm.connect').closest('button')
@ -348,7 +349,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
it('should call onConnect with complete form data when connect is clicked', async () => {
const user = userEvent.setup()
const onConnect = jest.fn()
const onConnect = vi.fn()
renderComponent({ onConnect })
// Fill all fields using real components
@ -400,7 +401,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
describe('ExternalApiSelection Integration', () => {
it('should auto-select first API when API list is available', async () => {
const user = userEvent.setup()
const onConnect = jest.fn()
const onConnect = vi.fn()
renderComponent({ onConnect })
const nameInput = screen.getByPlaceholderText('dataset.externalKnowledgeNamePlaceholder')
@ -434,7 +435,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
it('should allow selecting different API from dropdown', async () => {
const user = userEvent.setup()
const onConnect = jest.fn()
const onConnect = vi.fn()
renderComponent({ onConnect })
// Click on the API selector to open dropdown
@ -655,7 +656,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
it('should maintain stable navBackHandle callback reference', async () => {
const user = userEvent.setup()
const { rerender } = render(
<ExternalKnowledgeBaseCreate onConnect={jest.fn()} loading={false} />,
<ExternalKnowledgeBaseCreate onConnect={vi.fn()} loading={false} />,
)
const buttons = screen.getAllByRole('button')
@ -664,7 +665,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
expect(mockReplace).toHaveBeenCalledTimes(1)
rerender(<ExternalKnowledgeBaseCreate onConnect={jest.fn()} loading={false} />)
rerender(<ExternalKnowledgeBaseCreate onConnect={vi.fn()} loading={false} />)
await user.click(backButton!)
expect(mockReplace).toHaveBeenCalledTimes(2)
@ -672,8 +673,8 @@ describe('ExternalKnowledgeBaseCreate', () => {
it('should not recreate handlers on prop changes', async () => {
const user = userEvent.setup()
const onConnect1 = jest.fn()
const onConnect2 = jest.fn()
const onConnect1 = vi.fn()
const onConnect2 = vi.fn()
const { rerender } = render(
<ExternalKnowledgeBaseCreate onConnect={onConnect1} loading={false} />,
@ -707,7 +708,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
describe('Edge Cases', () => {
it('should handle empty description gracefully', async () => {
const user = userEvent.setup()
const onConnect = jest.fn()
const onConnect = vi.fn()
renderComponent({ onConnect })
const nameInput = screen.getByPlaceholderText('dataset.externalKnowledgeNamePlaceholder')
@ -767,7 +768,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
it('should preserve provider value as external', async () => {
const user = userEvent.setup()
const onConnect = jest.fn()
const onConnect = vi.fn()
renderComponent({ onConnect })
const nameInput = screen.getByPlaceholderText('dataset.externalKnowledgeNamePlaceholder')
@ -813,7 +814,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
describe('RetrievalSettings Integration', () => {
it('should toggle score threshold enabled when switch is clicked', async () => {
const user = userEvent.setup()
const onConnect = jest.fn()
const onConnect = vi.fn()
renderComponent({ onConnect })
// Find and click the switch for score threshold
@ -858,11 +859,8 @@ describe('ExternalKnowledgeBaseCreate', () => {
// Direct unit tests for RetrievalSettings component to cover all branches
describe('RetrievalSettings Component Direct Tests', () => {
// Import RetrievalSettings directly for unit testing
const RetrievalSettings = require('./RetrievalSettings').default
it('should render with isInHitTesting mode', () => {
const onChange = jest.fn()
const onChange = vi.fn()
render(
<RetrievalSettings
topK={4}
@ -878,7 +876,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
})
it('should render with isInRetrievalSetting mode', () => {
const onChange = jest.fn()
const onChange = vi.fn()
render(
<RetrievalSettings
topK={4}
@ -895,7 +893,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
it('should call onChange with score_threshold_enabled when switch is toggled', async () => {
const user = userEvent.setup()
const onChange = jest.fn()
const onChange = vi.fn()
render(
<RetrievalSettings
topK={4}
@ -913,7 +911,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
})
it('should call onChange with top_k when top k value changes', () => {
const onChange = jest.fn()
const onChange = vi.fn()
render(
<RetrievalSettings
topK={4}
@ -932,7 +930,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
})
it('should call onChange with score_threshold when threshold value changes', () => {
const onChange = jest.fn()
const onChange = vi.fn()
render(
<RetrievalSettings
topK={4}
@ -955,7 +953,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
describe('Complete Form Submission Flow', () => {
it('should submit form with all default retrieval settings', async () => {
const user = userEvent.setup()
const onConnect = jest.fn()
const onConnect = vi.fn()
renderComponent({ onConnect })
const nameInput = screen.getByPlaceholderText('dataset.externalKnowledgeNamePlaceholder')
@ -988,7 +986,7 @@ describe('ExternalKnowledgeBaseCreate', () => {
it('should submit form with modified retrieval settings', async () => {
const user = userEvent.setup()
const onConnect = jest.fn()
const onConnect = vi.fn()
renderComponent({ onConnect })
// Toggle score threshold switch