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: () =>
logs
,
}));
vi.mock("@/components/dock/TerminalTab", () => ({
TerminalTab: () => terminal
,
}));
vi.mock("@/components/dock/YamlEditorTab", () => ({
YamlEditorTab: () => yaml
,
}));
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();
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();
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();
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();
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();
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();
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();
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();
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();
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();
fireEvent.keyDown(window, { key: ",", ctrlKey: true });
expect(useBottomPanelStore.getState().activeTabId).not.toBe(b);
});
it("ignores shortcuts when panel is closed", () => {
render();
// Should not throw
fireEvent.keyDown(window, { key: "w", ctrlKey: true });
fireEvent.keyDown(window, { key: ".", ctrlKey: true });
expect(useBottomPanelStore.getState().tabs).toHaveLength(0);
});
});