1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-30 02:39:41 +02:00
portainer/app/react/sidebar/KubernetesSidebar/KubectlShellButton.test.tsx

127 lines
3.7 KiB
TypeScript

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 <Context.Provider value={state}>{children}</Context.Provider>;
}
function renderComponent(environmentId = 1, isSidebarOpen = true) {
return render(
<MockSidebarProvider isOpen={isSidebarOpen}>
<KubectlShellButton environmentId={environmentId} />
</MockSidebarProvider>
);
}
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);
});
});