// @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);
});
});