diff --git a/src/components/Dialog/RefreshKeysDialog/RefreshKeysDialog.test.tsx b/src/components/Dialog/RefreshKeysDialog/RefreshKeysDialog.test.tsx index e955b88fd..a1733d95b 100644 --- a/src/components/Dialog/RefreshKeysDialog/RefreshKeysDialog.test.tsx +++ b/src/components/Dialog/RefreshKeysDialog/RefreshKeysDialog.test.tsx @@ -1,55 +1,102 @@ import { render, screen, fireEvent } from "@testing-library/react"; -import { beforeEach, describe, expect, it, Mock, vi } from "vitest"; -import { RefreshKeysDialog } from "./RefreshKeysDialog"; +import { beforeEach, describe, expect, it, vi, Mock } from "vitest"; +import { RefreshKeysDialog } from "./RefreshKeysDialog.tsx"; import { useRefreshKeysDialog } from "./useRefreshKeysDialog.ts"; +import { useMessageStore } from "@core/stores/messageStore.ts"; // Import for mocking +import { useDevice } from "@core/stores/deviceStore.ts"; // Import for mocking +import { Protobuf } from "@meshtastic/core"; + +vi.mock("@core/stores/messageStore.ts", () => ({ + useMessageStore: vi.fn(), +})); + +const mockNodeWithError: Partial = { + user: { longName: "Test Node Long", shortName: "TNL", id: 456 }, +}; +const mockNodes = new Map([[456, mockNodeWithError]]); +const mockNodeErrors = new Map([[123, { node: 456 }]]); + +vi.mock("@core/stores/deviceStore.ts", () => ({ + useDevice: vi.fn(), +})); + +const mockHandleCloseDialog = vi.fn(); +const mockHandleNodeRemove = vi.fn(); vi.mock("./useRefreshKeysDialog.ts", () => ({ - useRefreshKeysDialog: vi.fn(), + useRefreshKeysDialog: vi.fn(() => ({ + handleCloseDialog: mockHandleCloseDialog, + handleNodeRemove: mockHandleNodeRemove, + })), })); describe("RefreshKeysDialog Component", () => { - let handleCloseDialogMock: Mock; - let handleNodeRemoveMock: Mock; let onOpenChangeMock: Mock; beforeEach(() => { - handleCloseDialogMock = vi.fn(); - handleNodeRemoveMock = vi.fn(); + vi.clearAllMocks(); onOpenChangeMock = vi.fn(); - (useRefreshKeysDialog as Mock).mockReturnValue({ - handleCloseDialog: handleCloseDialogMock, - handleNodeRemove: handleNodeRemoveMock, + vi.mocked(useMessageStore).mockReturnValue({ activeChat: 123 }); + vi.mocked(useDevice).mockReturnValue({ + nodeErrors: mockNodeErrors, + nodes: mockNodes, + }); + vi.mocked(useRefreshKeysDialog).mockReturnValue({ + handleCloseDialog: mockHandleCloseDialog, + handleNodeRemove: mockHandleNodeRemove, }); }); - it("renders the dialog with correct content", () => { - render(); - expect(screen.getByText("Keys Mismatch")).toBeInTheDocument(); - expect(screen.getByText("Request New Keys")).toBeInTheDocument(); - expect(screen.getByText("Dismiss")).toBeInTheDocument(); + it("should render the dialog with dynamic content when open and data is available", () => { + render(); + + expect(screen.getByText(`Keys Mismatch - ${mockNodeWithError?.user?.longName}`)).toBeInTheDocument(); + expect(screen.getByText(new RegExp(`${mockNodeWithError?.user?.longName}.*${mockNodeWithError?.user?.shortName}`))).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /request new keys/i })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /dismiss/i })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /Close/i })).toBeInTheDocument(); }); - it("calls handleNodeRemove when 'Request New Keys' button is clicked", () => { - render(); - fireEvent.click(screen.getByText("Request New Keys")); - expect(handleNodeRemoveMock).toHaveBeenCalled(); + it("should call handleNodeRemove when 'Request New Keys' button is clicked", () => { + render(); + fireEvent.click(screen.getByRole('button', { name: /request new keys/i })); + expect(mockHandleNodeRemove).toHaveBeenCalledTimes(1); }); - it("calls handleCloseDialog when 'Dismiss' button is clicked", () => { - render(); - fireEvent.click(screen.getByText("Dismiss")); - expect(handleCloseDialogMock).toHaveBeenCalled(); + it("should call handleCloseDialog when 'Dismiss' button is clicked", () => { + render(); + fireEvent.click(screen.getByRole('button', { name: /dismiss/i })); + expect(mockHandleCloseDialog).toHaveBeenCalledTimes(1); }); - it("calls onOpenChange when dialog close button is clicked", () => { - render(); - fireEvent.click(screen.getByRole("button", { name: /close/i })); - expect(handleCloseDialogMock).toHaveBeenCalled(); + it("should call handleCloseDialog when the explicit DialogClose button is clicked", () => { + render(); + fireEvent.click(screen.getByRole('button', { name: /close/i })); // Use the aria-label + expect(mockHandleCloseDialog).toHaveBeenCalledTimes(1); }); - it("does not render when open is false", () => { + + it("should not render the dialog when open is false", () => { render(); - expect(screen.queryByText("Keys Mismatch")).not.toBeInTheDocument(); + expect(screen.queryByRole("dialog")).not.toBeInTheDocument(); + }); + + it("should render null if nodeErrorNum is not found for activeChat", () => { + vi.mocked(useDevice).mockReturnValue({ + nodeErrors: new Map(), + nodes: mockNodes, + }); + const { container } = render(); + expect(container.firstChild).toBeNull(); + }); + + it("should render null if nodeWithError is not found for nodeErrorNum.node", () => { + vi.mocked(useDevice).mockReturnValue({ + nodeErrors: mockNodeErrors, + nodes: new Map(), + }); + const { container } = render(); + expect(container.firstChild).toBeNull(); }); -}); +}); \ No newline at end of file diff --git a/src/components/Dialog/RefreshKeysDialog/RefreshKeysDialog.tsx b/src/components/Dialog/RefreshKeysDialog/RefreshKeysDialog.tsx index d2fc659d1..ad1373f4b 100644 --- a/src/components/Dialog/RefreshKeysDialog/RefreshKeysDialog.tsx +++ b/src/components/Dialog/RefreshKeysDialog/RefreshKeysDialog.tsx @@ -8,6 +8,8 @@ import { import { Button } from "@components/UI/Button.tsx"; import { LockKeyholeOpenIcon } from "lucide-react"; import { useRefreshKeysDialog } from "./useRefreshKeysDialog.ts"; +import { useDevice } from "@core/stores/deviceStore.ts"; +import { useMessageStore } from "@core/stores/messageStore.ts"; export interface RefreshKeysDialogProps { open: boolean; @@ -15,16 +17,36 @@ export interface RefreshKeysDialogProps { } export const RefreshKeysDialog = ({ open, onOpenChange }: RefreshKeysDialogProps) => { - + const { activeChat } = useMessageStore(); + const { nodeErrors, nodes } = useDevice(); const { handleCloseDialog, handleNodeRemove } = useRefreshKeysDialog(); + + const nodeErrorNum = nodeErrors.get(activeChat); + + if (!nodeErrorNum) { + console.error("Node with error not found"); + return null; + } + + const nodeWithError = nodes.get(nodeErrorNum?.node ?? 0); + + if (!nodeWithError) { + console.error("Node with error not found"); + return null; + } + + const text = { + title: `Keys Mismatch - ${nodeWithError?.user?.longName ?? ""}`, + description: `Your node is unable to send a direct message to node: ${nodeWithError?.user?.longName ?? ""} (${nodeWithError?.user?.shortName ?? ""}). This is due to the remote node's current public key does not match the previously stored key for this node.`, + } return ( - Keys Mismatch + {text.title} - Your node is unable to send a direct message to this node. This is due to the remote node's current public key not matching the previously stored key for this node. + {text.description}
  • @@ -40,14 +62,12 @@ export const RefreshKeysDialog = ({ open, onOpenChange }: RefreshKeysDialogProps diff --git a/src/components/UI/Dialog.tsx b/src/components/UI/Dialog.tsx index 442af95e6..ce56f70e1 100644 --- a/src/components/UI/Dialog.tsx +++ b/src/components/UI/Dialog.tsx @@ -60,7 +60,7 @@ const DialogClose = ({ ...props }: DialogPrimitive.DialogCloseProps & React.RefAttributes & { className?: string }) => (