import type { ReactElement } from 'react' import { fireEvent, screen } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' import { renderWithConsoleQuery } from '@/test/console/query-data' import { PluginSource } from '../../types' import { OperationDropdown } from '../operation-dropdown' const render = (ui: ReactElement, enableMarketplace = true) => renderWithConsoleQuery(ui, { systemFeatures: { enable_marketplace: enableMarketplace } }) const openDropdown = () => { fireEvent.click(screen.getByRole('button', { name: 'plugin.detailPanel.operation.moreActions' })) } describe('OperationDropdown', () => { const mockOnInfo = vi.fn() const mockOnCheckVersion = vi.fn() const mockOnRemove = vi.fn() const mockOnViewReadme = vi.fn() const defaultProps = { source: PluginSource.github, detailUrl: 'https://github.com/test/repo', onInfo: mockOnInfo, onCheckVersion: mockOnCheckVersion, onRemove: mockOnRemove, } beforeEach(() => { vi.clearAllMocks() }) describe('Rendering', () => { it('should render the actions trigger', () => { render() expect( screen.getByRole('button', { name: 'plugin.detailPanel.operation.moreActions' }), ).toBeInTheDocument() }) it('should render GitHub actions when marketplace is enabled', () => { render() openDropdown() expect(screen.getByText('plugin.detailPanel.operation.info')).toBeInTheDocument() expect(screen.getByText('plugin.detailPanel.operation.checkUpdate')).toBeInTheDocument() expect(screen.getByText('plugin.detailPanel.operation.viewDetail')).toBeInTheDocument() expect(screen.getByText('plugin.detailPanel.operation.remove')).toBeInTheDocument() }) it('should render marketplace detail action for marketplace source', () => { render() openDropdown() expect(screen.queryByText('plugin.detailPanel.operation.info')).not.toBeInTheDocument() expect(screen.queryByText('plugin.detailPanel.operation.checkUpdate')).not.toBeInTheDocument() expect(screen.getByText('plugin.detailPanel.operation.viewDetail')).toBeInTheDocument() expect(screen.getByText('plugin.detailPanel.operation.remove')).toBeInTheDocument() }) it('should render README action only when provided', () => { const { unmount } = render() openDropdown() expect(screen.queryByText('plugin.detailPanel.operation.viewReadme')).not.toBeInTheDocument() unmount() render() openDropdown() expect(screen.getByText('plugin.detailPanel.operation.viewReadme')).toBeInTheDocument() }) it('should not render marketplace detail when source cannot open a detail page', () => { render() openDropdown() expect(screen.queryByText('plugin.detailPanel.operation.viewDetail')).not.toBeInTheDocument() expect(screen.getByText('plugin.detailPanel.operation.remove')).toBeInTheDocument() }) it('should not render the trigger when every action is unavailable', () => { render( , ) expect( screen.queryByRole('button', { name: 'plugin.detailPanel.operation.moreActions' }), ).not.toBeInTheDocument() }) }) describe('User Interactions', () => { it('should call onInfo when the info action is clicked', () => { render() openDropdown() fireEvent.click(screen.getByText('plugin.detailPanel.operation.info')) expect(mockOnInfo).toHaveBeenCalledTimes(1) }) it('should call onCheckVersion when the check update action is clicked', () => { render() openDropdown() fireEvent.click(screen.getByText('plugin.detailPanel.operation.checkUpdate')) expect(mockOnCheckVersion).toHaveBeenCalledTimes(1) }) it('should call onRemove when the remove action is clicked', () => { render() openDropdown() fireEvent.click(screen.getByText('plugin.detailPanel.operation.remove')) expect(mockOnRemove).toHaveBeenCalledTimes(1) }) it('should call onViewReadme when README action is clicked', () => { render() openDropdown() fireEvent.click(screen.getByText('plugin.detailPanel.operation.viewReadme')) expect(mockOnViewReadme).toHaveBeenCalledTimes(1) }) it('should render view detail as an external link', () => { render() openDropdown() const link = screen.getByText('plugin.detailPanel.operation.viewDetail').closest('a') expect(link).toHaveAttribute('href', 'https://github.com/test/repo') expect(link).toHaveAttribute('target', '_blank') expect(link).toHaveAttribute('rel', 'noopener noreferrer') }) }) describe('Feature Flags', () => { it('should hide marketplace detail when marketplace is disabled', () => { render(, false) openDropdown() expect(screen.queryByText('plugin.detailPanel.operation.viewDetail')).not.toBeInTheDocument() expect(screen.getByText('plugin.detailPanel.operation.info')).toBeInTheDocument() }) }) })