import { render, fireEvent, screen } from '@testing-library/react'; import { vi } from 'vitest'; import { PropsWithChildren, useMemo } from 'react'; import { useAnalytics } from '@/react/hooks/useAnalytics'; import { Context } from '../useSidebarState'; import { KubectlShellButton } from './KubectlShellButton'; vi.mock('@/react/hooks/useAnalytics', () => ({ useAnalytics: vi.fn().mockReturnValue({ trackEvent: vi.fn(), }), })); vi.mock('@/portainer/helpers/pathHelper', () => ({ baseHref: vi.fn().mockReturnValue('/portainer'), })); const mockWindowOpen = vi.fn(); const originalWindowOpen = window.open; beforeEach(() => { window.open = mockWindowOpen; mockWindowOpen.mockClear(); }); afterEach(() => { window.open = originalWindowOpen; }); function MockSidebarProvider({ children, isOpen = true, }: PropsWithChildren<{ isOpen?: boolean }>) { const state = useMemo(() => ({ isOpen, toggle: vi.fn() }), [isOpen]); return {children}; } function renderComponent(environmentId = 1, isSidebarOpen = true) { return render( ); } describe('KubectlShellButton', () => { test('should render button with text when sidebar is open', () => { renderComponent(); const button = screen.getByTestId('k8sSidebar-shellButton'); expect(button).toBeVisible(); expect(button).toHaveTextContent('kubectl shell'); }); test('should render button without text when sidebar is closed', () => { renderComponent(1, false); const button = screen.getByTestId('k8sSidebar-shellButton'); expect(button).toBeVisible(); expect(button).not.toHaveTextContent('kubectl shell'); expect(button).toHaveClass('!p-1'); }); test('should wrap button in tooltip when sidebar is closed', () => { renderComponent(1, false); // When sidebar is closed, the button is wrapped in a span with flex classes const button = screen.getByTestId('k8sSidebar-shellButton'); const wrapperSpan = button.parentElement; expect(wrapperSpan).toHaveClass('flex', 'w-full', 'justify-center'); // The button should have the !p-1 class when sidebar is closed expect(button).toHaveClass('!p-1'); }); test('should open new window with correct URL when button is clicked', () => { const environmentId = 5; renderComponent(environmentId); const button = screen.getByTestId('k8sSidebar-shellButton'); fireEvent.click(button); expect(mockWindowOpen).toHaveBeenCalledTimes(1); const [url, windowName, windowFeatures] = mockWindowOpen.mock.calls[0]; expect(url).toBe( `${window.location.origin}/portainer#!/${environmentId}/kubernetes/kubectl-shell` ); expect(windowName).toMatch(/^kubectl-shell-5-[a-f0-9-]+$/); expect(windowFeatures).toBe('width=800,height=600'); }); test('should track analytics event when button is clicked', () => { const mockTrackEvent = vi.fn(); vi.mocked(useAnalytics).mockReturnValue({ trackEvent: mockTrackEvent }); renderComponent(); const button = screen.getByRole('button'); fireEvent.click(button); expect(mockTrackEvent).toHaveBeenCalledWith('kubernetes-kubectl-shell', { category: 'kubernetes', }); }); test('should generate unique window names for multiple clicks', () => { renderComponent(); const button = screen.getByRole('button'); // Click multiple times fireEvent.click(button); fireEvent.click(button); expect(mockWindowOpen).toHaveBeenCalledTimes(2); const windowName1 = mockWindowOpen.mock.calls[0][1]; const windowName2 = mockWindowOpen.mock.calls[1][1]; expect(windowName1).not.toBe(windowName2); }); });