Files
dify/web/app/components/header/account-setting/data-source-page-new/install-from-marketplace.spec.tsx
2026-02-23 13:00:02 +08:00

178 lines
5.6 KiB
TypeScript

import type { DataSourceAuth } from './types'
import type { Plugin } from '@/app/components/plugins/types'
import { fireEvent, render, screen } from '@testing-library/react'
import { useTheme } from 'next-themes'
import { PluginCategoryEnum } from '@/app/components/plugins/types'
import { useMarketplaceAllPlugins } from './hooks'
import InstallFromMarketplace from './install-from-marketplace'
/**
* InstallFromMarketplace Component Tests
* Using Unit approach to focus on the component's internal state and conditional rendering.
*/
// Mock external dependencies
vi.mock('next-themes', () => ({
useTheme: vi.fn(),
}))
vi.mock('next/link', () => ({
default: ({ children, href }: { children: React.ReactNode, href: string }) => (
<a href={href} data-testid="mock-link">{children}</a>
),
}))
vi.mock('@/utils/var', () => ({
getMarketplaceUrl: vi.fn((path: string, { theme }: { theme: string }) => `https://marketplace.url${path}?theme=${theme}`),
}))
// Mock marketplace components
vi.mock('@/app/components/plugins/marketplace/list', () => ({
default: ({ plugins, cardRender, cardContainerClassName, emptyClassName }: {
plugins: Plugin[]
cardRender: (p: Plugin) => React.ReactNode
cardContainerClassName?: string
emptyClassName?: string
}) => (
<div data-testid="mock-list" className={cardContainerClassName}>
{plugins.length === 0 && <div className={emptyClassName} aria-label="empty-state" />}
{plugins.map(plugin => (
<div key={plugin.plugin_id} data-testid={`list-item-${plugin.plugin_id}`}>
{cardRender(plugin)}
</div>
))}
</div>
),
}))
vi.mock('@/app/components/plugins/provider-card', () => ({
default: ({ payload }: { payload: Plugin }) => (
<div data-testid={`mock-provider-card-${payload.plugin_id}`}>
{payload.name}
</div>
),
}))
vi.mock('./hooks', () => ({
useMarketplaceAllPlugins: vi.fn(),
}))
describe('InstallFromMarketplace Component', () => {
const mockProviders: DataSourceAuth[] = [
{
author: 'Author',
provider: 'provider',
plugin_id: 'p1',
plugin_unique_identifier: 'u1',
icon: 'icon',
name: 'name',
label: { en_US: 'Label', zh_Hans: '标签' },
description: { en_US: 'Desc', zh_Hans: '描述' },
credentials_list: [],
},
]
const mockPlugins: Plugin[] = [
{
type: 'plugin',
plugin_id: 'plugin-1',
name: 'Plugin 1',
category: PluginCategoryEnum.datasource,
// ...other minimal fields
} as Plugin,
{
type: 'bundle',
plugin_id: 'bundle-1',
name: 'Bundle 1',
category: PluginCategoryEnum.datasource,
} as Plugin,
]
beforeEach(() => {
vi.clearAllMocks()
vi.mocked(useTheme).mockReturnValue({
theme: 'light',
setTheme: vi.fn(),
themes: ['light', 'dark'],
systemTheme: 'light',
resolvedTheme: 'light',
} as unknown as ReturnType<typeof useTheme>)
})
describe('Rendering', () => {
it('should render correctly when not loading and not collapsed', () => {
// Arrange
vi.mocked(useMarketplaceAllPlugins).mockReturnValue({
plugins: mockPlugins,
isLoading: false,
})
// Act
render(<InstallFromMarketplace providers={mockProviders} searchText="" />)
// Assert
expect(screen.getByText('common.modelProvider.installDataSourceProvider')).toBeInTheDocument()
expect(screen.getByText('common.modelProvider.discoverMore')).toBeInTheDocument()
expect(screen.getByTestId('mock-link')).toHaveAttribute('href', 'https://marketplace.url?theme=light')
expect(screen.getByTestId('mock-list')).toBeInTheDocument()
expect(screen.getByTestId('mock-provider-card-plugin-1')).toBeInTheDocument()
expect(screen.queryByTestId('mock-provider-card-bundle-1')).not.toBeInTheDocument()
expect(screen.queryByRole('status')).not.toBeInTheDocument()
})
it('should show loading state when marketplace plugins are loading and component is not collapsed', () => {
// Arrange
vi.mocked(useMarketplaceAllPlugins).mockReturnValue({
plugins: [],
isLoading: true,
})
// Act
render(<InstallFromMarketplace providers={mockProviders} searchText="" />)
// Assert
expect(screen.getByRole('status')).toBeInTheDocument()
expect(screen.queryByTestId('mock-list')).not.toBeInTheDocument()
})
})
describe('Interactions', () => {
it('should toggle collapse state when clicking the header', () => {
// Arrange
vi.mocked(useMarketplaceAllPlugins).mockReturnValue({
plugins: mockPlugins,
isLoading: false,
})
render(<InstallFromMarketplace providers={mockProviders} searchText="" />)
const toggleHeader = screen.getByText('common.modelProvider.installDataSourceProvider')
// Act (Collapse)
fireEvent.click(toggleHeader)
// Assert
expect(screen.queryByTestId('mock-list')).not.toBeInTheDocument()
// Act (Expand)
fireEvent.click(toggleHeader)
// Assert
expect(screen.getByTestId('mock-list')).toBeInTheDocument()
})
it('should not show loading state even if isLoading is true when component is collapsed', () => {
// Arrange
vi.mocked(useMarketplaceAllPlugins).mockReturnValue({
plugins: [],
isLoading: true,
})
render(<InstallFromMarketplace providers={mockProviders} searchText="" />)
const toggleHeader = screen.getByText('common.modelProvider.installDataSourceProvider')
// Act (Collapse)
fireEvent.click(toggleHeader)
// Assert
expect(screen.queryByRole('status')).not.toBeInTheDocument()
})
})
})