import React from "react"; import { DEFAULT_SIDEBAR } from "../../constants"; import { Excalidraw, Sidebar } from "../../index"; import { fireEvent, GlobalTestState, queryAllByTestId, queryByTestId, render, waitFor, withExcalidrawDimensions, } from "../../tests/test-utils"; import { vi } from "vitest"; export const assertSidebarDockButton = async ( hasDockButton: T, ): Promise< T extends false ? { dockButton: null; sidebar: HTMLElement } : { dockButton: HTMLElement; sidebar: HTMLElement } > => { const sidebar = GlobalTestState.renderResult.container.querySelector( ".sidebar", ); expect(sidebar).not.toBe(null); const dockButton = queryByTestId(sidebar!, "sidebar-dock"); if (hasDockButton) { expect(dockButton).not.toBe(null); return { dockButton: dockButton!, sidebar: sidebar! } as any; } expect(dockButton).toBe(null); return { dockButton: null, sidebar: sidebar! } as any; }; export const assertExcalidrawWithSidebar = async ( sidebar: React.ReactNode, name: string, test: () => void, ) => { await render( {sidebar} , ); await withExcalidrawDimensions({ width: 1920, height: 1080 }, test); }; describe("Sidebar", () => { describe("General behavior", () => { it("should render custom sidebar", async () => { const { container } = await render(
42
, ); const node = container.querySelector("#test-sidebar-content"); expect(node).not.toBe(null); }); it("should render only one sidebar and prefer the custom one", async () => { const { container } = await render(
42
, ); await waitFor(() => { // make sure the custom sidebar is rendered const node = container.querySelector("#test-sidebar-content"); expect(node).not.toBe(null); // make sure only one sidebar is rendered const sidebars = container.querySelectorAll(".sidebar"); expect(sidebars.length).toBe(1); }); }); it("should toggle sidebar using excalidrawAPI.toggleSidebar()", async () => { const { container } = await render(
42
, ); // sidebar isn't rendered initially // ------------------------------------------------------------------------- await waitFor(() => { const node = container.querySelector("#test-sidebar-content"); expect(node).toBe(null); }); // toggle sidebar on // ------------------------------------------------------------------------- expect(window.h.app.toggleSidebar({ name: "customSidebar" })).toBe(true); await waitFor(() => { const node = container.querySelector("#test-sidebar-content"); expect(node).not.toBe(null); }); // toggle sidebar off // ------------------------------------------------------------------------- expect(window.h.app.toggleSidebar({ name: "customSidebar" })).toBe(false); await waitFor(() => { const node = container.querySelector("#test-sidebar-content"); expect(node).toBe(null); }); // force-toggle sidebar off (=> still hidden) // ------------------------------------------------------------------------- expect( window.h.app.toggleSidebar({ name: "customSidebar", force: false }), ).toBe(false); await waitFor(() => { const node = container.querySelector("#test-sidebar-content"); expect(node).toBe(null); }); // force-toggle sidebar on // ------------------------------------------------------------------------- expect( window.h.app.toggleSidebar({ name: "customSidebar", force: true }), ).toBe(true); expect( window.h.app.toggleSidebar({ name: "customSidebar", force: true }), ).toBe(true); await waitFor(() => { const node = container.querySelector("#test-sidebar-content"); expect(node).not.toBe(null); }); // toggle library (= hide custom sidebar) // ------------------------------------------------------------------------- expect(window.h.app.toggleSidebar({ name: DEFAULT_SIDEBAR.name })).toBe( true, ); await waitFor(() => { const node = container.querySelector("#test-sidebar-content"); expect(node).toBe(null); // make sure only one sidebar is rendered const sidebars = container.querySelectorAll(".sidebar"); expect(sidebars.length).toBe(1); }); // closing sidebar using `{ name: null }` // ------------------------------------------------------------------------- expect(window.h.app.toggleSidebar({ name: "customSidebar" })).toBe(true); await waitFor(() => { const node = container.querySelector("#test-sidebar-content"); expect(node).not.toBe(null); }); expect(window.h.app.toggleSidebar({ name: null })).toBe(false); await waitFor(() => { const node = container.querySelector("#test-sidebar-content"); expect(node).toBe(null); }); }); }); describe("", () => { it("should render custom sidebar header", async () => { const { container } = await render(
42
, ); const node = container.querySelector("#test-sidebar-header-content"); expect(node).not.toBe(null); // make sure we don't render the default fallback header, // just the custom one expect(queryAllByTestId(container, "sidebar-header").length).toBe(1); }); it("should not render for custom sidebars by default", async () => { const CustomExcalidraw = () => { return ( hello ); }; const { container } = await render(); const sidebar = container.querySelector(".test-sidebar"); expect(sidebar).not.toBe(null); const closeButton = queryByTestId(sidebar!, "sidebar-close"); expect(closeButton).toBe(null); }); it(" should render close button", async () => { const onStateChange = vi.fn(); const CustomExcalidraw = () => { return ( ); }; const { container } = await render(); // initial open expect(onStateChange).toHaveBeenCalledWith({ name: "customSidebar" }); const sidebar = container.querySelector(".test-sidebar"); expect(sidebar).not.toBe(null); const closeButton = queryByTestId(sidebar!, "sidebar-close")!; expect(closeButton).not.toBe(null); fireEvent.click(closeButton); await waitFor(() => { expect(container.querySelector(".test-sidebar")).toBe( null, ); expect(onStateChange).toHaveBeenCalledWith(null); }); }); }); describe("Docking behavior", () => { it("shouldn't be user-dockable if `onDock` not supplied", async () => { await assertExcalidrawWithSidebar( , "customSidebar", async () => { await assertSidebarDockButton(false); }, ); }); it("shouldn't be user-dockable if `onDock` not supplied & `docked={true}`", async () => { await assertExcalidrawWithSidebar( , "customSidebar", async () => { await assertSidebarDockButton(false); }, ); }); it("shouldn't be user-dockable if `onDock` not supplied & docked={false}`", async () => { await assertExcalidrawWithSidebar( , "customSidebar", async () => { await assertSidebarDockButton(false); }, ); }); it("should be user-dockable when both `onDock` and `docked` supplied", async () => { await render( {}} docked > , ); await withExcalidrawDimensions( { width: 1920, height: 1080 }, async () => { await assertSidebarDockButton(true); }, ); }); it("shouldn't be user-dockable when only `onDock` supplied w/o `docked`", async () => { await render( {}} > , ); await withExcalidrawDimensions( { width: 1920, height: 1080 }, async () => { await assertSidebarDockButton(false); }, ); }); }); describe("Sidebar.tab", () => { it("should toggle sidebars tabs correctly", async () => { const { container } = await render( Library Comments , ); await withExcalidrawDimensions( { width: 1920, height: 1080 }, async () => { expect( container.querySelector( "[role=tabpanel][data-testid=library]", ), ).toBeNull(); // open library sidebar expect( window.h.app.toggleSidebar({ name: "custom", tab: "library" }), ).toBe(true); expect( container.querySelector( "[role=tabpanel][data-testid=library]", ), ).not.toBeNull(); // switch to comments tab expect( window.h.app.toggleSidebar({ name: "custom", tab: "comments" }), ).toBe(true); expect( container.querySelector( "[role=tabpanel][data-testid=comments]", ), ).not.toBeNull(); // toggle sidebar closed expect( window.h.app.toggleSidebar({ name: "custom", tab: "comments" }), ).toBe(false); expect( container.querySelector( "[role=tabpanel][data-testid=comments]", ), ).toBeNull(); // toggle sidebar open expect( window.h.app.toggleSidebar({ name: "custom", tab: "comments" }), ).toBe(true); expect( container.querySelector( "[role=tabpanel][data-testid=comments]", ), ).not.toBeNull(); }, ); }); }); });