mirror of
https://github.com/langgenius/dify.git
synced 2026-05-03 17:08:03 +08:00
test(web): add comprehensive unit and integration tests for plugins and tools modules (#32220)
Co-authored-by: CodingOnStar <hanxujiang@dify.com>
This commit is contained in:
@ -0,0 +1,92 @@
|
||||
import { cleanup, render, screen } from '@testing-library/react'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import DeprecationNotice from '../deprecation-notice'
|
||||
|
||||
vi.mock('next/link', () => ({
|
||||
default: ({ children, href }: { children: React.ReactNode, href: string }) => (
|
||||
<a data-testid="link" href={href}>{children}</a>
|
||||
),
|
||||
}))
|
||||
|
||||
describe('DeprecationNotice', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
cleanup()
|
||||
})
|
||||
|
||||
it('returns null when status is not "deleted"', () => {
|
||||
const { container } = render(
|
||||
<DeprecationNotice
|
||||
status="active"
|
||||
deprecatedReason="business_adjustments"
|
||||
alternativePluginId="alt-plugin"
|
||||
alternativePluginURL="/plugins/alt-plugin"
|
||||
/>,
|
||||
)
|
||||
expect(container.firstChild).toBeNull()
|
||||
})
|
||||
|
||||
it('renders deprecation notice when status is "deleted"', () => {
|
||||
render(
|
||||
<DeprecationNotice
|
||||
status="deleted"
|
||||
deprecatedReason=""
|
||||
alternativePluginId=""
|
||||
alternativePluginURL=""
|
||||
/>,
|
||||
)
|
||||
expect(screen.getByText('plugin.detailPanel.deprecation.noReason')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders with valid reason and alternative plugin', () => {
|
||||
render(
|
||||
<DeprecationNotice
|
||||
status="deleted"
|
||||
deprecatedReason="business_adjustments"
|
||||
alternativePluginId="better-plugin"
|
||||
alternativePluginURL="/plugins/better-plugin"
|
||||
/>,
|
||||
)
|
||||
expect(screen.getByText('detailPanel.deprecation.fullMessage')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders only reason without alternative plugin', () => {
|
||||
render(
|
||||
<DeprecationNotice
|
||||
status="deleted"
|
||||
deprecatedReason="no_maintainer"
|
||||
alternativePluginId=""
|
||||
alternativePluginURL=""
|
||||
/>,
|
||||
)
|
||||
expect(screen.getByText(/plugin\.detailPanel\.deprecation\.onlyReason/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders no-reason message for invalid reason', () => {
|
||||
render(
|
||||
<DeprecationNotice
|
||||
status="deleted"
|
||||
deprecatedReason="unknown_reason"
|
||||
alternativePluginId=""
|
||||
alternativePluginURL=""
|
||||
/>,
|
||||
)
|
||||
expect(screen.getByText('plugin.detailPanel.deprecation.noReason')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('applies custom className', () => {
|
||||
const { container } = render(
|
||||
<DeprecationNotice
|
||||
status="deleted"
|
||||
deprecatedReason=""
|
||||
alternativePluginId=""
|
||||
alternativePluginURL=""
|
||||
className="my-custom-class"
|
||||
/>,
|
||||
)
|
||||
expect((container.firstChild as HTMLElement).className).toContain('my-custom-class')
|
||||
})
|
||||
})
|
||||
@ -0,0 +1,59 @@
|
||||
import { cleanup, fireEvent, render, screen } from '@testing-library/react'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import KeyValueItem from '../key-value-item'
|
||||
|
||||
vi.mock('../../../base/icons/src/vender/line/files', () => ({
|
||||
CopyCheck: () => <span data-testid="copy-check-icon" />,
|
||||
}))
|
||||
|
||||
vi.mock('../../../base/tooltip', () => ({
|
||||
default: ({ children, popupContent }: { children: React.ReactNode, popupContent: string }) => (
|
||||
<div data-testid="tooltip" data-content={popupContent}>{children}</div>
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/action-button', () => ({
|
||||
default: ({ children, onClick }: { children: React.ReactNode, onClick: () => void }) => (
|
||||
<button data-testid="action-button" onClick={onClick}>{children}</button>
|
||||
),
|
||||
}))
|
||||
|
||||
const mockCopy = vi.fn()
|
||||
vi.mock('copy-to-clipboard', () => ({
|
||||
default: (...args: unknown[]) => mockCopy(...args),
|
||||
}))
|
||||
|
||||
describe('KeyValueItem', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
vi.useFakeTimers()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers()
|
||||
cleanup()
|
||||
})
|
||||
|
||||
it('renders label and value', () => {
|
||||
render(<KeyValueItem label="ID" value="abc-123" />)
|
||||
expect(screen.getByText('ID')).toBeInTheDocument()
|
||||
expect(screen.getByText('abc-123')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders maskedValue instead of value when provided', () => {
|
||||
render(<KeyValueItem label="Key" value="sk-secret" maskedValue="sk-***" />)
|
||||
expect(screen.getByText('sk-***')).toBeInTheDocument()
|
||||
expect(screen.queryByText('sk-secret')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('copies actual value (not masked) when copy button is clicked', () => {
|
||||
render(<KeyValueItem label="Key" value="sk-secret" maskedValue="sk-***" />)
|
||||
fireEvent.click(screen.getByTestId('action-button'))
|
||||
expect(mockCopy).toHaveBeenCalledWith('sk-secret')
|
||||
})
|
||||
|
||||
it('renders copy tooltip', () => {
|
||||
render(<KeyValueItem label="ID" value="123" />)
|
||||
expect(screen.getByTestId('tooltip')).toHaveAttribute('data-content', 'common.operation.copy')
|
||||
})
|
||||
})
|
||||
@ -1,7 +1,7 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { Theme } from '@/types/app'
|
||||
import IconWithTooltip from './icon-with-tooltip'
|
||||
import IconWithTooltip from '../icon-with-tooltip'
|
||||
|
||||
// Mock Tooltip component
|
||||
vi.mock('@/app/components/base/tooltip', () => ({
|
||||
@ -2,7 +2,7 @@ import type { ComponentProps } from 'react'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { Theme } from '@/types/app'
|
||||
import Partner from './partner'
|
||||
import Partner from '../partner'
|
||||
|
||||
// Mock useTheme hook
|
||||
const mockUseTheme = vi.fn()
|
||||
@ -11,9 +11,9 @@ vi.mock('@/hooks/use-theme', () => ({
|
||||
}))
|
||||
|
||||
// Mock IconWithTooltip to directly test Partner's behavior
|
||||
type IconWithTooltipProps = ComponentProps<typeof import('./icon-with-tooltip').default>
|
||||
type IconWithTooltipProps = ComponentProps<typeof import('../icon-with-tooltip').default>
|
||||
const mockIconWithTooltip = vi.fn()
|
||||
vi.mock('./icon-with-tooltip', () => ({
|
||||
vi.mock('../icon-with-tooltip', () => ({
|
||||
default: (props: IconWithTooltipProps) => {
|
||||
mockIconWithTooltip(props)
|
||||
const { theme, BadgeIconLight, BadgeIconDark, className, popupContent } = props
|
||||
@ -0,0 +1,52 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import * as React from 'react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
vi.mock('@/app/components/base/icons/src/public/plugins/VerifiedDark', () => ({
|
||||
default: () => <span data-testid="verified-dark" />,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/icons/src/public/plugins/VerifiedLight', () => ({
|
||||
default: () => <span data-testid="verified-light" />,
|
||||
}))
|
||||
|
||||
vi.mock('@/hooks/use-theme', () => ({
|
||||
default: () => ({ theme: 'light' }),
|
||||
}))
|
||||
|
||||
vi.mock('../icon-with-tooltip', () => ({
|
||||
default: ({ popupContent, BadgeIconLight, BadgeIconDark, theme }: {
|
||||
popupContent: string
|
||||
BadgeIconLight: React.FC
|
||||
BadgeIconDark: React.FC
|
||||
theme: string
|
||||
[key: string]: unknown
|
||||
}) => (
|
||||
<div data-testid="icon-with-tooltip" data-popup={popupContent}>
|
||||
{theme === 'light' ? <BadgeIconLight /> : <BadgeIconDark />}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
describe('Verified', () => {
|
||||
let Verified: (typeof import('../verified'))['default']
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks()
|
||||
const mod = await import('../verified')
|
||||
Verified = mod.default
|
||||
})
|
||||
|
||||
it('should render with tooltip text', () => {
|
||||
render(<Verified text="Verified Plugin" />)
|
||||
|
||||
const tooltip = screen.getByTestId('icon-with-tooltip')
|
||||
expect(tooltip).toHaveAttribute('data-popup', 'Verified Plugin')
|
||||
})
|
||||
|
||||
it('should render light theme icon by default', () => {
|
||||
render(<Verified text="Verified" />)
|
||||
|
||||
expect(screen.getByTestId('verified-light')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user