import type { PluginDeclaration, PluginDetail } from '@/app/components/plugins/types' import { fireEvent, render, screen, waitFor } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' import { PluginCategoryEnum, PluginSource } from '@/app/components/plugins/types' import PluginDetailPanel from '../index' const mockSetDetail = vi.fn() vi.mock('../store', () => ({ usePluginStore: () => ({ setDetail: mockSetDetail }), })) vi.mock('../detail-header', () => ({ default: ({ onUpdate, onHide, }: { onUpdate: (isDelete?: boolean) => void onHide: () => void }) => (
), })) vi.mock('../action-list', () => ({ default: () =>
Actions
})) vi.mock('../agent-strategy-list', () => ({ default: () =>
Agent strategies
})) vi.mock('../endpoint-list', () => ({ default: () =>
Endpoints
})) vi.mock('../model-list', () => ({ default: () =>
Models
})) vi.mock('../datasource-action-list', () => ({ default: () =>
Data sources
})) vi.mock('../subscription-list', () => ({ SubscriptionList: () =>
Subscriptions
, })) vi.mock('../trigger/event-list', () => ({ TriggerEventsList: () =>
Trigger events
, })) vi.mock('../../readme-panel/entrance', () => ({ ReadmeEntrance: () =>
Readme
, })) const createPluginDetail = ( declarationOverrides: Partial = {}, ): PluginDetail => { const declaration = { plugin_unique_identifier: 'test-plugin-uid', version: '1.0.0', author: 'test-author', icon: 'test-icon.png', name: 'test-plugin', category: PluginCategoryEnum.tool, label: { en_US: 'Test Plugin' }, description: { en_US: 'Test plugin description' }, created_at: '2024-01-01T00:00:00Z', resource: null, plugins: null, verified: true, endpoint: undefined, tool: undefined, model: null, tags: [], agent_strategy: null, meta: { version: '1.0.0' }, trigger: null, datasource: null, ...declarationOverrides, } as unknown as PluginDeclaration return { id: 'test-plugin-id', created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-02T00:00:00Z', name: 'Test Plugin', plugin_id: 'test-plugin-id', plugin_unique_identifier: 'test-plugin-uid', declaration, installation_id: 'install-1', tenant_id: 'tenant-1', endpoints_setups: 0, endpoints_active: 0, version: '1.0.0', latest_version: '1.0.0', latest_unique_identifier: 'test-plugin-uid', source: PluginSource.marketplace, meta: undefined, status: 'active', deprecated_reason: '', alternative_plugin_id: '', } } describe('PluginDetailPanel', () => { const onUpdate = vi.fn() const onHide = vi.fn() beforeEach(() => { vi.clearAllMocks() }) it('renders nothing and clears the store when detail is absent', async () => { const { container } = render( , ) expect(container).toBeEmptyDOMElement() await waitFor(() => expect(mockSetDetail).toHaveBeenCalledWith(undefined)) }) it('publishes the detail fields consumed by descendants', async () => { const detail = createPluginDetail() render() await waitFor(() => { expect(mockSetDetail).toHaveBeenCalledWith({ plugin_id: 'test-plugin-id', provider: 'test-plugin-id/test-plugin', plugin_unique_identifier: 'test-plugin-uid', declaration: detail.declaration, name: 'Test Plugin', id: 'test-plugin-id', }) }) }) it.each([ ['tool', { tool: {} }, 'Actions'], ['agent strategy', { agent_strategy: {} }, 'Agent strategies'], ['endpoint', { endpoint: {} }, 'Endpoints'], ['model', { model: {} }, 'Models'], ['data source', { datasource: {} }, 'Data sources'], ] as const)('renders the %s section declared by the plugin', (_, declaration, section) => { render( )} onUpdate={onUpdate} onHide={onHide} />, ) expect(screen.getByText(section)).toBeInTheDocument() expect(screen.getByText('Readme')).toBeInTheDocument() }) it('renders subscription and event sections for trigger plugins', () => { render( , ) expect(screen.getByText('Subscriptions')).toBeInTheDocument() expect(screen.getByText('Trigger events')).toBeInTheDocument() }) it('updates without closing the panel', () => { render() fireEvent.click(screen.getByRole('button', { name: 'Update' })) expect(onUpdate).toHaveBeenCalledOnce() expect(onHide).not.toHaveBeenCalled() }) it('closes before notifying consumers when the plugin is deleted', () => { render() fireEvent.click(screen.getByRole('button', { name: 'Delete' })) expect(onHide).toHaveBeenCalledOnce() expect(onUpdate).toHaveBeenCalledOnce() expect(onHide.mock.invocationCallOrder[0]!).toBeLessThan(onUpdate.mock.invocationCallOrder[0]!) }) })