// @vitest-environment jsdom import React, { act } from "react"; import { createRoot, type Root } from "react-dom/client"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; const mocks = vi.hoisted(() => ({ createNodeWithIntersection: vi.fn(async () => undefined), getCenteredPosition: vi.fn(() => ({ x: 0, y: 0 })), })); vi.mock("@/components/canvas/canvas-placement-context", () => ({ useCanvasPlacement: () => ({ createNodeWithIntersection: mocks.createNodeWithIntersection, }), })); vi.mock("@/hooks/use-centered-flow-node-position", () => ({ useCenteredFlowNodePosition: () => mocks.getCenteredPosition, })); vi.mock("@/components/ui/dropdown-menu", () => ({ DropdownMenu: ({ children }: { children: React.ReactNode }) =>
{children}
, DropdownMenuTrigger: ({ children }: { children: React.ReactNode }) => <>{children}, DropdownMenuContent: ({ children }: { children: React.ReactNode }) =>
{children}
, DropdownMenuItem: ({ children }: { children: React.ReactNode }) => , DropdownMenuLabel: ({ children }: { children: React.ReactNode }) =>
{children}
, DropdownMenuSeparator: () =>
, })); vi.mock("@/components/canvas/credit-display", () => ({ CreditDisplay: () =>
, })); vi.mock("@/components/canvas/export-button", () => ({ ExportButton: ({ canvasName }: { canvasName: string }) => ( ), })); vi.mock("@/lib/canvas-node-catalog", () => ({ NODE_CATEGORIES_ORDERED: [], NODE_CATEGORY_META: {}, catalogEntriesByCategory: () => new Map(), getTemplateForCatalogType: () => null, isNodePaletteEnabled: () => false, })); import CanvasToolbar from "@/components/canvas/canvas-toolbar"; (globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; describe("CanvasToolbar", () => { let container: HTMLDivElement | null = null; let root: Root | null = null; beforeEach(() => { mocks.createNodeWithIntersection.mockClear(); mocks.getCenteredPosition.mockClear(); container = document.createElement("div"); document.body.appendChild(container); root = createRoot(container); }); afterEach(async () => { if (root) { await act(async () => { root?.unmount(); }); } container?.remove(); container = null; root = null; }); it("renders the favorites filter button", async () => { await act(async () => { root?.render( , ); }); const favoriteButton = container?.querySelector('button[title="Favoriten hervorheben"]'); expect(favoriteButton).not.toBeNull(); }); it("reflects active state via aria-pressed", async () => { await act(async () => { root?.render( , ); }); let favoriteButton = container?.querySelector('button[title="Favoriten hervorheben"]'); expect(favoriteButton?.getAttribute("aria-pressed")).toBe("false"); await act(async () => { root?.render( , ); }); favoriteButton = container?.querySelector('button[title="Favoriten hervorheben"]'); expect(favoriteButton?.getAttribute("aria-pressed")).toBe("true"); }); it("toggles and calls onFavoriteFilterChange", async () => { const onFavoriteFilterChange = vi.fn(); await act(async () => { root?.render( , ); }); const favoriteButton = container?.querySelector('button[title="Favoriten hervorheben"]'); if (!(favoriteButton instanceof HTMLButtonElement)) { throw new Error("Favorite filter button not found"); } await act(async () => { favoriteButton.click(); }); expect(onFavoriteFilterChange).toHaveBeenCalledTimes(1); expect(onFavoriteFilterChange).toHaveBeenCalledWith(true); onFavoriteFilterChange.mockClear(); await act(async () => { root?.render( , ); }); const activeFavoriteButton = container?.querySelector('button[title="Favoriten hervorheben"]'); if (!(activeFavoriteButton instanceof HTMLButtonElement)) { throw new Error("Active favorite filter button not found"); } await act(async () => { activeFavoriteButton.click(); }); expect(onFavoriteFilterChange).toHaveBeenCalledTimes(1); expect(onFavoriteFilterChange).toHaveBeenCalledWith(false); }); });