import { describe, it, expect, vi, beforeEach } from "vitest"; import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import { MemoryRouter } from "react-router-dom"; import { invoke } from "@tauri-apps/api/core"; import { KubernetesPage } from "@/pages/Kubernetes/KubernetesPage"; import { useKubernetesStore } from "@/stores/kubernetesStore"; // Mock all Kubernetes child components that do their own invoke calls or have heavy deps vi.mock("@/components/Kubernetes/ClusterOverview", () => ({ ClusterOverview: ({ clusterId }: { clusterId: string }) => (
ClusterOverview:{clusterId}
), })); vi.mock("@/components/Kubernetes/PodList", () => ({ PodList: () =>
PodList
, })); vi.mock("@/components/Kubernetes/DeploymentList", () => ({ DeploymentList: () =>
DeploymentList
, })); vi.mock("@/components/Kubernetes/DaemonSetList", () => ({ DaemonSetList: () =>
DaemonSetList
, })); vi.mock("@/components/Kubernetes/StatefulSetList", () => ({ StatefulSetList: () =>
StatefulSetList
, })); vi.mock("@/components/Kubernetes/ReplicaSetList", () => ({ ReplicaSetList: () =>
ReplicaSetList
, })); vi.mock("@/components/Kubernetes/JobList", () => ({ JobList: () =>
JobList
, })); vi.mock("@/components/Kubernetes/CronJobList", () => ({ CronJobList: () =>
CronJobList
, })); vi.mock("@/components/Kubernetes/ServiceList", () => ({ ServiceList: () =>
ServiceList
, })); vi.mock("@/components/Kubernetes/IngressList", () => ({ IngressList: () =>
IngressList
, })); vi.mock("@/components/Kubernetes/ConfigMapList", () => ({ ConfigMapList: () =>
ConfigMapList
, })); vi.mock("@/components/Kubernetes/SecretList", () => ({ SecretList: () =>
SecretList
, })); vi.mock("@/components/Kubernetes/HPAList", () => ({ HPAList: () =>
HPAList
, })); vi.mock("@/components/Kubernetes/PVCList", () => ({ PVCList: () =>
PVCList
, })); vi.mock("@/components/Kubernetes/PVList", () => ({ PVList: () =>
PVList
, })); vi.mock("@/components/Kubernetes/ServiceAccountList", () => ({ ServiceAccountList: () =>
ServiceAccountList
, })); vi.mock("@/components/Kubernetes/RoleList", () => ({ RoleList: () =>
RoleList
, })); vi.mock("@/components/Kubernetes/ClusterRoleList", () => ({ ClusterRoleList: () =>
ClusterRoleList
, })); vi.mock("@/components/Kubernetes/RoleBindingList", () => ({ RoleBindingList: () =>
RoleBindingList
, })); vi.mock("@/components/Kubernetes/ClusterRoleBindingList", () => ({ ClusterRoleBindingList: () =>
ClusterRoleBindingList
, })); vi.mock("@/components/Kubernetes/NodeList", () => ({ NodeList: () =>
NodeList
, })); vi.mock("@/components/Kubernetes/EventList", () => ({ EventList: () =>
EventList
, })); vi.mock("@/components/Kubernetes/PortForwardList", () => ({ PortForwardList: ({ onStart }: { onStart: () => void }) => (
), })); vi.mock("@/components/Kubernetes/PortForwardForm", () => ({ PortForwardForm: ({ isOpen }: { isOpen: boolean }) => isOpen ?
PortForwardForm
: null, })); vi.mock("@/components/Kubernetes/CommandPalette", () => ({ CommandPalette: ({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) => isOpen ? (
CommandPalette
) : null, })); vi.mock("@/components/Kubernetes/Hotbar", () => ({ Hotbar: ({ onRefresh }: { onRefresh: () => void }) => (
), })); type MockedInvoke = ReturnType; const mockInvoke = invoke as unknown as MockedInvoke; const MOCK_KUBECONFIGS = [ { id: "kc-1", name: "prod-cluster", context: "prod", cluster_url: "https://k8s.prod.example.com", is_active: true }, { id: "kc-2", name: "staging-cluster", context: "staging", cluster_url: "https://k8s.staging.example.com", is_active: false }, ]; const MOCK_NAMESPACES = [ { name: "default", status: "Active", age: "100d" }, { name: "kube-system", status: "Active", age: "100d" }, ]; function renderPage() { return render( ); } describe("KubernetesPage", () => { beforeEach(() => { vi.clearAllMocks(); // Reset the kubernetes store to a clean state useKubernetesStore.setState({ selectedClusterId: null, selectedNamespace: "all", }); // Default: return empty arrays for all IPC calls unless overridden mockInvoke.mockImplementation((cmd: string) => { if (cmd === "list_kubeconfigs") return Promise.resolve([]); if (cmd === "list_namespaces") return Promise.resolve([]); if (cmd === "list_port_forwards") return Promise.resolve([]); return Promise.resolve([]); }); }); describe("Sidebar structure", () => { it("renders all resource category section headings", async () => { renderPage(); await waitFor(() => { expect(screen.getByText("Workloads")).toBeInTheDocument(); expect(screen.getByText("Services & Networking")).toBeInTheDocument(); expect(screen.getByText("Config & Storage")).toBeInTheDocument(); expect(screen.getByText("Access Control")).toBeInTheDocument(); expect(screen.getByText("Cluster")).toBeInTheDocument(); }); }); it("renders all Workloads nav items", async () => { renderPage(); await waitFor(() => { expect(screen.getByRole("button", { name: "Pods" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Deployments" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Daemon Sets" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Stateful Sets" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Replica Sets" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Jobs" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Cron Jobs" })).toBeInTheDocument(); }); }); it("renders all Services & Networking nav items", async () => { renderPage(); await waitFor(() => { expect(screen.getByRole("button", { name: "Services" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Ingresses" })).toBeInTheDocument(); }); }); it("renders all Config & Storage nav items", async () => { renderPage(); await waitFor(() => { expect(screen.getByRole("button", { name: "Config Maps" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Secrets" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Horizontal Pod Autoscalers" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Persistent Volume Claims" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Persistent Volumes" })).toBeInTheDocument(); }); }); it("renders all Access Control nav items", async () => { renderPage(); await waitFor(() => { expect(screen.getByRole("button", { name: "Service Accounts" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Roles" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Cluster Roles" })).toBeInTheDocument(); // Use exact aria-label to disambiguate from "Cluster Role Bindings" expect(screen.getByRole("button", { name: "Role Bindings" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Cluster Role Bindings" })).toBeInTheDocument(); }); }); it("renders Port Forwarding under Cluster section", async () => { renderPage(); await waitFor(() => { expect(screen.getByRole("button", { name: "Port Forwarding" })).toBeInTheDocument(); }); }); }); describe("Cluster selector", () => { it("renders a cluster selector trigger button", async () => { renderPage(); // The SelectTrigger renders as a