import React from "react"; import { describe, it, expect, vi, beforeEach } from "vitest"; import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import { invoke } from "@tauri-apps/api/core"; import { PodList } from "@/components/Kubernetes/PodList"; import type { PodInfo } from "@/lib/tauriCommands"; vi.mock("@tauri-apps/api/core"); // Silence console.error noise from modal portals in jsdom vi.mock("@/components/Kubernetes/LogsModal", () => ({ LogsModal: ({ namespace }: { namespace: string }) => (
), })); vi.mock("@/components/Kubernetes/ShellExecModal", () => ({ ShellExecModal: ({ namespace }: { namespace: string }) => (
), })); vi.mock("@/components/Kubernetes/AttachModal", () => ({ AttachModal: ({ namespace }: { namespace: string }) => (
), })); vi.mock("@/components/Kubernetes/EditResourceModal", () => ({ EditResourceModal: ({ namespace }: { namespace: string }) => (
), })); vi.mock("@/components/Kubernetes/ConfirmDeleteDialog", () => ({ ConfirmDeleteDialog: ({ onConfirm, resourceName, }: { onConfirm: () => void; resourceName: string; }) => (
{resourceName}
), })); type MockedInvoke = typeof invoke & { mockResolvedValue: (v: unknown) => void; mockRejectedValue: (e: Error) => void; mockImplementation: (fn: (cmd: string) => Promise) => void; }; const mockInvoke = invoke as MockedInvoke; // A pod whose own namespace ("default") differs from the filter prop ("all") const mockPod: PodInfo = { name: "test-pod", namespace: "default", status: "Running", ready: "1/1", age: "1h", containers: ["app"], }; function openActionMenu() { const trigger = screen.getByRole("button", { name: /actions/i }); fireEvent.click(trigger); } describe("PodList — namespace isolation", () => { beforeEach(() => { vi.clearAllMocks(); }); it('Edit action calls getResourceYamlCmd with pod.namespace ("default"), not filter "all"', async () => { mockInvoke.mockImplementation((cmd: string) => { if (cmd === "get_resource_yaml") { return Promise.resolve("apiVersion: v1\nkind: Pod"); } return Promise.resolve(undefined); }); render( {}} /> ); openActionMenu(); fireEvent.click(screen.getByRole("button", { name: /^edit$/i })); await waitFor(() => { expect(mockInvoke).toHaveBeenCalledWith("get_resource_yaml", { clusterId: "c1", namespace: "default", resourceType: "pods", resourceName: "test-pod", }); }); }); it('Delete action calls deleteResourceCmd with pod.namespace ("default"), not filter "all"', async () => { mockInvoke.mockResolvedValue(undefined); render( {}} /> ); openActionMenu(); fireEvent.click(screen.getByRole("button", { name: /^delete$/i })); await waitFor(() => { expect(screen.getByTestId("confirm-delete")).toBeDefined(); }); fireEvent.click(screen.getByRole("button", { name: /confirm/i })); await waitFor(() => { expect(mockInvoke).toHaveBeenCalledWith("delete_resource", { clusterId: "c1", namespace: "default", resourceType: "pods", resourceName: "test-pod", }); }); }); it('Force Delete action calls forceDeleteResourceCmd with pod.namespace ("default"), not filter "all"', async () => { mockInvoke.mockResolvedValue(undefined); // Force Delete is only visible when pod is Running or Pending render( {}} /> ); openActionMenu(); fireEvent.click(screen.getByRole("button", { name: /^force delete$/i })); await waitFor(() => { expect(screen.getByTestId("confirm-delete")).toBeDefined(); }); fireEvent.click(screen.getByRole("button", { name: /confirm/i })); await waitFor(() => { expect(mockInvoke).toHaveBeenCalledWith("force_delete_resource", { clusterId: "c1", namespace: "default", resourceType: "pods", resourceName: "test-pod", }); }); }); it('Logs modal receives pod.namespace ("default"), not filter "all"', async () => { render( {}} /> ); openActionMenu(); fireEvent.click(screen.getByRole("button", { name: /^logs$/i })); await waitFor(() => { const modal = screen.getByTestId("logs-modal"); expect(modal.getAttribute("data-namespace")).toBe("default"); }); }); it('Shell modal receives pod.namespace ("default"), not filter "all"', async () => { render( {}} /> ); openActionMenu(); fireEvent.click(screen.getByRole("button", { name: /^shell$/i })); await waitFor(() => { const modal = screen.getByTestId("shell-modal"); expect(modal.getAttribute("data-namespace")).toBe("default"); }); }); it('Attach modal receives pod.namespace ("default"), not filter "all"', async () => { render( {}} /> ); openActionMenu(); fireEvent.click(screen.getByRole("button", { name: /^attach$/i })); await waitFor(() => { const modal = screen.getByTestId("attach-modal"); expect(modal.getAttribute("data-namespace")).toBe("default"); }); }); });