mirror of
https://github.com/langgenius/dify.git
synced 2026-05-03 17:08:03 +08:00
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:
@ -11,7 +11,7 @@ enum MockCredentialTypeEnum {
|
||||
}
|
||||
|
||||
// Mock plugin-auth module to avoid deep import chain issues
|
||||
jest.mock('@/app/components/plugins/plugin-auth', () => ({
|
||||
vi.mock('@/app/components/plugins/plugin-auth', () => ({
|
||||
CredentialTypeEnum: {
|
||||
OAUTH2: 'oauth2',
|
||||
API_KEY: 'api_key',
|
||||
@ -19,7 +19,7 @@ jest.mock('@/app/components/plugins/plugin-auth', () => ({
|
||||
}))
|
||||
|
||||
// Mock portal-to-follow-elem - use React state to properly handle open/close
|
||||
jest.mock('@/app/components/base/portal-to-follow-elem', () => {
|
||||
vi.mock('@/app/components/base/portal-to-follow-elem', () => {
|
||||
const MockPortalToFollowElem = ({ children, open }: any) => {
|
||||
return (
|
||||
<div data-testid="portal-root" data-open={open}>
|
||||
@ -85,14 +85,14 @@ const createMockCredentials = (count: number = 3): DataSourceCredential[] =>
|
||||
|
||||
const createDefaultProps = (overrides?: Partial<CredentialSelectorProps>): CredentialSelectorProps => ({
|
||||
currentCredentialId: 'cred-1',
|
||||
onCredentialChange: jest.fn(),
|
||||
onCredentialChange: vi.fn(),
|
||||
credentials: createMockCredentials(),
|
||||
...overrides,
|
||||
})
|
||||
|
||||
describe('CredentialSelector', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
// ==========================================
|
||||
@ -277,7 +277,7 @@ describe('CredentialSelector', () => {
|
||||
describe('onCredentialChange prop', () => {
|
||||
it('should be called when selecting a credential', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange })
|
||||
render(<CredentialSelector {...props} />)
|
||||
|
||||
@ -298,7 +298,7 @@ describe('CredentialSelector', () => {
|
||||
['cred-3', 'Credential 3'],
|
||||
])('should call onCredentialChange with %s when selecting %s', (credId, credentialName) => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange })
|
||||
render(<CredentialSelector {...props} />)
|
||||
|
||||
@ -317,7 +317,7 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should call onCredentialChange with cred-1 when selecting Credential 1 in dropdown', () => {
|
||||
// Arrange - Start with cred-2 selected so cred-1 is only in dropdown
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({
|
||||
onCredentialChange: mockOnChange,
|
||||
currentCredentialId: 'cred-2',
|
||||
@ -359,7 +359,7 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should call onCredentialChange when clicking a credential item', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange })
|
||||
render(<CredentialSelector {...props} />)
|
||||
|
||||
@ -376,7 +376,7 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should close dropdown after selecting a credential', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange })
|
||||
render(<CredentialSelector {...props} />)
|
||||
|
||||
@ -410,7 +410,7 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should allow selecting credentials multiple times', () => {
|
||||
// Arrange - Start with cred-2 selected so we can select other credentials
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({
|
||||
onCredentialChange: mockOnChange,
|
||||
currentCredentialId: 'cred-2',
|
||||
@ -435,7 +435,7 @@ describe('CredentialSelector', () => {
|
||||
describe('Side Effects and Cleanup', () => {
|
||||
it('should auto-select first credential when currentCredential is not found and credentials exist', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({
|
||||
currentCredentialId: 'non-existent-id',
|
||||
onCredentialChange: mockOnChange,
|
||||
@ -450,7 +450,7 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should not call onCredentialChange when currentCredential is found', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({
|
||||
currentCredentialId: 'cred-2',
|
||||
onCredentialChange: mockOnChange,
|
||||
@ -465,7 +465,7 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should not call onCredentialChange when credentials array is empty', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({
|
||||
currentCredentialId: 'cred-1',
|
||||
credentials: [],
|
||||
@ -481,7 +481,7 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should auto-select when credentials change and currentCredential becomes invalid', async () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const initialCredentials = createMockCredentials(3)
|
||||
const props = createDefaultProps({
|
||||
currentCredentialId: 'cred-1',
|
||||
@ -512,7 +512,7 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should not trigger auto-select effect on every render with same props', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange })
|
||||
|
||||
// Act - Render and rerender with same props
|
||||
@ -531,7 +531,7 @@ describe('CredentialSelector', () => {
|
||||
describe('Callback Stability and Memoization', () => {
|
||||
it('should have stable handleCredentialChange callback', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange })
|
||||
render(<CredentialSelector {...props} />)
|
||||
|
||||
@ -547,8 +547,8 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should update handleCredentialChange when onCredentialChange changes', () => {
|
||||
// Arrange
|
||||
const mockOnChange1 = jest.fn()
|
||||
const mockOnChange2 = jest.fn()
|
||||
const mockOnChange1 = vi.fn()
|
||||
const mockOnChange2 = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange1 })
|
||||
|
||||
const { rerender } = render(<CredentialSelector {...props} />)
|
||||
@ -618,7 +618,7 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should return undefined currentCredential when id not found', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({
|
||||
currentCredentialId: 'non-existent',
|
||||
onCredentialChange: mockOnChange,
|
||||
@ -643,9 +643,9 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should not re-render when props remain the same', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange })
|
||||
const renderSpy = jest.fn()
|
||||
const renderSpy = vi.fn()
|
||||
|
||||
const TrackedCredentialSelector: React.FC<CredentialSelectorProps> = (trackedProps) => {
|
||||
renderSpy()
|
||||
@ -693,8 +693,8 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should re-render when onCredentialChange reference changes', () => {
|
||||
// Arrange
|
||||
const mockOnChange1 = jest.fn()
|
||||
const mockOnChange2 = jest.fn()
|
||||
const mockOnChange1 = vi.fn()
|
||||
const mockOnChange2 = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange1 })
|
||||
const { rerender } = render(<CredentialSelector {...props} />)
|
||||
|
||||
@ -845,7 +845,7 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should handle credential selection with duplicate names', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const duplicateCredentials = [
|
||||
createMockCredential({ id: 'cred-1', name: 'Same Name' }),
|
||||
createMockCredential({ id: 'cred-2', name: 'Same Name' }),
|
||||
@ -875,7 +875,7 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should not crash when clicking credential after unmount', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange })
|
||||
const { unmount } = render(<CredentialSelector {...props} />)
|
||||
|
||||
@ -1017,7 +1017,7 @@ describe('CredentialSelector', () => {
|
||||
|
||||
it('should pass handleCredentialChange to List component', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange })
|
||||
render(<CredentialSelector {...props} />)
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ enum MockCredentialTypeEnum {
|
||||
}
|
||||
|
||||
// Mock plugin-auth module to avoid deep import chain issues
|
||||
jest.mock('@/app/components/plugins/plugin-auth', () => ({
|
||||
vi.mock('@/app/components/plugins/plugin-auth', () => ({
|
||||
CredentialTypeEnum: {
|
||||
OAUTH2: 'oauth2',
|
||||
API_KEY: 'api_key',
|
||||
@ -18,7 +18,7 @@ jest.mock('@/app/components/plugins/plugin-auth', () => ({
|
||||
}))
|
||||
|
||||
// Mock portal-to-follow-elem - required for CredentialSelector
|
||||
jest.mock('@/app/components/base/portal-to-follow-elem', () => {
|
||||
vi.mock('@/app/components/base/portal-to-follow-elem', () => {
|
||||
const MockPortalToFollowElem = ({ children, open }: any) => {
|
||||
return (
|
||||
<div data-testid="portal-root" data-open={open}>
|
||||
@ -84,14 +84,14 @@ const createDefaultProps = (overrides?: Partial<HeaderProps>): HeaderProps => ({
|
||||
docLink: 'https://docs.example.com',
|
||||
pluginName: 'Test Plugin',
|
||||
currentCredentialId: 'cred-1',
|
||||
onCredentialChange: jest.fn(),
|
||||
onCredentialChange: vi.fn(),
|
||||
credentials: createMockCredentials(),
|
||||
...overrides,
|
||||
})
|
||||
|
||||
describe('Header', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
// ==========================================
|
||||
@ -266,7 +266,7 @@ describe('Header', () => {
|
||||
describe('onClickConfiguration prop', () => {
|
||||
it('should call onClickConfiguration when configuration icon is clicked', () => {
|
||||
// Arrange
|
||||
const mockOnClick = jest.fn()
|
||||
const mockOnClick = vi.fn()
|
||||
const props = createDefaultProps({ onClickConfiguration: mockOnClick })
|
||||
render(<Header {...props} />)
|
||||
|
||||
@ -328,7 +328,7 @@ describe('Header', () => {
|
||||
|
||||
it('should pass onCredentialChange to CredentialSelector', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange })
|
||||
render(<Header {...props} />)
|
||||
|
||||
@ -363,7 +363,7 @@ describe('Header', () => {
|
||||
|
||||
it('should allow credential selection through CredentialSelector', () => {
|
||||
// Arrange
|
||||
const mockOnChange = jest.fn()
|
||||
const mockOnChange = vi.fn()
|
||||
const props = createDefaultProps({ onCredentialChange: mockOnChange })
|
||||
render(<Header {...props} />)
|
||||
|
||||
@ -377,7 +377,7 @@ describe('Header', () => {
|
||||
|
||||
it('should trigger configuration callback when clicking config icon', () => {
|
||||
// Arrange
|
||||
const mockOnConfig = jest.fn()
|
||||
const mockOnConfig = vi.fn()
|
||||
const props = createDefaultProps({ onClickConfiguration: mockOnConfig })
|
||||
const { container } = render(<Header {...props} />)
|
||||
|
||||
@ -402,7 +402,7 @@ describe('Header', () => {
|
||||
it('should not re-render when props remain the same', () => {
|
||||
// Arrange
|
||||
const props = createDefaultProps()
|
||||
const renderSpy = jest.fn()
|
||||
const renderSpy = vi.fn()
|
||||
|
||||
const TrackedHeader: React.FC<HeaderProps> = (trackedProps) => {
|
||||
renderSpy()
|
||||
@ -573,7 +573,7 @@ describe('Header', () => {
|
||||
describe('Integration', () => {
|
||||
it('should work with full credential workflow', () => {
|
||||
// Arrange
|
||||
const mockOnCredentialChange = jest.fn()
|
||||
const mockOnCredentialChange = vi.fn()
|
||||
const props = createDefaultProps({
|
||||
onCredentialChange: mockOnCredentialChange,
|
||||
currentCredentialId: 'cred-1',
|
||||
@ -597,7 +597,7 @@ describe('Header', () => {
|
||||
|
||||
it('should display all components together correctly', () => {
|
||||
// Arrange
|
||||
const mockOnConfig = jest.fn()
|
||||
const mockOnConfig = vi.fn()
|
||||
const props = createDefaultProps({
|
||||
docTitle: 'Integration Test Docs',
|
||||
docLink: 'https://test.com/docs',
|
||||
|
||||
Reference in New Issue
Block a user