mirror of
https://github.com/portainer/portainer.git
synced 2025-07-30 02:39:41 +02:00
127 lines
3.7 KiB
TypeScript
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);
|
|
});
|
|
});
|