import type { ReactElement } from 'react' import { fireEvent, screen } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vite-plus/test' import { renderWithConsoleQuery } from '@/test/console/query-data' import InstallPluginDropdown from '../install-plugin-dropdown' const { mockSystemFeatures } = vi.hoisted(() => ({ mockSystemFeatures: { enable_marketplace: true, plugin_installation_permission: { restrict_to_marketplace_only: false, }, }, })) vi.mock('@/config', async (importOriginal) => { const actual = await importOriginal() return { ...actual, SUPPORT_INSTALL_LOCAL_FILE_EXTENSIONS: '.difypkg,.zip', } }) const render = (ui: ReactElement) => renderWithConsoleQuery(ui, { systemFeatures: mockSystemFeatures }) vi.mock('@/app/components/base/icons/src/vender/solid/files', () => ({ FileZip: () => file, })) vi.mock('@/app/components/base/icons/src/vender/solid/general', () => ({ Github: () => github, })) vi.mock('@/app/components/base/icons/src/vender/solid/mediaAndDevices', () => ({ MagicBox: () => magic, })) vi.mock('@remixicon/react', () => ({ RiAddCircleFill: ({ className }: { className?: string }) => ( ), RiArrowDownSLine: ({ className }: { className?: string }) => ( ), })) vi.mock('@/app/components/plugins/install-plugin/install-from-github', () => ({ default: ({ onClose }: { onClose: () => void }) => (
), })) vi.mock('@/app/components/plugins/install-plugin/install-from-local-package', () => ({ default: ({ file, onClose }: { file: File; onClose: () => void }) => (
{file.name}
), })) const getTrigger = (name = 'plugin.installPlugin') => screen.getByRole('button', { name }) describe('InstallPluginDropdown', () => { beforeEach(() => { vi.clearAllMocks() mockSystemFeatures.enable_marketplace = true mockSystemFeatures.plugin_installation_permission.restrict_to_marketplace_only = false }) it('shows all install methods when marketplace and custom installs are enabled', () => { render() fireEvent.click(getTrigger()) expect(screen.getByText('plugin.installFrom')).toBeInTheDocument() expect(screen.getByText('plugin.source.marketplace')).toBeInTheDocument() expect(screen.getByText('plugin.source.github')).toBeInTheDocument() expect(screen.getByText('plugin.source.local')).toBeInTheDocument() }) it('applies custom trigger label and presentation props', () => { const { container } = render( , ) const trigger = getTrigger('Install') expect(container.querySelector('.custom-root')).toBeInTheDocument() expect(trigger).toHaveTextContent('Install') expect(screen.getByTestId('add-circle-fill-icon')).toBeInTheDocument() expect(screen.getByTestId('arrow-down-icon')).toBeInTheDocument() expect(trigger).toHaveClass('custom-trigger') expect(trigger).not.toHaveAttribute('data-popup-open') fireEvent.click(trigger) expect(trigger).toHaveClass('custom-open') expect(trigger).toHaveAttribute('data-popup-open', '') expect(screen.getByRole('menu')).toHaveClass('custom-popup') }) it('can hide the trigger arrow for compact integrations placement', () => { render( , ) const trigger = getTrigger('Install') expect(trigger).toHaveTextContent('Install') expect(screen.getByTestId('add-circle-fill-icon')).toBeInTheDocument() expect(screen.queryByTestId('arrow-down-icon')).not.toBeInTheDocument() }) it('keeps the trigger visible but disabled when install is unavailable', () => { const onSwitchToMarketplaceTab = vi.fn() const { container } = render( , ) const trigger = getTrigger() expect(trigger).toBeDisabled() fireEvent.click(trigger) fireEvent.change(container.querySelector('input[type="file"]')!, { target: { files: [new File(['content'], 'plugin.difypkg')], }, }) expect(screen.queryByRole('menu')).not.toBeInTheDocument() expect(screen.queryByTestId('local-modal')).not.toBeInTheDocument() expect(onSwitchToMarketplaceTab).not.toHaveBeenCalled() }) it('shows only marketplace when installation is restricted', () => { mockSystemFeatures.plugin_installation_permission.restrict_to_marketplace_only = true render() fireEvent.click(getTrigger()) expect(screen.getByText('plugin.source.marketplace')).toBeInTheDocument() expect(screen.queryByText('plugin.source.github')).not.toBeInTheDocument() expect(screen.queryByText('plugin.source.local')).not.toBeInTheDocument() }) it('switches to marketplace when the marketplace action is selected', () => { const onSwitchToMarketplaceTab = vi.fn() render() fireEvent.click(getTrigger()) fireEvent.click(screen.getByText('plugin.source.marketplace')) expect(onSwitchToMarketplaceTab).toHaveBeenCalledTimes(1) }) it('opens the github installer when github is selected', async () => { render() fireEvent.click(getTrigger()) fireEvent.click(screen.getByText('plugin.source.github')) expect(await screen.findByTestId('github-modal')).toBeInTheDocument() }) it('opens the local package installer when a file is selected', () => { const { container } = render() fireEvent.click(getTrigger()) fireEvent.click(screen.getByText('plugin.source.local')) fireEvent.change(container.querySelector('input[type="file"]')!, { target: { files: [new File(['content'], 'plugin.difypkg')], }, }) expect(screen.getByTestId('local-modal')).toBeInTheDocument() expect(screen.getByText('plugin.difypkg')).toBeInTheDocument() }) it('triggers the hidden file input when local is selected from the menu', () => { const clickSpy = vi.spyOn(HTMLInputElement.prototype, 'click') render() fireEvent.click(getTrigger()) fireEvent.click(screen.getByText('plugin.source.local')) expect(clickSpy).toHaveBeenCalledTimes(1) clickSpy.mockRestore() }) it('closes the github installer when the modal requests close', async () => { render() fireEvent.click(getTrigger()) fireEvent.click(screen.getByText('plugin.source.github')) fireEvent.click(await screen.findByTestId('close-github-modal')) expect(screen.queryByTestId('github-modal')).not.toBeInTheDocument() }) it('closes the local package installer when the modal requests close', () => { const { container } = render() fireEvent.click(getTrigger()) fireEvent.click(screen.getByText('plugin.source.local')) fireEvent.change(container.querySelector('input[type="file"]')!, { target: { files: [new File(['content'], 'plugin.difypkg')], }, }) fireEvent.click(screen.getByTestId('close-local-modal')) expect(screen.queryByTestId('local-modal')).not.toBeInTheDocument() }) })