excalidraw/src/tests/MermaidToExcalidraw.test.tsx
Aakansha Doshi e8def8da8d
feat: Support mermaid flowchart and sequence diagrams to excalidraw diagrams 🥳 (#6920)
* feat: integrate mermaidToExcalidraw

* create mermaid to excal dialog

* allow mermaid syntax and export in preview

* fix

* fix webpack config

* fix markdown error by using named export

* center preview

* set elements as selected when inserted onto canvas

* persist mermaid data to storage

* store canvas data in refs

* load mermaid lazily

* tweak design

* compute width, height correctly for arrows

* fix undefined vertex issue

* add mermaid icon in dropdown

* add a note in dialog

* reset preview when error

* show error in preview when error

* show mermaid error messgae react way

* design tweaks

* add example and docs link

* fix

* tweak design to remove scroll bar

* show a spinner unless mermaid loaded

* regenerate ids when needed via programmatic api, this makes sure for mermaid diagrams ids are regenerated

* tweak

* add option to transform viewport to scene coords in transform api

* make opts optional and use 100% zoom when inserting to canvas

* fix arrow bindings in safari and firefox

* fix elements insert position and viewport centering

* fix: Update start/end points by 0.5 so bindings don't overlap with start/end bound element coordinates.

* defer rendering the preview

* tweak text

* fix tests

* remove only

* make design responsive

* fix: show extra tools dropdown in mobile

* fix mobile css

* width auto

* upgrade mermaid-to-excalidraw

* don't pass appState in deps as its not used

* upgrade mermaid-to-excalidraw to fix firefox issue

* use types from mermaid-to-excalidraw

* upgrade mermaid-to-excalidraw

* use stable version of mermaid-to-excalidraw

* upgrade mermaid-to-excalidraw

* fix width of shapes toolbar for smaller screen size and also fix regression of mobile menu

* use i18n

* better api

* enable test coverage in ui

* Add tests

* use common utils to update and get text editor

* updgrade mermaid-to-excalidraw to support sequence diagrams

* fix test

* don't update arrow container height anytime in when redrawing text bounding box

* increase size limit

* increase size limit of vendor to 900kb

* use openDialog for mermaid

* upgrade mermaid-to-excalidraw

* update frame id post generation

* upgrade mermaid-to-excalidraw to add entity codes support

* update size limit

* upgrade mermaid-to-excalidraw package with frame api changes

* upgrade mermaid-to-excalidraw to remove directive and use config

* don't highlight mermaid tool and remove unused api setSelection

* stop using loading state to update text area

* move some styling to scss

* review fixes

* use modifiedTableIcon props and remove stale snap

* css

* dialog css

* fix snap

* use dialog border

* change mermaidToExcalidrawLib to state

* better styling of errors

* make modal bigger

* fix mobile

* update snaps

* fix icon color

* fix dark mode insert button color

* horizontally center spinner

* render canvas conditionally on loaded state

* rd tweaks

* tweak class names

* remove max height

* typo in example

* upgrade mermaid-to-excalidraw

* simplify error state

* fix height & overflow on vertical breakpoint

* fix lint

* show errors in overlay

* set textarea font family

* reduce opacity

* update snap

* upgrade to mermaid  0.1.2

---------

Co-authored-by: dwelle <luzar.david@gmail.com>
2023-11-03 17:41:34 +05:30

168 lines
4.4 KiB
TypeScript

import { act, fireEvent, render } from "./test-utils";
import { Excalidraw } from "../packages/excalidraw/index";
import React from "react";
import { expect, vi } from "vitest";
import * as MermaidToExcalidraw from "@excalidraw/mermaid-to-excalidraw";
import { getTextEditor, updateTextEditor } from "./queries/dom";
vi.mock("@excalidraw/mermaid-to-excalidraw", async (importActual) => {
const module = (await importActual()) as any;
return {
__esModule: true,
...module,
};
});
const parseMermaidToExcalidrawSpy = vi.spyOn(
MermaidToExcalidraw,
"parseMermaidToExcalidraw",
);
parseMermaidToExcalidrawSpy.mockImplementation(
async (
definition: string,
options?: MermaidToExcalidraw.MermaidOptions | undefined,
) => {
const firstLine = definition.split("\n")[0];
return new Promise((resolve, reject) => {
if (firstLine === "flowchart TD") {
resolve({
elements: [
{
id: "Start",
type: "rectangle",
groupIds: [],
x: 0,
y: 0,
width: 69.703125,
height: 44,
strokeWidth: 2,
label: {
groupIds: [],
text: "Start",
fontSize: 20,
},
link: null,
},
{
id: "Stop",
type: "rectangle",
groupIds: [],
x: 2.7109375,
y: 94,
width: 64.28125,
height: 44,
strokeWidth: 2,
label: {
groupIds: [],
text: "Stop",
fontSize: 20,
},
link: null,
},
{
id: "Start_Stop",
type: "arrow",
groupIds: [],
x: 34.852,
y: 44,
strokeWidth: 2,
points: [
[0, 0],
[0, 50],
],
roundness: {
type: 2,
},
start: {
id: "Start",
},
end: {
id: "Stop",
},
},
],
});
} else {
reject(new Error("ERROR"));
}
});
},
);
vi.spyOn(React, "useRef").mockReturnValue({
current: {
parseMermaidToExcalidraw: parseMermaidToExcalidrawSpy,
},
});
describe("Test <MermaidToExcalidraw/>", () => {
beforeEach(async () => {
await render(
<Excalidraw
initialData={{
appState: {
openDialog: "mermaid",
},
}}
/>,
);
});
it("should open mermaid popup when active tool is mermaid", async () => {
const dialog = document.querySelector(".dialog-mermaid")!;
expect(dialog.outerHTML).toMatchSnapshot();
});
it("should close the popup and set the tool to selection when close button clicked", () => {
const dialog = document.querySelector(".dialog-mermaid")!;
const closeBtn = dialog.querySelector(".Dialog__close")!;
fireEvent.click(closeBtn);
expect(document.querySelector(".dialog-mermaid")).toBe(null);
expect(window.h.state.activeTool).toStrictEqual({
customType: null,
lastActiveTool: null,
locked: false,
type: "selection",
});
});
it("should show error in preview when mermaid library throws error", async () => {
const dialog = document.querySelector(".dialog-mermaid")!;
const selector = ".dialog-mermaid-panels-text textarea";
let editor = await getTextEditor(selector, false);
expect(dialog.querySelector('[data-testid="mermaid-error"]')).toBeNull();
expect(editor.textContent).toMatchInlineSnapshot(`
"flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[Car]"
`);
await act(async () => {
updateTextEditor(editor, "flowchart TD1");
await new Promise((cb) => setTimeout(cb, 0));
});
editor = await getTextEditor(selector, false);
expect(editor.textContent).toBe("flowchart TD1");
expect(dialog.querySelector('[data-testid="mermaid-error"]'))
.toMatchInlineSnapshot(`
<div
class="mermaid-error"
data-testid="mermaid-error"
>
Error!
<p>
ERROR
</p>
</div>
`);
});
});