feat: partition main canvas vertically (#6759)

Co-authored-by: Marcel Mraz <marcel.mraz@adacta-fintech.com>
Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
Marcel Mraz
2023-08-12 22:56:59 +02:00
committed by GitHub
parent 3ea07076ad
commit a376bd9495
69 changed files with 4348 additions and 2970 deletions

File diff suppressed because it is too large Load Diff

View File

@ -33,7 +33,7 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e
"roundness": {
"type": 2,
},
"seed": 337897,
"seed": 1278240551,
"startArrowhead": null,
"startBinding": null,
"strokeColor": "#1e1e1e",
@ -42,7 +42,7 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e
"type": "arrow",
"updated": 1,
"version": 3,
"versionNonce": 449462985,
"versionNonce": 401146281,
"width": 30,
"x": 30,
"y": 20,
@ -69,14 +69,14 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e
"roundness": {
"type": 2,
},
"seed": 337897,
"seed": 1278240551,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "diamond",
"updated": 1,
"version": 2,
"versionNonce": 1278240551,
"versionNonce": 453191,
"width": 30,
"x": 30,
"y": 20,
@ -103,14 +103,14 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e
"roundness": {
"type": 2,
},
"seed": 337897,
"seed": 1278240551,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "ellipse",
"updated": 1,
"version": 2,
"versionNonce": 1278240551,
"versionNonce": 453191,
"width": 30,
"x": 30,
"y": 20,
@ -148,7 +148,7 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e
"roundness": {
"type": 2,
},
"seed": 337897,
"seed": 1278240551,
"startArrowhead": null,
"startBinding": null,
"strokeColor": "#1e1e1e",
@ -157,7 +157,7 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e
"type": "line",
"updated": 1,
"version": 3,
"versionNonce": 449462985,
"versionNonce": 401146281,
"width": 30,
"x": 30,
"y": 20,
@ -184,14 +184,14 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e
"roundness": {
"type": 3,
},
"seed": 337897,
"seed": 1278240551,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"updated": 1,
"version": 2,
"versionNonce": 1278240551,
"versionNonce": 453191,
"width": 30,
"x": 30,
"y": 20,

View File

@ -5,7 +5,7 @@ exports[`Test Linear Elements > Test bound text element > should match styles fo
class="excalidraw-wysiwyg"
data-type="wysiwyg"
dir="auto"
style="position: absolute; display: inline-block; min-height: 1em; backface-visibility: hidden; margin: 0px; padding: 0px; border: 0px; outline: 0; resize: none; background: transparent; overflow: hidden; z-index: var(--zIndex-wysiwyg); word-break: break-word; white-space: pre-wrap; overflow-wrap: break-word; box-sizing: content-box; width: 10.5px; height: 25px; left: 35px; top: 7.5px; transform: translate(0px, 0px) scale(1) rotate(0deg); text-align: center; vertical-align: middle; color: rgb(30, 30, 30); opacity: 1; filter: var(--theme-filter); max-height: -7.5px; font: Emoji 20px 20px; line-height: 1.25; font-family: Virgil, Segoe UI Emoji;"
style="position: absolute; display: inline-block; min-height: 1em; backface-visibility: hidden; margin: 0px; padding: 0px; border: 0px; outline: 0; resize: none; background: transparent; overflow: hidden; z-index: var(--zIndex-wysiwyg); word-break: break-word; white-space: pre-wrap; overflow-wrap: break-word; box-sizing: content-box; width: 10.5px; height: 25px; left: 35px; top: 7.5px; transform: translate(0px, 0px) scale(1) rotate(0deg); text-align: center; vertical-align: middle; color: rgb(30, 30, 30); opacity: 1; filter: var(--theme-filter); max-height: 992.5px; font: Emoji 20px 20px; line-height: 1.25; font-family: Virgil, Segoe UI Emoji;"
tabindex="0"
wrap="off"
/>

View File

@ -18,14 +18,14 @@ exports[`duplicate element on move when ALT is clicked > rectangle 1`] = `
"roundness": {
"type": 3,
},
"seed": 401146281,
"seed": 1014066025,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"updated": 1,
"version": 4,
"versionNonce": 2019559783,
"versionNonce": 238820263,
"width": 30,
"x": 30,
"y": 20,
@ -50,14 +50,14 @@ exports[`duplicate element on move when ALT is clicked > rectangle 2`] = `
"roundness": {
"type": 3,
},
"seed": 337897,
"seed": 1278240551,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"updated": 1,
"version": 4,
"versionNonce": 1150084233,
"versionNonce": 1604849351,
"width": 30,
"x": -10,
"y": 60,
@ -82,14 +82,14 @@ exports[`move element > rectangle 1`] = `
"roundness": {
"type": 3,
},
"seed": 337897,
"seed": 1278240551,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"updated": 1,
"version": 3,
"versionNonce": 453191,
"versionNonce": 1150084233,
"width": 30,
"x": 0,
"y": 40,
@ -119,14 +119,14 @@ exports[`move element > rectangles with binding arrow 1`] = `
"roundness": {
"type": 3,
},
"seed": 337897,
"seed": 1278240551,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"updated": 1,
"version": 3,
"versionNonce": 1014066025,
"versionNonce": 81784553,
"width": 100,
"x": 0,
"y": 0,
@ -156,14 +156,14 @@ exports[`move element > rectangles with binding arrow 2`] = `
"roundness": {
"type": 3,
},
"seed": 449462985,
"seed": 2019559783,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"updated": 1,
"version": 6,
"versionNonce": 1723083209,
"versionNonce": 927333447,
"width": 300,
"x": 201,
"y": 2,
@ -205,7 +205,7 @@ exports[`move element > rectangles with binding arrow 3`] = `
"roundness": {
"type": 2,
},
"seed": 401146281,
"seed": 238820263,
"startArrowhead": null,
"startBinding": {
"elementId": "id0",
@ -218,7 +218,7 @@ exports[`move element > rectangles with binding arrow 3`] = `
"type": "line",
"updated": 1,
"version": 11,
"versionNonce": 1006504105,
"versionNonce": 1051383431,
"width": 81,
"x": 110,
"y": 49.981789081137734,

View File

@ -38,7 +38,7 @@ exports[`multi point mode in linear elements > arrow 1`] = `
"roundness": {
"type": 2,
},
"seed": 337897,
"seed": 1278240551,
"startArrowhead": null,
"startBinding": null,
"strokeColor": "#1e1e1e",
@ -47,7 +47,7 @@ exports[`multi point mode in linear elements > arrow 1`] = `
"type": "arrow",
"updated": 1,
"version": 7,
"versionNonce": 1150084233,
"versionNonce": 1505387817,
"width": 70,
"x": 30,
"y": 30,
@ -92,7 +92,7 @@ exports[`multi point mode in linear elements > line 1`] = `
"roundness": {
"type": 2,
},
"seed": 337897,
"seed": 1278240551,
"startArrowhead": null,
"startBinding": null,
"strokeColor": "#1e1e1e",
@ -101,7 +101,7 @@ exports[`multi point mode in linear elements > line 1`] = `
"type": "line",
"updated": 1,
"version": 7,
"versionNonce": 1150084233,
"versionNonce": 1505387817,
"width": 70,
"x": 30,
"y": 30,

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@ exports[`select single element on the scene > arrow 1`] = `
"roundness": {
"type": 2,
},
"seed": 337897,
"seed": 1278240551,
"startArrowhead": null,
"startBinding": null,
"strokeColor": "#1e1e1e",
@ -40,7 +40,7 @@ exports[`select single element on the scene > arrow 1`] = `
"type": "arrow",
"updated": 1,
"version": 3,
"versionNonce": 449462985,
"versionNonce": 401146281,
"width": 30,
"x": 10,
"y": 10,
@ -78,7 +78,7 @@ exports[`select single element on the scene > arrow escape 1`] = `
"roundness": {
"type": 2,
},
"seed": 337897,
"seed": 1278240551,
"startArrowhead": null,
"startBinding": null,
"strokeColor": "#1e1e1e",
@ -87,7 +87,7 @@ exports[`select single element on the scene > arrow escape 1`] = `
"type": "line",
"updated": 1,
"version": 3,
"versionNonce": 449462985,
"versionNonce": 401146281,
"width": 30,
"x": 10,
"y": 10,
@ -112,14 +112,14 @@ exports[`select single element on the scene > diamond 1`] = `
"roundness": {
"type": 2,
},
"seed": 337897,
"seed": 1278240551,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "diamond",
"updated": 1,
"version": 2,
"versionNonce": 1278240551,
"versionNonce": 453191,
"width": 30,
"x": 10,
"y": 10,
@ -144,14 +144,14 @@ exports[`select single element on the scene > ellipse 1`] = `
"roundness": {
"type": 2,
},
"seed": 337897,
"seed": 1278240551,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "ellipse",
"updated": 1,
"version": 2,
"versionNonce": 1278240551,
"versionNonce": 453191,
"width": 30,
"x": 10,
"y": 10,
@ -176,14 +176,14 @@ exports[`select single element on the scene > rectangle 1`] = `
"roundness": {
"type": 3,
},
"seed": 337897,
"seed": 1278240551,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 1,
"type": "rectangle",
"updated": 1,
"version": 2,
"versionNonce": 1278240551,
"versionNonce": 453191,
"width": 30,
"x": 10,
"y": 10,

View File

@ -24,7 +24,7 @@ import { LibraryItem } from "../types";
import { vi } from "vitest";
const checkpoint = (name: string) => {
expect(renderScene.mock.calls.length).toMatchSnapshot(
expect(renderStaticScene.mock.calls.length).toMatchSnapshot(
`[${name}] number of renders`,
);
expect(h.state).toMatchSnapshot(`[${name}] appState`);
@ -40,10 +40,10 @@ const mouse = new Pointer("mouse");
// Unmount ReactDOM from root
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
const renderScene = vi.spyOn(Renderer, "renderScene");
const renderStaticScene = vi.spyOn(Renderer, "renderStaticScene");
beforeEach(() => {
localStorage.clear();
renderScene.mockClear();
renderStaticScene.mockClear();
reseed(7);
});
@ -52,7 +52,7 @@ const { h } = window;
describe("contextMenu element", () => {
beforeEach(async () => {
localStorage.clear();
renderScene.mockClear();
renderStaticScene.mockClear();
reseed(7);
setDateTimeForTests("201933152653");
@ -75,7 +75,7 @@ describe("contextMenu element", () => {
});
it("shows context menu for canvas", () => {
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,
@ -105,7 +105,7 @@ describe("contextMenu element", () => {
mouse.down(10, 10);
mouse.up(20, 20);
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,
@ -159,7 +159,7 @@ describe("contextMenu element", () => {
API.setSelectedElements([rect1]);
// lower z-index
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 100,
clientY: 100,
@ -169,7 +169,7 @@ describe("contextMenu element", () => {
// higher z-index
API.setSelectedElements([rect2]);
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 100,
clientY: 100,
@ -193,7 +193,7 @@ describe("contextMenu element", () => {
mouse.click(20, 0);
});
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,
@ -246,7 +246,7 @@ describe("contextMenu element", () => {
Keyboard.keyPress(KEYS.G);
});
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,
@ -285,7 +285,7 @@ describe("contextMenu element", () => {
mouse.down(10, 10);
mouse.up(20, 20);
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,
@ -333,7 +333,7 @@ describe("contextMenu element", () => {
mouse.reset();
// Copy styles of second rectangle
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 40,
clientY: 40,
@ -346,7 +346,7 @@ describe("contextMenu element", () => {
mouse.reset();
// Paste styles to first rectangle
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 10,
clientY: 10,
@ -370,7 +370,7 @@ describe("contextMenu element", () => {
mouse.down(10, 10);
mouse.up(20, 20);
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,
@ -386,7 +386,7 @@ describe("contextMenu element", () => {
mouse.down(10, 10);
mouse.up(20, 20);
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,
@ -407,7 +407,7 @@ describe("contextMenu element", () => {
mouse.down(10, 10);
mouse.up(20, 20);
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,
@ -430,7 +430,7 @@ describe("contextMenu element", () => {
mouse.up(20, 20);
mouse.reset();
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 40,
clientY: 40,
@ -452,7 +452,7 @@ describe("contextMenu element", () => {
mouse.up(20, 20);
mouse.reset();
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 10,
clientY: 10,
@ -474,7 +474,7 @@ describe("contextMenu element", () => {
mouse.up(20, 20);
mouse.reset();
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 40,
clientY: 40,
@ -495,7 +495,7 @@ describe("contextMenu element", () => {
mouse.up(20, 20);
mouse.reset();
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 10,
clientY: 10,
@ -520,7 +520,7 @@ describe("contextMenu element", () => {
mouse.click(10, 10);
});
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,
@ -550,7 +550,7 @@ describe("contextMenu element", () => {
Keyboard.keyPress(KEYS.G);
});
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,

View File

@ -15,10 +15,13 @@ import { vi } from "vitest";
// Unmount ReactDOM from root
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
const renderScene = vi.spyOn(Renderer, "renderScene");
const renderInteractiveScene = vi.spyOn(Renderer, "renderInteractiveScene");
const renderStaticScene = vi.spyOn(Renderer, "renderStaticScene");
beforeEach(() => {
localStorage.clear();
renderScene.mockClear();
renderInteractiveScene.mockClear();
renderStaticScene.mockClear();
reseed(7);
});
@ -32,7 +35,7 @@ describe("Test dragCreate", () => {
const tool = getByToolName("rectangle");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
// start from (30, 20)
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
@ -43,7 +46,8 @@ describe("Test dragCreate", () => {
// finish (position does not matter)
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(9);
expect(renderInteractiveScene).toHaveBeenCalledTimes(6);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
@ -63,7 +67,7 @@ describe("Test dragCreate", () => {
const tool = getByToolName("ellipse");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
// start from (30, 20)
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
@ -74,7 +78,9 @@ describe("Test dragCreate", () => {
// finish (position does not matter)
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(9);
expect(renderInteractiveScene).toHaveBeenCalledTimes(6);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
@ -94,7 +100,7 @@ describe("Test dragCreate", () => {
const tool = getByToolName("diamond");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
// start from (30, 20)
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
@ -105,7 +111,8 @@ describe("Test dragCreate", () => {
// finish (position does not matter)
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(9);
expect(renderInteractiveScene).toHaveBeenCalledTimes(6);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
@ -125,7 +132,7 @@ describe("Test dragCreate", () => {
const tool = getByToolName("arrow");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
// start from (30, 20)
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
@ -136,7 +143,8 @@ describe("Test dragCreate", () => {
// finish (position does not matter)
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(9);
expect(renderInteractiveScene).toHaveBeenCalledTimes(6);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
@ -160,7 +168,7 @@ describe("Test dragCreate", () => {
const tool = getByToolName("line");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
// start from (30, 20)
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
@ -171,7 +179,8 @@ describe("Test dragCreate", () => {
// finish (position does not matter)
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(9);
expect(renderInteractiveScene).toHaveBeenCalledTimes(6);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
@ -203,7 +212,7 @@ describe("Test dragCreate", () => {
const tool = getByToolName("rectangle");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
// start from (30, 20)
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
@ -211,7 +220,8 @@ describe("Test dragCreate", () => {
// finish (position does not matter)
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(7);
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
expect(renderStaticScene).toHaveBeenCalledTimes(5);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(0);
});
@ -222,7 +232,7 @@ describe("Test dragCreate", () => {
const tool = getByToolName("ellipse");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
// start from (30, 20)
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
@ -230,7 +240,8 @@ describe("Test dragCreate", () => {
// finish (position does not matter)
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(7);
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
expect(renderStaticScene).toHaveBeenCalledTimes(5);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(0);
});
@ -241,7 +252,7 @@ describe("Test dragCreate", () => {
const tool = getByToolName("diamond");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
// start from (30, 20)
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
@ -249,7 +260,8 @@ describe("Test dragCreate", () => {
// finish (position does not matter)
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(7);
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
expect(renderStaticScene).toHaveBeenCalledTimes(5);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(0);
});
@ -260,7 +272,7 @@ describe("Test dragCreate", () => {
const tool = getByToolName("arrow");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
// start from (30, 20)
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
@ -273,7 +285,8 @@ describe("Test dragCreate", () => {
key: KEYS.ENTER,
});
expect(renderScene).toHaveBeenCalledTimes(8);
expect(renderInteractiveScene).toHaveBeenCalledTimes(6);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(0);
});
@ -284,7 +297,7 @@ describe("Test dragCreate", () => {
const tool = getByToolName("line");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
// start from (30, 20)
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
@ -297,7 +310,8 @@ describe("Test dragCreate", () => {
key: KEYS.ENTER,
});
expect(renderScene).toHaveBeenCalledTimes(8);
expect(renderInteractiveScene).toHaveBeenCalledTimes(6);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(0);
});

View File

@ -279,7 +279,7 @@ export class API {
};
static drop = async (blob: Blob) => {
const fileDropEvent = createEvent.drop(GlobalTestState.canvas);
const fileDropEvent = createEvent.drop(GlobalTestState.interactiveCanvas);
const text = await new Promise<string>((resolve, reject) => {
try {
const reader = new FileReader();
@ -306,6 +306,6 @@ export class API {
},
},
});
fireEvent(GlobalTestState.canvas, fileDropEvent);
fireEvent(GlobalTestState.interactiveCanvas, fileDropEvent);
};
}

View File

@ -107,7 +107,7 @@ export class Pointer {
restorePosition(x = 0, y = 0) {
this.clientX = x;
this.clientY = y;
fireEvent.pointerMove(GlobalTestState.canvas, this.getEvent());
fireEvent.pointerMove(GlobalTestState.interactiveCanvas, this.getEvent());
}
private getEvent() {
@ -129,18 +129,18 @@ export class Pointer {
if (dx !== 0 || dy !== 0) {
this.clientX += dx;
this.clientY += dy;
fireEvent.pointerMove(GlobalTestState.canvas, this.getEvent());
fireEvent.pointerMove(GlobalTestState.interactiveCanvas, this.getEvent());
}
}
down(dx = 0, dy = 0) {
this.move(dx, dy);
fireEvent.pointerDown(GlobalTestState.canvas, this.getEvent());
fireEvent.pointerDown(GlobalTestState.interactiveCanvas, this.getEvent());
}
up(dx = 0, dy = 0) {
this.move(dx, dy);
fireEvent.pointerUp(GlobalTestState.canvas, this.getEvent());
fireEvent.pointerUp(GlobalTestState.interactiveCanvas, this.getEvent());
}
click(dx = 0, dy = 0) {
@ -150,7 +150,7 @@ export class Pointer {
doubleClick(dx = 0, dy = 0) {
this.move(dx, dy);
fireEvent.doubleClick(GlobalTestState.canvas, this.getEvent());
fireEvent.doubleClick(GlobalTestState.interactiveCanvas, this.getEvent());
}
// absolute coords
@ -159,19 +159,19 @@ export class Pointer {
moveTo(x: number = this.clientX, y: number = this.clientY) {
this.clientX = x;
this.clientY = y;
fireEvent.pointerMove(GlobalTestState.canvas, this.getEvent());
fireEvent.pointerMove(GlobalTestState.interactiveCanvas, this.getEvent());
}
downAt(x = this.clientX, y = this.clientY) {
this.clientX = x;
this.clientY = y;
fireEvent.pointerDown(GlobalTestState.canvas, this.getEvent());
fireEvent.pointerDown(GlobalTestState.interactiveCanvas, this.getEvent());
}
upAt(x = this.clientX, y = this.clientY) {
this.clientX = x;
this.clientY = y;
fireEvent.pointerUp(GlobalTestState.canvas, this.getEvent());
fireEvent.pointerUp(GlobalTestState.interactiveCanvas, this.getEvent());
}
clickAt(x: number, y: number) {
@ -180,7 +180,7 @@ export class Pointer {
}
rightClickAt(x: number, y: number) {
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: x,
clientY: y,
@ -189,7 +189,7 @@ export class Pointer {
doubleClickAt(x: number, y: number) {
this.moveTo(x, y);
fireEvent.doubleClick(GlobalTestState.canvas, this.getEvent());
fireEvent.doubleClick(GlobalTestState.interactiveCanvas, this.getEvent());
}
// ---------------------------------------------------------------------------
@ -327,6 +327,13 @@ export class UI {
});
}
static ungroup(elements: ExcalidrawElement[]) {
mouse.select(elements);
Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
Keyboard.keyPress(KEYS.G);
});
}
static queryContextMenu = () => {
return GlobalTestState.renderResult.container.querySelector(
".context-menu",

View File

@ -26,26 +26,28 @@ import * as textElementUtils from "../element/textElement";
import { ROUNDNESS, VERTICAL_ALIGN } from "../constants";
import { vi } from "vitest";
const renderScene = vi.spyOn(Renderer, "renderScene");
const renderInteractiveScene = vi.spyOn(Renderer, "renderInteractiveScene");
const renderStaticScene = vi.spyOn(Renderer, "renderStaticScene");
const { h } = window;
const font = "20px Cascadia, width: Segoe UI Emoji" as FontString;
describe("Test Linear Elements", () => {
let container: HTMLElement;
let canvas: HTMLCanvasElement;
let interactiveCanvas: HTMLCanvasElement;
beforeEach(async () => {
// Unmount ReactDOM from root
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
localStorage.clear();
renderScene.mockClear();
renderInteractiveScene.mockClear();
renderStaticScene.mockClear();
reseed(7);
const comp = await render(<ExcalidrawApp />);
h.state.width = 1000;
h.state.height = 1000;
container = comp.container;
canvas = container.querySelector("canvas")!;
canvas.width = 1000;
canvas.height = 1000;
interactiveCanvas = container.querySelector("canvas.interactive")!;
});
const p1: Point = [20, 20];
@ -120,26 +122,26 @@ describe("Test Linear Elements", () => {
};
const drag = (startPoint: Point, endPoint: Point) => {
fireEvent.pointerDown(canvas, {
fireEvent.pointerDown(interactiveCanvas, {
clientX: startPoint[0],
clientY: startPoint[1],
});
fireEvent.pointerMove(canvas, {
fireEvent.pointerMove(interactiveCanvas, {
clientX: endPoint[0],
clientY: endPoint[1],
});
fireEvent.pointerUp(canvas, {
fireEvent.pointerUp(interactiveCanvas, {
clientX: endPoint[0],
clientY: endPoint[1],
});
};
const deletePoint = (point: Point) => {
fireEvent.pointerDown(canvas, {
fireEvent.pointerDown(interactiveCanvas, {
clientX: point[0],
clientY: point[1],
});
fireEvent.pointerUp(canvas, {
fireEvent.pointerUp(interactiveCanvas, {
clientX: point[0],
clientY: point[1],
});
@ -172,12 +174,14 @@ describe("Test Linear Elements", () => {
createTwoPointerLinearElement("line");
const line = h.elements[0] as ExcalidrawLinearElement;
expect(renderScene).toHaveBeenCalledTimes(7);
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
expect(renderStaticScene).toHaveBeenCalledTimes(4);
expect((h.elements[0] as ExcalidrawLinearElement).points.length).toEqual(2);
// drag line from midpoint
drag(midpoint, [midpoint[0] + delta, midpoint[1] + delta]);
expect(renderScene).toHaveBeenCalledTimes(11);
expect(renderInteractiveScene).toHaveBeenCalledTimes(9);
expect(renderStaticScene).toHaveBeenCalledTimes(5);
expect(line.points.length).toEqual(3);
expect(line.points).toMatchInlineSnapshot(`
[
@ -199,14 +203,14 @@ describe("Test Linear Elements", () => {
it("should allow entering and exiting line editor via context menu", () => {
createTwoPointerLinearElement("line");
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: midpoint[0],
clientY: midpoint[1],
});
// Enter line editor
let contextMenu = document.querySelector(".context-menu");
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: midpoint[0],
clientY: midpoint[1],
@ -216,13 +220,13 @@ describe("Test Linear Elements", () => {
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
// Exiting line editor
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: midpoint[0],
clientY: midpoint[1],
});
contextMenu = document.querySelector(".context-menu");
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: midpoint[0],
clientY: midpoint[1],
@ -270,7 +274,8 @@ describe("Test Linear Elements", () => {
// drag line from midpoint
drag(midpoint, [midpoint[0] + delta, midpoint[1] + delta]);
expect(renderScene).toHaveBeenCalledTimes(15);
expect(renderInteractiveScene).toHaveBeenCalledTimes(14);
expect(renderStaticScene).toHaveBeenCalledTimes(5);
expect(line.points.length).toEqual(3);
expect(line.points).toMatchInlineSnapshot(`
@ -307,7 +312,9 @@ describe("Test Linear Elements", () => {
// update roundness
fireEvent.click(screen.getByTitle("Round"));
expect(renderScene).toHaveBeenCalledTimes(12);
expect(renderInteractiveScene).toHaveBeenCalledTimes(10);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
const midPointsWithRoundEdge = LinearElementEditor.getEditorMidPoints(
h.elements[0] as ExcalidrawLinearElement,
h.state,
@ -351,7 +358,9 @@ describe("Test Linear Elements", () => {
// Move the element
drag(startPoint, endPoint);
expect(renderScene).toHaveBeenCalledTimes(16);
expect(renderInteractiveScene).toHaveBeenCalledTimes(14);
expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect([line.x, line.y]).toEqual([
points[0][0] + deltaX,
points[0][1] + deltaY,
@ -408,7 +417,9 @@ describe("Test Linear Elements", () => {
lastSegmentMidpoint[1] + delta,
]);
expect(renderScene).toHaveBeenCalledTimes(21);
expect(renderInteractiveScene).toHaveBeenCalledTimes(21);
expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect(line.points.length).toEqual(5);
expect((h.elements[0] as ExcalidrawLinearElement).points)
@ -447,7 +458,8 @@ describe("Test Linear Elements", () => {
// Drag from first point
drag(hitCoords, [hitCoords[0] - delta, hitCoords[1] - delta]);
expect(renderScene).toHaveBeenCalledTimes(16);
expect(renderInteractiveScene).toHaveBeenCalledTimes(14);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
const newPoints = LinearElementEditor.getPointsGlobalCoordinates(line);
expect([newPoints[0][0], newPoints[0][1]]).toEqual([
@ -473,7 +485,8 @@ describe("Test Linear Elements", () => {
// Drag from first point
drag(hitCoords, [hitCoords[0] + delta, hitCoords[1] + delta]);
expect(renderScene).toHaveBeenCalledTimes(16);
expect(renderInteractiveScene).toHaveBeenCalledTimes(14);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
const newPoints = LinearElementEditor.getPointsGlobalCoordinates(line);
expect([newPoints[0][0], newPoints[0][1]]).toEqual([
@ -507,7 +520,8 @@ describe("Test Linear Elements", () => {
// delete 3rd point
deletePoint(points[2]);
expect(line.points.length).toEqual(3);
expect(renderScene).toHaveBeenCalledTimes(22);
expect(renderInteractiveScene).toHaveBeenCalledTimes(21);
expect(renderStaticScene).toHaveBeenCalledTimes(7);
const newMidPoints = LinearElementEditor.getEditorMidPoints(
line,
@ -553,8 +567,8 @@ describe("Test Linear Elements", () => {
lastSegmentMidpoint[0] + delta,
lastSegmentMidpoint[1] + delta,
]);
expect(renderScene).toHaveBeenCalledTimes(21);
expect(renderInteractiveScene).toHaveBeenCalledTimes(21);
expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect(line.points.length).toEqual(5);
expect((h.elements[0] as ExcalidrawLinearElement).points)
@ -629,7 +643,8 @@ describe("Test Linear Elements", () => {
// Drag from first point
drag(hitCoords, [hitCoords[0] + delta, hitCoords[1] + delta]);
expect(renderScene).toHaveBeenCalledTimes(16);
expect(renderInteractiveScene).toHaveBeenCalledTimes(14);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
const newPoints = LinearElementEditor.getPointsGlobalCoordinates(line);
expect([newPoints[0][0], newPoints[0][1]]).toEqual([
@ -870,10 +885,10 @@ describe("Test Linear Elements", () => {
]);
expect((h.elements[1] as ExcalidrawTextElementWithContainer).text)
.toMatchInlineSnapshot(`
"Online whiteboard
collaboration made
easy"
`);
"Online whiteboard
collaboration made
easy"
`);
});
it("should bind text to arrow when clicked on arrow and enter pressed", async () => {
@ -904,10 +919,10 @@ describe("Test Linear Elements", () => {
]);
expect((h.elements[1] as ExcalidrawTextElementWithContainer).text)
.toMatchInlineSnapshot(`
"Online whiteboard
collaboration made
easy"
`);
"Online whiteboard
collaboration made
easy"
`);
});
it("should not bind text to line when double clicked", async () => {
@ -1046,9 +1061,9 @@ describe("Test Linear Elements", () => {
`);
expect((h.elements[1] as ExcalidrawTextElementWithContainer).text)
.toMatchInlineSnapshot(`
"Online whiteboard
collaboration made easy"
`);
"Online whiteboard
collaboration made easy"
`);
expect(LinearElementEditor.getElementAbsoluteCoords(container, true))
.toMatchInlineSnapshot(`
[
@ -1206,7 +1221,7 @@ describe("Test Linear Elements", () => {
const container = h.elements[0];
API.setSelectedElements([container, text]);
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 20,
clientY: 30,
@ -1231,7 +1246,7 @@ describe("Test Linear Elements", () => {
mouse.up();
API.setSelectedElements([h.elements[0], h.elements[1]]);
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 20,
clientY: 30,

View File

@ -17,10 +17,13 @@ import { vi } from "vitest";
// Unmount ReactDOM from root
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
const renderScene = vi.spyOn(Renderer, "renderScene");
const renderInteractiveScene = vi.spyOn(Renderer, "renderInteractiveScene");
const renderStaticScene = vi.spyOn(Renderer, "renderStaticScene");
beforeEach(() => {
localStorage.clear();
renderScene.mockClear();
renderInteractiveScene.mockClear();
renderStaticScene.mockClear();
reseed(7);
});
@ -29,7 +32,7 @@ const { h } = window;
describe("move element", () => {
it("rectangle", async () => {
const { getByToolName, container } = await render(<ExcalidrawApp />);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
{
// create element
@ -39,20 +42,23 @@ describe("move element", () => {
fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 });
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(9);
expect(renderInteractiveScene).toHaveBeenCalledTimes(6);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
expect([h.elements[0].x, h.elements[0].y]).toEqual([30, 20]);
renderScene.mockClear();
renderInteractiveScene.mockClear();
renderStaticScene.mockClear();
}
fireEvent.pointerDown(canvas, { clientX: 50, clientY: 20 });
fireEvent.pointerMove(canvas, { clientX: 20, clientY: 40 });
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(3);
expect(renderInteractiveScene).toHaveBeenCalledTimes(3);
expect(renderStaticScene).toHaveBeenCalledTimes(2);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
expect([h.elements[0].x, h.elements[0].y]).toEqual([0, 40]);
@ -78,7 +84,8 @@ describe("move element", () => {
// select the second rectangles
new Pointer("mouse").clickOn(rectB);
expect(renderScene).toHaveBeenCalledTimes(23);
expect(renderInteractiveScene).toHaveBeenCalledTimes(21);
expect(renderStaticScene).toHaveBeenCalledTimes(16);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(3);
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
@ -87,7 +94,8 @@ describe("move element", () => {
expect([line.x, line.y]).toEqual([110, 50]);
expect([line.width, line.height]).toEqual([80, 80]);
renderScene.mockClear();
renderInteractiveScene.mockClear();
renderStaticScene.mockClear();
// Move selected rectangle
Keyboard.keyDown(KEYS.ARROW_RIGHT);
@ -95,7 +103,8 @@ describe("move element", () => {
Keyboard.keyDown(KEYS.ARROW_DOWN);
// Check that the arrow size has been changed according to moving the rectangle
expect(renderScene).toHaveBeenCalledTimes(3);
expect(renderInteractiveScene).toHaveBeenCalledTimes(3);
expect(renderStaticScene).toHaveBeenCalledTimes(3);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(3);
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
@ -111,7 +120,7 @@ describe("move element", () => {
describe("duplicate element on move when ALT is clicked", () => {
it("rectangle", async () => {
const { getByToolName, container } = await render(<ExcalidrawApp />);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
{
// create element
@ -121,13 +130,15 @@ describe("duplicate element on move when ALT is clicked", () => {
fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 });
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(9);
expect(renderInteractiveScene).toHaveBeenCalledTimes(6);
expect(renderStaticScene).toHaveBeenCalledTimes(6);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
expect([h.elements[0].x, h.elements[0].y]).toEqual([30, 20]);
renderScene.mockClear();
renderInteractiveScene.mockClear();
renderStaticScene.mockClear();
}
fireEvent.pointerDown(canvas, { clientX: 50, clientY: 20 });
@ -141,7 +152,8 @@ describe("duplicate element on move when ALT is clicked", () => {
// TODO: This used to be 4, but binding made it go up to 5. Do we need
// that additional render?
expect(renderScene).toHaveBeenCalledTimes(5);
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
expect(renderStaticScene).toHaveBeenCalledTimes(3);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(2);

View File

@ -15,10 +15,13 @@ import { vi } from "vitest";
// Unmount ReactDOM from root
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
const renderScene = vi.spyOn(Renderer, "renderScene");
const renderInteractiveScene = vi.spyOn(Renderer, "renderInteractiveScene");
const renderStaticScene = vi.spyOn(Renderer, "renderStaticScene");
beforeEach(() => {
localStorage.clear();
renderScene.mockClear();
renderInteractiveScene.mockClear();
renderStaticScene.mockClear();
reseed(7);
});
@ -39,11 +42,12 @@ describe("remove shape in non linear elements", () => {
const tool = getByToolName("rectangle");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 });
expect(renderScene).toHaveBeenCalledTimes(7);
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
expect(renderStaticScene).toHaveBeenCalledTimes(5);
expect(h.elements.length).toEqual(0);
});
@ -53,11 +57,12 @@ describe("remove shape in non linear elements", () => {
const tool = getByToolName("ellipse");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 });
expect(renderScene).toHaveBeenCalledTimes(7);
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
expect(renderStaticScene).toHaveBeenCalledTimes(5);
expect(h.elements.length).toEqual(0);
});
@ -67,11 +72,12 @@ describe("remove shape in non linear elements", () => {
const tool = getByToolName("diamond");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 });
expect(renderScene).toHaveBeenCalledTimes(7);
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
expect(renderStaticScene).toHaveBeenCalledTimes(5);
expect(h.elements.length).toEqual(0);
});
});
@ -83,7 +89,7 @@ describe("multi point mode in linear elements", () => {
const tool = getByToolName("arrow");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
// first point is added on pointer down
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 30 });
@ -103,7 +109,8 @@ describe("multi point mode in linear elements", () => {
key: KEYS.ENTER,
});
expect(renderScene).toHaveBeenCalledTimes(15);
expect(renderInteractiveScene).toHaveBeenCalledTimes(10);
expect(renderStaticScene).toHaveBeenCalledTimes(10);
expect(h.elements.length).toEqual(1);
const element = h.elements[0] as ExcalidrawLinearElement;
@ -126,7 +133,7 @@ describe("multi point mode in linear elements", () => {
const tool = getByToolName("line");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
// first point is added on pointer down
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 30 });
@ -146,7 +153,8 @@ describe("multi point mode in linear elements", () => {
key: KEYS.ENTER,
});
expect(renderScene).toHaveBeenCalledTimes(15);
expect(renderInteractiveScene).toHaveBeenCalledTimes(10);
expect(renderStaticScene).toHaveBeenCalledTimes(10);
expect(h.elements.length).toEqual(1);
const element = h.elements[0] as ExcalidrawLinearElement;

View File

@ -1,6 +1,6 @@
import { fireEvent, GlobalTestState, toggleMenu, render } from "../test-utils";
import { Excalidraw, Footer, MainMenu } from "../../packages/excalidraw/index";
import { queryByText, queryByTestId, screen } from "@testing-library/react";
import { queryByText, queryByTestId } from "@testing-library/react";
import { GRID_SIZE, THEME } from "../../constants";
import { t } from "../../i18n";
import { useMemo } from "react";
@ -23,7 +23,7 @@ describe("<Excalidraw/>", () => {
).toBe(0);
expect(h.state.zenModeEnabled).toBe(false);
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,
@ -42,8 +42,8 @@ describe("<Excalidraw/>", () => {
container.getElementsByClassName("disable-zen-mode--visible").length,
).toBe(0);
expect(h.state.zenModeEnabled).toBe(true);
screen.debug();
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,
@ -95,7 +95,7 @@ describe("<Excalidraw/>", () => {
expect(
container.getElementsByClassName("disable-zen-mode--visible").length,
).toBe(0);
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,
@ -114,7 +114,7 @@ describe("<Excalidraw/>", () => {
expect(
container.getElementsByClassName("disable-zen-mode--visible").length,
).toBe(0);
fireEvent.contextMenu(GlobalTestState.canvas, {
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
button: 2,
clientX: 1,
clientY: 1,

View File

@ -21,7 +21,7 @@ import { vi } from "vitest";
const { h } = window;
const renderScene = vi.spyOn(Renderer, "renderScene");
const renderStaticScene = vi.spyOn(Renderer, "renderStaticScene");
const mouse = new Pointer("mouse");
const finger1 = new Pointer("touch", 1);
@ -33,7 +33,7 @@ const finger2 = new Pointer("touch", 2);
* to debug where a test failure came from.
*/
const checkpoint = (name: string) => {
expect(renderScene.mock.calls.length).toMatchSnapshot(
expect(renderStaticScene.mock.calls.length).toMatchSnapshot(
`[${name}] number of renders`,
);
expect(h.state).toMatchSnapshot(`[${name}] appState`);
@ -48,7 +48,7 @@ beforeEach(async () => {
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
localStorage.clear();
renderScene.mockClear();
renderStaticScene.mockClear();
reseed(7);
setDateTimeForTests("201933152653");
@ -1056,6 +1056,28 @@ describe("regression tests", () => {
expect(API.getSelectedElements()).toEqual(selectedElements_prev);
});
it("deleting last but one element in editing group should unselect the group", () => {
const rect1 = UI.createElement("rectangle", { x: 10 });
const rect2 = UI.createElement("rectangle", { x: 50 });
UI.group([rect1, rect2]);
mouse.doubleClickOn(rect1);
Keyboard.keyDown(KEYS.DELETE);
// Clicking on the deleted element, hence in the empty space
mouse.clickOn(rect1);
expect(h.state.selectedGroupIds).toEqual({});
expect(API.getSelectedElements()).toEqual([]);
// Clicking back in and expecting no group selection
mouse.clickOn(rect2);
expect(h.state.selectedGroupIds).toEqual({ [rect2.groupIds[0]]: false });
expect(API.getSelectedElements()).toEqual([rect2.get()]);
});
it("Cmd/Ctrl-click exclusively select element under pointer", () => {
const rect1 = UI.createElement("rectangle", { x: 0 });
const rect2 = UI.createElement("rectangle", { x: 30 });

View File

@ -14,10 +14,11 @@ import { vi } from "vitest";
// Unmount ReactDOM from root
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
const renderScene = vi.spyOn(Renderer, "renderScene");
const renderStaticScene = vi.spyOn(Renderer, "renderStaticScene");
beforeEach(() => {
localStorage.clear();
renderScene.mockClear();
renderStaticScene.mockClear();
reseed(7);
});

View File

@ -18,10 +18,13 @@ import { vi } from "vitest";
// Unmount ReactDOM from root
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
const renderScene = vi.spyOn(Renderer, "renderScene");
const renderInteractiveScene = vi.spyOn(Renderer, "renderInteractiveScene");
const renderStaticScene = vi.spyOn(Renderer, "renderStaticScene");
beforeEach(() => {
localStorage.clear();
renderScene.mockClear();
renderInteractiveScene.mockClear();
renderStaticScene.mockClear();
reseed(7);
});
@ -201,7 +204,7 @@ describe("inner box-selection", () => {
});
h.elements = [rect1, rect2, rect3];
Keyboard.withModifierKeys({ ctrl: true }, () => {
mouse.downAt(rect2.x - 20, rect2.x - 20);
mouse.downAt(rect2.x - 20, rect2.y - 20);
mouse.moveTo(rect2.x + rect2.width + 10, rect2.y + rect2.height + 10);
assertSelectedElements([rect2.id, rect3.id]);
expect(h.state.selectedGroupIds).toEqual({ A: true });
@ -220,10 +223,11 @@ describe("selection element", () => {
const tool = getByToolName("selection");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
fireEvent.pointerDown(canvas, { clientX: 60, clientY: 100 });
expect(renderScene).toHaveBeenCalledTimes(5);
expect(renderInteractiveScene).toHaveBeenCalledTimes(3);
expect(renderStaticScene).toHaveBeenCalledTimes(3);
const selectionElement = h.state.selectionElement!;
expect(selectionElement).not.toBeNull();
expect(selectionElement.type).toEqual("selection");
@ -240,11 +244,12 @@ describe("selection element", () => {
const tool = getByToolName("selection");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
fireEvent.pointerDown(canvas, { clientX: 60, clientY: 100 });
fireEvent.pointerMove(canvas, { clientX: 150, clientY: 30 });
expect(renderScene).toHaveBeenCalledTimes(6);
expect(renderInteractiveScene).toHaveBeenCalledTimes(4);
expect(renderStaticScene).toHaveBeenCalledTimes(3);
const selectionElement = h.state.selectionElement!;
expect(selectionElement).not.toBeNull();
expect(selectionElement.type).toEqual("selection");
@ -261,12 +266,13 @@ describe("selection element", () => {
const tool = getByToolName("selection");
fireEvent.click(tool);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
fireEvent.pointerDown(canvas, { clientX: 60, clientY: 100 });
fireEvent.pointerMove(canvas, { clientX: 150, clientY: 30 });
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(7);
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
expect(renderStaticScene).toHaveBeenCalledTimes(3);
expect(h.state.selectionElement).toBeNull();
});
});
@ -282,7 +288,7 @@ describe("select single element on the scene", () => {
it("rectangle", async () => {
const { getByToolName, container } = await render(<ExcalidrawApp />);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
{
// create element
const tool = getByToolName("rectangle");
@ -301,7 +307,8 @@ describe("select single element on the scene", () => {
fireEvent.pointerDown(canvas, { clientX: 45, clientY: 20 });
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(11);
expect(renderInteractiveScene).toHaveBeenCalledTimes(9);
expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
@ -311,7 +318,7 @@ describe("select single element on the scene", () => {
it("diamond", async () => {
const { getByToolName, container } = await render(<ExcalidrawApp />);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
{
// create element
const tool = getByToolName("diamond");
@ -330,7 +337,8 @@ describe("select single element on the scene", () => {
fireEvent.pointerDown(canvas, { clientX: 45, clientY: 20 });
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(11);
expect(renderInteractiveScene).toHaveBeenCalledTimes(9);
expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
@ -340,7 +348,7 @@ describe("select single element on the scene", () => {
it("ellipse", async () => {
const { getByToolName, container } = await render(<ExcalidrawApp />);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
{
// create element
const tool = getByToolName("ellipse");
@ -359,7 +367,8 @@ describe("select single element on the scene", () => {
fireEvent.pointerDown(canvas, { clientX: 45, clientY: 20 });
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(11);
expect(renderInteractiveScene).toHaveBeenCalledTimes(9);
expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
@ -369,7 +378,7 @@ describe("select single element on the scene", () => {
it("arrow", async () => {
const { getByToolName, container } = await render(<ExcalidrawApp />);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
{
// create element
const tool = getByToolName("arrow");
@ -401,7 +410,8 @@ describe("select single element on the scene", () => {
fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 });
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(11);
expect(renderInteractiveScene).toHaveBeenCalledTimes(9);
expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
@ -410,7 +420,7 @@ describe("select single element on the scene", () => {
it("arrow escape", async () => {
const { getByToolName, container } = await render(<ExcalidrawApp />);
const canvas = container.querySelector("canvas")!;
const canvas = container.querySelector("canvas.interactive")!;
{
// create element
const tool = getByToolName("line");
@ -442,7 +452,8 @@ describe("select single element on the scene", () => {
fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 });
fireEvent.pointerUp(canvas);
expect(renderScene).toHaveBeenCalledTimes(11);
expect(renderInteractiveScene).toHaveBeenCalledTimes(9);
expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1);
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();

View File

@ -49,15 +49,30 @@ const renderApp: TestRenderFn = async (ui, options) => {
// child App component isn't likely mounted yet (and thus canvas not
// present in DOM)
get() {
return renderResult.container.querySelector("canvas")!;
return renderResult.container.querySelector("canvas.static")!;
},
});
Object.defineProperty(GlobalTestState, "interactiveCanvas", {
// must be a getter because at the time of ExcalidrawApp render the
// child App component isn't likely mounted yet (and thus canvas not
// present in DOM)
get() {
return renderResult.container.querySelector("canvas.interactive")!;
},
});
await waitFor(() => {
const canvas = renderResult.container.querySelector("canvas");
const canvas = renderResult.container.querySelector("canvas.static");
if (!canvas) {
throw new Error("not initialized yet");
}
const interactiveCanvas =
renderResult.container.querySelector("canvas.interactive");
if (!interactiveCanvas) {
throw new Error("not initialized yet");
}
});
return renderResult;
@ -81,11 +96,17 @@ export class GlobalTestState {
*/
static renderResult: RenderResult<typeof customQueries> = null!;
/**
* retrieves canvas for currently rendered app instance
* retrieves static canvas for currently rendered app instance
*/
static get canvas(): HTMLCanvasElement {
return null!;
}
/**
* retrieves interactive canvas for currently rendered app instance
*/
static get interactiveCanvas(): HTMLCanvasElement {
return null!;
}
}
const initLocalStorage = (data: ImportedDataState) => {

View File

@ -17,7 +17,9 @@ describe("view mode", () => {
it("after switching to view mode cursor type should be pointer", async () => {
h.setState({ viewModeEnabled: true });
expect(GlobalTestState.canvas.style.cursor).toBe(CURSOR_TYPE.GRAB);
expect(GlobalTestState.interactiveCanvas.style.cursor).toBe(
CURSOR_TYPE.GRAB,
);
});
it("after switching to view mode, moving, clicking, and pressing space key cursor type should be pointer", async () => {
@ -29,7 +31,9 @@ describe("view mode", () => {
pointer.move(100, 100);
pointer.click();
Keyboard.keyPress(KEYS.SPACE);
expect(GlobalTestState.canvas.style.cursor).toBe(CURSOR_TYPE.GRAB);
expect(GlobalTestState.interactiveCanvas.style.cursor).toBe(
CURSOR_TYPE.GRAB,
);
});
});
@ -45,13 +49,19 @@ describe("view mode", () => {
pointer.moveTo(50, 50);
// eslint-disable-next-line dot-notation
if (pointerType["pointerType"] === "mouse") {
expect(GlobalTestState.canvas.style.cursor).toBe(CURSOR_TYPE.MOVE);
expect(GlobalTestState.interactiveCanvas.style.cursor).toBe(
CURSOR_TYPE.MOVE,
);
} else {
expect(GlobalTestState.canvas.style.cursor).toBe(CURSOR_TYPE.GRAB);
expect(GlobalTestState.interactiveCanvas.style.cursor).toBe(
CURSOR_TYPE.GRAB,
);
}
h.setState({ viewModeEnabled: true });
expect(GlobalTestState.canvas.style.cursor).toBe(CURSOR_TYPE.GRAB);
expect(GlobalTestState.interactiveCanvas.style.cursor).toBe(
CURSOR_TYPE.GRAB,
);
});
});
});

View File

@ -94,7 +94,7 @@ const populateElements = (
),
...appState,
selectedElementIds,
});
} as AppState);
return selectedElementIds;
};