* init * add: vite dev build working * fix: href serving from public * feat: add ejs plugin * feat: migrated env files and ejs templating * chore: add types related to envs * chore: add vite-env types * feat: support vite pwa * chore: upgrade vite pwa * chore: pin node version to 16.18.1 * chore: preserve use of nodejs 14 * refactor: preserve REACT_APP as env prefix * chore: support esm environment variables * fix ts config * use VITE prefix and remove vite-plugin-env-compatible * introduce import-meta-loader for building pacakge as webpack isn't compatible with import.meta syntax * lint * remove import.meta.env in main.js * set debug flag to false * migrate to vitest and use jest-canvas-mock 2.4.0 so its comp atible with vite * integrate vitest-ui * fix most of teh test * snaps * Add script for testing with vite ui * fix all tests related to mocking * fix more test * fix more * fix flip.test.tsx * fix contentxmenu snaps * fix regression snaps * fix excalidraw.test.tsx and this makes all tests finally pass :) * use node 16 * specify node version * use node 16 in lint as well * fix mobile.test.tsx * use node 16 * add style-loader * upgrade to node 18 * fix lint package.json * support eslint with vite * fix lint * fix lint * fix ts * remove pwa/sw stuff * use env vars in EJS the vite way * fix lint * move remainig jest mock/spy to vite * don't cache locales * fix regex * add fonts cache * tweak * add custom service worker * upgrade vite and create font cache again * cache fonts.css and locales * tweak * use manifestTransforms for filtering locales * use assets js pattern for locales * add font.css to globIgnore so its pushed to fonts cache * create a separate chunk for locales with rollup * remove manifestTransforms and fix glob pattern for locales to filter from workbox pre-cache * push sourcemaps in production * add comments in config * lint * use node 18 * disable pwa in dev * fix * fix * increase limit of bundle * upgrade vite-pwa to latest * remove public/workbox so workbox assets are not precached * fon't club en.json and percentages.json with manual locales chunk to fix first load+offline mode * tweak regex * remove happy-dom as its not used * add comment * use any instead of ts-ignore * cleanup * remove jest-canvas-mock resolution as vite-canvas-mock was patched locking deps at 2.4.0 * use same theme color present in entry point * remove vite-plugin-eslint as it improves DX significantly * integrate vite-plugin-checker for ts errors * add nabla/vite-plugin-eslint * use eslint from checker only * add env variable VITE_APP_COLLAPSE_OVERLAY for collapsing the checker overlay * tweak vite checker overlay badge position * Enable eslint behind flag as its not working well with windows with non WSL * make port configurable * open the browser when server ready * enable eslint by default --------- Co-authored-by: Weslley Braga <weslley@bambee.com> Co-authored-by: dwelle <luzar.david@gmail.com>
333 lines
10 KiB
TypeScript
333 lines
10 KiB
TypeScript
import React from "react";
|
|
import { DEFAULT_SIDEBAR } from "../../constants";
|
|
import { Excalidraw, Sidebar } from "../../packages/excalidraw/index";
|
|
import {
|
|
fireEvent,
|
|
GlobalTestState,
|
|
queryAllByTestId,
|
|
queryByTestId,
|
|
render,
|
|
waitFor,
|
|
withExcalidrawDimensions,
|
|
} from "../../tests/test-utils";
|
|
import { vi } from "vitest";
|
|
|
|
export const assertSidebarDockButton = async <T extends boolean>(
|
|
hasDockButton: T,
|
|
): Promise<
|
|
T extends false
|
|
? { dockButton: null; sidebar: HTMLElement }
|
|
: { dockButton: HTMLElement; sidebar: HTMLElement }
|
|
> => {
|
|
const sidebar =
|
|
GlobalTestState.renderResult.container.querySelector<HTMLElement>(
|
|
".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(
|
|
<Excalidraw initialData={{ appState: { openSidebar: { name } } }}>
|
|
{sidebar}
|
|
</Excalidraw>,
|
|
);
|
|
await withExcalidrawDimensions({ width: 1920, height: 1080 }, test);
|
|
};
|
|
|
|
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 props.toggleMenu()", 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(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);
|
|
});
|
|
});
|
|
});
|
|
|
|
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 () => {
|
|
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);
|
|
},
|
|
);
|
|
});
|
|
});
|
|
});
|