tftsr-devops_investigation/tests/unit/BottomPanel.test.tsx
Shaun Arman f7b4e591f9 fix(performance): resolve memory leaks and add polish features
- Fix LogStreamPanel event listener cleanup with synchronous unlisten
- Fix eventBus async-unsafe unsubscribe with proper error handling
- Fix KubernetesPage infinite loading by resetting state on section change
- Add ErrorBoundary component with reset capability
- Add Badge component with multiple variants
- Add ResourceDetailsDrawer for slide-out details panel
- Add useFavorites hook with localStorage persistence
- Add useKeyboardShortcuts hook for declarative shortcuts
- Add comprehensive test coverage for all new components/hooks
- Add keyboard shortcuts documentation to README
- Wrap KubernetesPage with ErrorBoundary for crash recovery
- Install react-window for virtual scrolling support

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-09 13:28:30 -05:00

157 lines
4.9 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { BottomPanel } from "@/components/BottomPanel";
import {
useBottomPanelStore,
BottomPanelTabType,
DEFAULT_PANEL_HEIGHT,
} from "@/stores/bottomPanelStore";
// Stub the heavier tab content to keep this test focused on the panel chrome.
vi.mock("@/components/dock/LogsTab", () => ({
LogsTab: () => <div data-testid="logs-tab-stub">logs</div>,
}));
vi.mock("@/components/dock/TerminalTab", () => ({
TerminalTab: () => <div data-testid="terminal-tab-stub">terminal</div>,
}));
vi.mock("@/components/dock/YamlEditorTab", () => ({
YamlEditorTab: () => <div data-testid="yaml-tab-stub">yaml</div>,
}));
function resetStore() {
useBottomPanelStore.setState({
isOpen: false,
height: DEFAULT_PANEL_HEIGHT,
tabs: [],
activeTabId: null,
nextTabIndex: 1,
});
}
describe("BottomPanel", () => {
beforeEach(() => {
resetStore();
});
it("renders nothing when closed", () => {
render(<BottomPanel />);
expect(screen.queryByTestId("bottom-panel")).toBeNull();
});
it("renders panel + drag handle when open with a tab", () => {
useBottomPanelStore.getState().openTab({
type: BottomPanelTabType.TERMINAL,
title: "terminal-1",
});
render(<BottomPanel />);
expect(screen.getByTestId("bottom-panel")).toBeInTheDocument();
expect(screen.getByTestId("bottom-panel-drag-handle")).toBeInTheDocument();
});
it("uses height from the store", () => {
useBottomPanelStore.getState().openTab({
type: BottomPanelTabType.TERMINAL,
title: "t",
});
useBottomPanelStore.getState().setHeight(420);
render(<BottomPanel />);
const panel = screen.getByTestId("bottom-panel");
expect(panel).toHaveStyle({ height: "420px" });
});
it("close button removes the active tab", () => {
const id = useBottomPanelStore.getState().openTab({
type: BottomPanelTabType.TERMINAL,
title: "term",
});
render(<BottomPanel />);
const closeBtn = screen.getByLabelText(`Close tab term`);
fireEvent.click(closeBtn);
expect(useBottomPanelStore.getState().tabs.find((t) => t.id === id)).toBeUndefined();
});
it("clicking inactive tab makes it active", () => {
const a = useBottomPanelStore.getState().openTab({
type: BottomPanelTabType.TERMINAL,
title: "alpha",
});
useBottomPanelStore.getState().openTab({
type: BottomPanelTabType.TERMINAL,
title: "beta",
});
render(<BottomPanel />);
fireEvent.click(screen.getByText("alpha"));
expect(useBottomPanelStore.getState().activeTabId).toBe(a);
});
it("collapse-all button closes the panel", () => {
useBottomPanelStore.getState().openTab({
type: BottomPanelTabType.TERMINAL,
title: "term",
});
render(<BottomPanel />);
fireEvent.click(screen.getByLabelText("Hide bottom panel"));
expect(useBottomPanelStore.getState().isOpen).toBe(false);
});
});
describe("BottomPanel keyboard shortcuts", () => {
beforeEach(() => {
resetStore();
});
it("Ctrl+W closes the active tab", () => {
const id = useBottomPanelStore.getState().openTab({
type: BottomPanelTabType.TERMINAL,
title: "term",
});
render(<BottomPanel />);
fireEvent.keyDown(window, { key: "w", ctrlKey: true });
expect(useBottomPanelStore.getState().tabs.find((t) => t.id === id)).toBeUndefined();
});
it("Shift+Escape hides the panel", () => {
useBottomPanelStore.getState().openTab({
type: BottomPanelTabType.TERMINAL,
title: "term",
});
render(<BottomPanel />);
fireEvent.keyDown(window, { key: "Escape", shiftKey: true });
expect(useBottomPanelStore.getState().isOpen).toBe(false);
});
it("Ctrl+. switches to next tab", () => {
const a = useBottomPanelStore.getState().openTab({ type: BottomPanelTabType.TERMINAL, title: "a" });
const b = useBottomPanelStore.getState().openTab({ type: BottomPanelTabType.TERMINAL, title: "b" });
useBottomPanelStore.getState().setActiveTab(a);
render(<BottomPanel />);
fireEvent.keyDown(window, { key: ".", ctrlKey: true });
expect(useBottomPanelStore.getState().activeTabId).toBe(b);
});
it("Ctrl+, switches to previous tab", () => {
useBottomPanelStore.getState().openTab({ type: BottomPanelTabType.TERMINAL, title: "a" });
const b = useBottomPanelStore.getState().openTab({ type: BottomPanelTabType.TERMINAL, title: "b" });
useBottomPanelStore.getState().setActiveTab(b);
render(<BottomPanel />);
fireEvent.keyDown(window, { key: ",", ctrlKey: true });
expect(useBottomPanelStore.getState().activeTabId).not.toBe(b);
});
it("ignores shortcuts when panel is closed", () => {
render(<BottomPanel />);
// Should not throw
fireEvent.keyDown(window, { key: "w", ctrlKey: true });
fireEvent.keyDown(window, { key: ".", ctrlKey: true });
expect(useBottomPanelStore.getState().tabs).toHaveLength(0);
});
});