aboutsummaryrefslogtreecommitdiffstats
path: root/packages/excalidraw/components/Sidebar/Sidebar.test.tsx
diff options
context:
space:
mode:
authorkj_sh6042026-03-15 16:19:35 -0400
committerkj_sh6042026-03-15 16:19:35 -0400
commit6ec259a0e71174651bae95d4628138bf6fd68742 (patch)
tree5e33c6a5ec091ecabfcb257fdc7b6a88ed8754ac /packages/excalidraw/components/Sidebar/Sidebar.test.tsx
parent16c8578b15c727f22921f8a80a56ee4d4e7f2272 (diff)
refactor: packages/
Diffstat (limited to 'packages/excalidraw/components/Sidebar/Sidebar.test.tsx')
-rw-r--r--packages/excalidraw/components/Sidebar/Sidebar.test.tsx393
1 files changed, 393 insertions, 0 deletions
diff --git a/packages/excalidraw/components/Sidebar/Sidebar.test.tsx b/packages/excalidraw/components/Sidebar/Sidebar.test.tsx
new file mode 100644
index 0000000..b61529d
--- /dev/null
+++ b/packages/excalidraw/components/Sidebar/Sidebar.test.tsx
@@ -0,0 +1,393 @@
+import React from "react";
+import { DEFAULT_SIDEBAR } from "../../constants";
+import { Excalidraw, Sidebar } from "../../index";
+import {
+ act,
+ fireEvent,
+ queryAllByTestId,
+ queryByTestId,
+ render,
+ waitFor,
+ withExcalidrawDimensions,
+} from "../../tests/test-utils";
+import { vi } from "vitest";
+import {
+ assertExcalidrawWithSidebar,
+ assertSidebarDockButton,
+} from "./siderbar.test.helpers";
+
+const toggleSidebar = (
+ ...args: Parameters<typeof window.h.app.toggleSidebar>
+): Promise<boolean> => {
+ return act(() => {
+ return window.h.app.toggleSidebar(...args);
+ });
+};
+
+describe("Sidebar", () => {
+ describe("General behavior", () => {
+ it("should render custom sidebar", async () => {
+ const { container } = await render(
+ <Excalidraw
+ initialData={{ appState: { openSidebar: { name: "customSidebar" } } }}
+ >
+ <Sidebar name="customSidebar">
+ <div id="test-sidebar-content">42</div>
+ </Sidebar>
+ </Excalidraw>,
+ );
+
+ 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(
+ <Excalidraw
+ initialData={{ appState: { openSidebar: { name: "customSidebar" } } }}
+ >
+ <Sidebar name="customSidebar">
+ <div id="test-sidebar-content">42</div>
+ </Sidebar>
+ </Excalidraw>,
+ );
+
+ 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(
+ <Excalidraw>
+ <Sidebar name="customSidebar">
+ <div id="test-sidebar-content">42</div>
+ </Sidebar>
+ </Excalidraw>,
+ );
+
+ // sidebar isn't rendered initially
+ // -------------------------------------------------------------------------
+ await waitFor(() => {
+ const node = container.querySelector("#test-sidebar-content");
+ expect(node).toBe(null);
+ });
+
+ // toggle sidebar on
+ // -------------------------------------------------------------------------
+ expect(await toggleSidebar({ name: "customSidebar" })).toBe(true);
+
+ await waitFor(() => {
+ const node = container.querySelector("#test-sidebar-content");
+ expect(node).not.toBe(null);
+ });
+
+ // toggle sidebar off
+ // -------------------------------------------------------------------------
+ expect(await 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(await 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(await toggleSidebar({ name: "customSidebar", force: true })).toBe(
+ true,
+ );
+ expect(await 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(await 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(await toggleSidebar({ name: "customSidebar" })).toBe(true);
+ await waitFor(() => {
+ const node = container.querySelector("#test-sidebar-content");
+ expect(node).not.toBe(null);
+ });
+
+ expect(await toggleSidebar({ name: null })).toBe(false);
+ await waitFor(() => {
+ const node = container.querySelector("#test-sidebar-content");
+ expect(node).toBe(null);
+ });
+ });
+ });
+
+ describe("<Sidebar.Header/>", () => {
+ it("should render custom sidebar header", async () => {
+ const { container } = await render(
+ <Excalidraw
+ initialData={{ appState: { openSidebar: { name: "customSidebar" } } }}
+ >
+ <Sidebar name="customSidebar">
+ <Sidebar.Header>
+ <div id="test-sidebar-header-content">42</div>
+ </Sidebar.Header>
+ </Sidebar>
+ </Excalidraw>,
+ );
+
+ 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 <Sidebar.Header> for custom sidebars by default", async () => {
+ const CustomExcalidraw = () => {
+ return (
+ <Excalidraw
+ initialData={{
+ appState: { openSidebar: { name: "customSidebar" } },
+ }}
+ >
+ <Sidebar name="customSidebar" className="test-sidebar">
+ hello
+ </Sidebar>
+ </Excalidraw>
+ );
+ };
+
+ const { container } = await render(<CustomExcalidraw />);
+
+ const sidebar = container.querySelector<HTMLElement>(".test-sidebar");
+ expect(sidebar).not.toBe(null);
+ const closeButton = queryByTestId(sidebar!, "sidebar-close");
+ expect(closeButton).toBe(null);
+ });
+
+ it("<Sidebar.Header> should render close button", async () => {
+ const onStateChange = vi.fn();
+ const CustomExcalidraw = () => {
+ return (
+ <Excalidraw
+ initialData={{
+ appState: { openSidebar: { name: "customSidebar" } },
+ }}
+ >
+ <Sidebar
+ name="customSidebar"
+ className="test-sidebar"
+ onStateChange={onStateChange}
+ >
+ <Sidebar.Header />
+ </Sidebar>
+ </Excalidraw>
+ );
+ };
+
+ const { container } = await render(<CustomExcalidraw />);
+
+ // initial open
+ expect(onStateChange).toHaveBeenCalledWith({ name: "customSidebar" });
+
+ const sidebar = container.querySelector<HTMLElement>(".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<HTMLElement>(".test-sidebar")).toBe(
+ null,
+ );
+ expect(onStateChange).toHaveBeenCalledWith(null);
+ });
+ });
+ });
+
+ describe("Docking behavior", () => {
+ it("shouldn't be user-dockable if `onDock` not supplied", async () => {
+ await assertExcalidrawWithSidebar(
+ <Sidebar name="customSidebar">
+ <Sidebar.Header />
+ </Sidebar>,
+ "customSidebar",
+ async () => {
+ await assertSidebarDockButton(false);
+ },
+ );
+ });
+
+ it("shouldn't be user-dockable if `onDock` not supplied & `docked={true}`", async () => {
+ await assertExcalidrawWithSidebar(
+ <Sidebar name="customSidebar" docked={true}>
+ <Sidebar.Header />
+ </Sidebar>,
+ "customSidebar",
+ async () => {
+ await assertSidebarDockButton(false);
+ },
+ );
+ });
+
+ it("shouldn't be user-dockable if `onDock` not supplied & docked={false}`", async () => {
+ await assertExcalidrawWithSidebar(
+ <Sidebar name="customSidebar" docked={false}>
+ <Sidebar.Header />
+ </Sidebar>,
+ "customSidebar",
+ async () => {
+ await assertSidebarDockButton(false);
+ },
+ );
+ });
+
+ it("should be user-dockable when both `onDock` and `docked` supplied", async () => {
+ await render(
+ <Excalidraw
+ initialData={{ appState: { openSidebar: { name: "customSidebar" } } }}
+ >
+ <Sidebar
+ name="customSidebar"
+ className="test-sidebar"
+ onDock={() => {}}
+ docked
+ >
+ <Sidebar.Header />
+ </Sidebar>
+ </Excalidraw>,
+ );
+
+ await withExcalidrawDimensions(
+ { width: 1920, height: 1080 },
+ async () => {
+ await assertSidebarDockButton(true);
+ },
+ );
+ });
+
+ it("shouldn't be user-dockable when only `onDock` supplied w/o `docked`", async () => {
+ // we expect warnings in this test and don't want to pollute stdout
+ const mock = jest.spyOn(console, "warn").mockImplementation(() => {});
+
+ await render(
+ <Excalidraw
+ initialData={{ appState: { openSidebar: { name: "customSidebar" } } }}
+ >
+ <Sidebar
+ name="customSidebar"
+ className="test-sidebar"
+ onDock={() => {}}
+ >
+ <Sidebar.Header />
+ </Sidebar>
+ </Excalidraw>,
+ );
+
+ await withExcalidrawDimensions(
+ { width: 1920, height: 1080 },
+ async () => {
+ await assertSidebarDockButton(false);
+ },
+ );
+
+ mock.mockRestore();
+ });
+ });
+
+ describe("Sidebar.tab", () => {
+ it("should toggle sidebars tabs correctly", async () => {
+ const { container } = await render(
+ <Excalidraw>
+ <Sidebar name="custom" docked>
+ <Sidebar.Tabs>
+ <Sidebar.Tab tab="library">Library</Sidebar.Tab>
+ <Sidebar.Tab tab="comments">Comments</Sidebar.Tab>
+ </Sidebar.Tabs>
+ </Sidebar>
+ </Excalidraw>,
+ );
+
+ await withExcalidrawDimensions(
+ { width: 1920, height: 1080 },
+ async () => {
+ expect(
+ container.querySelector<HTMLElement>(
+ "[role=tabpanel][data-testid=library]",
+ ),
+ ).toBeNull();
+
+ // open library sidebar
+ expect(await toggleSidebar({ name: "custom", tab: "library" })).toBe(
+ true,
+ );
+ expect(
+ container.querySelector<HTMLElement>(
+ "[role=tabpanel][data-testid=library]",
+ ),
+ ).not.toBeNull();
+
+ // switch to comments tab
+ expect(await toggleSidebar({ name: "custom", tab: "comments" })).toBe(
+ true,
+ );
+ expect(
+ container.querySelector<HTMLElement>(
+ "[role=tabpanel][data-testid=comments]",
+ ),
+ ).not.toBeNull();
+
+ // toggle sidebar closed
+ expect(await toggleSidebar({ name: "custom", tab: "comments" })).toBe(
+ false,
+ );
+ expect(
+ container.querySelector<HTMLElement>(
+ "[role=tabpanel][data-testid=comments]",
+ ),
+ ).toBeNull();
+
+ // toggle sidebar open
+ expect(await toggleSidebar({ name: "custom", tab: "comments" })).toBe(
+ true,
+ );
+ expect(
+ container.querySelector<HTMLElement>(
+ "[role=tabpanel][data-testid=comments]",
+ ),
+ ).not.toBeNull();
+ },
+ );
+ });
+ });
+});