146 lines
4.2 KiB
TypeScript
146 lines
4.2 KiB
TypeScript
import { render, screen, act } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { vi } from 'vitest';
|
|
|
|
import { terminalClose } from '@/portainer/services/terminal-window';
|
|
|
|
import { Terminal } from '@@/Terminal/Terminal';
|
|
import type { ShellState } from '@@/Terminal/Terminal';
|
|
|
|
import { KubectlShellView } from './KubectlShellView';
|
|
|
|
vi.mock('@@/Terminal/Terminal', () => ({
|
|
Terminal: vi.fn(() => null),
|
|
LINUX_SHELL_INIT_COMMANDS: [],
|
|
}));
|
|
|
|
vi.mock('@/react/hooks/useEnvironmentId', () => ({
|
|
useEnvironmentId: () => 1,
|
|
}));
|
|
|
|
vi.mock('@/portainer/helpers/pathHelper', () => ({
|
|
baseHref: vi.fn().mockReturnValue('/portainer/'),
|
|
}));
|
|
|
|
vi.mock('@/portainer/services/terminal-window', () => ({
|
|
terminalClose: vi.fn(),
|
|
}));
|
|
|
|
function getTerminalProps() {
|
|
return vi.mocked(Terminal).mock.calls[0][0] as {
|
|
url: string;
|
|
connect: boolean;
|
|
onStateChange?: (state: ShellState) => void;
|
|
};
|
|
}
|
|
|
|
function triggerStateChange(state: ShellState) {
|
|
act(() => {
|
|
getTerminalProps().onStateChange?.(state);
|
|
});
|
|
}
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
Object.defineProperty(window, 'location', {
|
|
value: { protocol: 'https:', host: 'localhost:3000' },
|
|
writable: true,
|
|
});
|
|
});
|
|
|
|
describe('KubectlShellView', () => {
|
|
describe('URL construction', () => {
|
|
it('builds wss:// URL when location is https', () => {
|
|
render(<KubectlShellView />);
|
|
expect(getTerminalProps().url).toBe(
|
|
'wss://localhost:3000/portainer/api/websocket/kubernetes-shell?endpointId=1'
|
|
);
|
|
});
|
|
|
|
it('builds ws:// URL when location is http', () => {
|
|
Object.defineProperty(window, 'location', {
|
|
value: { protocol: 'http:', host: 'localhost:3000' },
|
|
writable: true,
|
|
});
|
|
render(<KubectlShellView />);
|
|
expect(getTerminalProps().url).toBe(
|
|
'ws://localhost:3000/portainer/api/websocket/kubernetes-shell?endpointId=1'
|
|
);
|
|
});
|
|
|
|
it('passes connect=true to Terminal', () => {
|
|
render(<KubectlShellView />);
|
|
expect(getTerminalProps().connect).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('shell state', () => {
|
|
it('shows loading indicator when connecting', () => {
|
|
render(<KubectlShellView />);
|
|
triggerStateChange('connecting');
|
|
expect(screen.getByText('Loading Terminal...')).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows disconnected panel when disconnected', () => {
|
|
render(<KubectlShellView />);
|
|
triggerStateChange('disconnected');
|
|
expect(screen.getByText('Console disconnected')).toBeInTheDocument();
|
|
});
|
|
|
|
it('calls terminalClose when state becomes disconnected', () => {
|
|
render(<KubectlShellView />);
|
|
triggerStateChange('disconnected');
|
|
expect(vi.mocked(terminalClose)).toHaveBeenCalled();
|
|
});
|
|
|
|
it('shows nothing initially (idle state)', () => {
|
|
render(<KubectlShellView />);
|
|
expect(screen.queryByText('Loading Terminal...')).not.toBeInTheDocument();
|
|
expect(
|
|
screen.queryByText('Console disconnected')
|
|
).not.toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('disconnected buttons', () => {
|
|
beforeEach(() => {
|
|
render(<KubectlShellView />);
|
|
triggerStateChange('disconnected');
|
|
});
|
|
|
|
it('renders Reload button', () => {
|
|
expect(screen.getByTestId('k8sShell-reloadButton')).toHaveTextContent(
|
|
'Reload'
|
|
);
|
|
});
|
|
|
|
it('renders Close button', () => {
|
|
expect(screen.getByTestId('k8sShell-closeButton')).toHaveTextContent(
|
|
'Close'
|
|
);
|
|
});
|
|
|
|
it('reloads page when Reload is clicked', async () => {
|
|
const user = userEvent.setup();
|
|
const mockReload = vi.fn();
|
|
Object.defineProperty(window, 'location', {
|
|
value: { ...window.location, reload: mockReload },
|
|
writable: true,
|
|
});
|
|
await user.click(screen.getByTestId('k8sShell-reloadButton'));
|
|
expect(mockReload).toHaveBeenCalled();
|
|
});
|
|
|
|
it('closes window when Close is clicked', async () => {
|
|
const user = userEvent.setup();
|
|
const mockClose = vi.fn();
|
|
Object.defineProperty(window, 'close', {
|
|
value: mockClose,
|
|
writable: true,
|
|
});
|
|
await user.click(screen.getByTestId('k8sShell-closeButton'));
|
|
expect(mockClose).toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|