mirror of
https://github.com/langgenius/dify.git
synced 2026-05-01 07:58:02 +08:00
refactor(components): reorder class names for consistency in various plugin components and add unit tests for CardMoreInfo and other components
This commit is contained in:
@ -1,32 +1,24 @@
|
||||
import type { Plugin } from '../types'
|
||||
import type { Plugin } from '../../types'
|
||||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import * as React from 'react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { PluginCategoryEnum } from '../types'
|
||||
import PluginMutationModal from './index'
|
||||
import { PluginCategoryEnum } from '../../types'
|
||||
import PluginMutationModal from '../index'
|
||||
|
||||
// ================================
|
||||
// Mock External Dependencies Only
|
||||
// ================================
|
||||
|
||||
// Mock useTheme hook
|
||||
vi.mock('@/hooks/use-theme', () => ({
|
||||
default: () => ({ theme: 'light' }),
|
||||
}))
|
||||
|
||||
// Mock i18n-config
|
||||
vi.mock('@/i18n-config', () => ({
|
||||
renderI18nObject: (obj: Record<string, string>, locale: string) => {
|
||||
return obj?.[locale] || obj?.['en-US'] || ''
|
||||
},
|
||||
}))
|
||||
|
||||
// Mock i18n-config/language
|
||||
vi.mock('@/i18n-config/language', () => ({
|
||||
getLanguage: (locale: string) => locale || 'en-US',
|
||||
}))
|
||||
|
||||
// Mock useCategories hook
|
||||
const mockCategoriesMap: Record<string, { label: string }> = {
|
||||
'tool': { label: 'Tool' },
|
||||
'model': { label: 'Model' },
|
||||
@ -37,18 +29,16 @@ const mockCategoriesMap: Record<string, { label: string }> = {
|
||||
'bundle': { label: 'Bundle' },
|
||||
}
|
||||
|
||||
vi.mock('../hooks', () => ({
|
||||
vi.mock('../../hooks', () => ({
|
||||
useCategories: () => ({
|
||||
categoriesMap: mockCategoriesMap,
|
||||
}),
|
||||
}))
|
||||
|
||||
// Mock formatNumber utility
|
||||
vi.mock('@/utils/format', () => ({
|
||||
formatNumber: (num: number) => num.toLocaleString(),
|
||||
}))
|
||||
|
||||
// Mock shouldUseMcpIcon utility
|
||||
vi.mock('@/utils/mcp', () => ({
|
||||
shouldUseMcpIcon: (src: unknown) =>
|
||||
typeof src === 'object'
|
||||
@ -56,7 +46,6 @@ vi.mock('@/utils/mcp', () => ({
|
||||
&& (src as { content?: string })?.content === '🔗',
|
||||
}))
|
||||
|
||||
// Mock AppIcon component
|
||||
vi.mock('@/app/components/base/app-icon', () => ({
|
||||
default: ({
|
||||
icon,
|
||||
@ -83,7 +72,6 @@ vi.mock('@/app/components/base/app-icon', () => ({
|
||||
),
|
||||
}))
|
||||
|
||||
// Mock Mcp icon component
|
||||
vi.mock('@/app/components/base/icons/src/vender/other', () => ({
|
||||
Mcp: ({ className }: { className?: string }) => (
|
||||
<div data-testid="mcp-icon" className={className}>
|
||||
@ -97,8 +85,7 @@ vi.mock('@/app/components/base/icons/src/vender/other', () => ({
|
||||
),
|
||||
}))
|
||||
|
||||
// Mock LeftCorner icon component
|
||||
vi.mock('../../base/icons/src/vender/plugin', () => ({
|
||||
vi.mock('../../../base/icons/src/vender/plugin', () => ({
|
||||
LeftCorner: ({ className }: { className?: string }) => (
|
||||
<div data-testid="left-corner" className={className}>
|
||||
LeftCorner
|
||||
@ -106,8 +93,7 @@ vi.mock('../../base/icons/src/vender/plugin', () => ({
|
||||
),
|
||||
}))
|
||||
|
||||
// Mock Partner badge
|
||||
vi.mock('../base/badges/partner', () => ({
|
||||
vi.mock('../../base/badges/partner', () => ({
|
||||
default: ({ className, text }: { className?: string, text?: string }) => (
|
||||
<div data-testid="partner-badge" className={className} title={text}>
|
||||
Partner
|
||||
@ -115,8 +101,7 @@ vi.mock('../base/badges/partner', () => ({
|
||||
),
|
||||
}))
|
||||
|
||||
// Mock Verified badge
|
||||
vi.mock('../base/badges/verified', () => ({
|
||||
vi.mock('../../base/badges/verified', () => ({
|
||||
default: ({ className, text }: { className?: string, text?: string }) => (
|
||||
<div data-testid="verified-badge" className={className} title={text}>
|
||||
Verified
|
||||
@ -124,36 +109,6 @@ vi.mock('../base/badges/verified', () => ({
|
||||
),
|
||||
}))
|
||||
|
||||
// Mock Remix icons
|
||||
vi.mock('@remixicon/react', () => ({
|
||||
RiCheckLine: ({ className }: { className?: string }) => (
|
||||
<span data-testid="ri-check-line" className={className}>
|
||||
✓
|
||||
</span>
|
||||
),
|
||||
RiCloseLine: ({ className }: { className?: string }) => (
|
||||
<span data-testid="ri-close-line" className={className}>
|
||||
✕
|
||||
</span>
|
||||
),
|
||||
RiInstallLine: ({ className }: { className?: string }) => (
|
||||
<span data-testid="ri-install-line" className={className}>
|
||||
↓
|
||||
</span>
|
||||
),
|
||||
RiAlertFill: ({ className }: { className?: string }) => (
|
||||
<span data-testid="ri-alert-fill" className={className}>
|
||||
⚠
|
||||
</span>
|
||||
),
|
||||
RiLoader2Line: ({ className }: { className?: string }) => (
|
||||
<span data-testid="ri-loader-line" className={className}>
|
||||
⟳
|
||||
</span>
|
||||
),
|
||||
}))
|
||||
|
||||
// Mock Skeleton components
|
||||
vi.mock('@/app/components/base/skeleton', () => ({
|
||||
SkeletonContainer: ({ children }: { children: React.ReactNode }) => (
|
||||
<div data-testid="skeleton-container">{children}</div>
|
||||
@ -330,8 +285,7 @@ describe('PluginMutationModal', () => {
|
||||
|
||||
render(<PluginMutationModal {...props} />)
|
||||
|
||||
// The modal should have a close button
|
||||
expect(screen.getByTestId('ri-close-line')).toBeInTheDocument()
|
||||
expect(screen.getByRole('dialog')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -465,9 +419,8 @@ describe('PluginMutationModal', () => {
|
||||
|
||||
render(<PluginMutationModal {...props} />)
|
||||
|
||||
// Find the close icon - the Modal component handles the onClose callback
|
||||
const closeIcon = screen.getByTestId('ri-close-line')
|
||||
expect(closeIcon).toBeInTheDocument()
|
||||
const dialog = screen.getByRole('dialog')
|
||||
expect(dialog).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should not call mutate when button is disabled during pending', () => {
|
||||
@ -563,9 +516,7 @@ describe('PluginMutationModal', () => {
|
||||
|
||||
render(<PluginMutationModal {...props} />)
|
||||
|
||||
// The Card component should receive installed=true
|
||||
// This will show a check icon
|
||||
expect(screen.getByTestId('ri-check-line')).toBeInTheDocument()
|
||||
expect(document.querySelector('.bg-state-success-solid')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -577,8 +528,7 @@ describe('PluginMutationModal', () => {
|
||||
|
||||
render(<PluginMutationModal {...props} />)
|
||||
|
||||
// The check icon should not be present (installed=false)
|
||||
expect(screen.queryByTestId('ri-check-line')).not.toBeInTheDocument()
|
||||
expect(document.querySelector('.bg-state-success-solid')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -593,7 +543,7 @@ describe('PluginMutationModal', () => {
|
||||
expect(
|
||||
screen.queryByRole('button', { name: /Cancel/i }),
|
||||
).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('ri-check-line')).not.toBeInTheDocument()
|
||||
expect(document.querySelector('.bg-state-success-solid')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should handle isPending=false and isSuccess=true', () => {
|
||||
@ -606,7 +556,7 @@ describe('PluginMutationModal', () => {
|
||||
expect(
|
||||
screen.getByRole('button', { name: /Cancel/i }),
|
||||
).toBeInTheDocument()
|
||||
expect(screen.getByTestId('ri-check-line')).toBeInTheDocument()
|
||||
expect(document.querySelector('.bg-state-success-solid')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should handle both isPending=true and isSuccess=true', () => {
|
||||
@ -619,7 +569,7 @@ describe('PluginMutationModal', () => {
|
||||
expect(
|
||||
screen.queryByRole('button', { name: /Cancel/i }),
|
||||
).not.toBeInTheDocument()
|
||||
expect(screen.getByTestId('ri-check-line')).toBeInTheDocument()
|
||||
expect(document.querySelector('.bg-state-success-solid')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -710,8 +660,8 @@ describe('PluginMutationModal', () => {
|
||||
it('should have displayName set', () => {
|
||||
// The component sets displayName = 'PluginMutationModal'
|
||||
const displayName
|
||||
= (PluginMutationModal as any).type?.displayName
|
||||
|| (PluginMutationModal as any).displayName
|
||||
= (PluginMutationModal as unknown as { type?: { displayName?: string }, displayName?: string }).type?.displayName
|
||||
|| (PluginMutationModal as unknown as { displayName?: string }).displayName
|
||||
expect(displayName).toBe('PluginMutationModal')
|
||||
})
|
||||
|
||||
@ -901,8 +851,7 @@ describe('PluginMutationModal', () => {
|
||||
|
||||
render(<PluginMutationModal {...props} />)
|
||||
|
||||
// Close icon should be present
|
||||
expect(screen.getByTestId('ri-close-line')).toBeInTheDocument()
|
||||
expect(screen.getByRole('dialog')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -1118,8 +1067,7 @@ describe('PluginMutationModal', () => {
|
||||
/>,
|
||||
)
|
||||
|
||||
// Should show success state
|
||||
expect(screen.getByTestId('ri-check-line')).toBeInTheDocument()
|
||||
expect(document.querySelector('.bg-state-success-solid')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should handle plugin prop changes', () => {
|
||||
Reference in New Issue
Block a user