mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Fix tests
This commit is contained in:
parent
05d8ce55e4
commit
ff57dd60d8
9 changed files with 432 additions and 258 deletions
|
@ -18,7 +18,9 @@ const mouse = new Pointer("mouse");
|
||||||
|
|
||||||
describe("element binding", () => {
|
describe("element binding", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
localStorage.clear();
|
||||||
await render(<Excalidraw handleKeyboardGlobally={true} />);
|
await render(<Excalidraw handleKeyboardGlobally={true} />);
|
||||||
|
mouse.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create valid binding if duplicate start/end points", async () => {
|
it("should create valid binding if duplicate start/end points", async () => {
|
||||||
|
@ -89,8 +91,16 @@ describe("element binding", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
//@TODO fix the test with rotation
|
// UX RATIONALE: We are not aware of any use-case where the user would want to
|
||||||
it.skip("rotation of arrow should rebind both ends", () => {
|
// have the arrow rebind after rotation but not when the arrow shaft is
|
||||||
|
// dragged so either the start or the end point is in the binding range of a
|
||||||
|
// bindable element. So to remain consistent, we only "rebind" if at the end
|
||||||
|
// of the rotation the original binding would remain the same (i.e. like we
|
||||||
|
// would've evaluated binding only at the end of the operation).
|
||||||
|
it(
|
||||||
|
"rotation of arrow should not rebind on both ends if rotated enough to" +
|
||||||
|
" not be in the binding range of the original elements",
|
||||||
|
() => {
|
||||||
const rectLeft = UI.createElement("rectangle", {
|
const rectLeft = UI.createElement("rectangle", {
|
||||||
x: 0,
|
x: 0,
|
||||||
width: 200,
|
width: 200,
|
||||||
|
@ -123,12 +133,13 @@ describe("element binding", () => {
|
||||||
mouse.up();
|
mouse.up();
|
||||||
expect(arrow.angle).toBeGreaterThan(0.7 * Math.PI);
|
expect(arrow.angle).toBeGreaterThan(0.7 * Math.PI);
|
||||||
expect(arrow.angle).toBeLessThan(1.3 * Math.PI);
|
expect(arrow.angle).toBeLessThan(1.3 * Math.PI);
|
||||||
expect(arrow.startBinding?.elementId).toBe(rectRight.id);
|
expect(arrow.startBinding).toBe(null);
|
||||||
expect(arrow.endBinding?.elementId).toBe(rectLeft.id);
|
expect(arrow.endBinding).toBe(null);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// TODO fix & reenable once we rewrite tests to work with concurrency
|
// TODO fix & reenable once we rewrite tests to work with concurrency
|
||||||
it.skip(
|
it(
|
||||||
"editing arrow and moving its head to bind it to element A, finalizing the" +
|
"editing arrow and moving its head to bind it to element A, finalizing the" +
|
||||||
"editing by clicking on element A should end up selecting A",
|
"editing by clicking on element A should end up selecting A",
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -142,7 +153,10 @@ describe("element binding", () => {
|
||||||
mouse.up(0, 80);
|
mouse.up(0, 80);
|
||||||
|
|
||||||
// Edit arrow with multi-point
|
// Edit arrow with multi-point
|
||||||
|
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
||||||
mouse.doubleClick();
|
mouse.doubleClick();
|
||||||
|
});
|
||||||
|
|
||||||
// move arrow head
|
// move arrow head
|
||||||
mouse.down();
|
mouse.down();
|
||||||
mouse.up(0, 10);
|
mouse.up(0, 10);
|
||||||
|
@ -152,11 +166,7 @@ describe("element binding", () => {
|
||||||
// the issue, due to https://github.com/excalidraw/excalidraw/blob/46bff3daceb602accf60c40a84610797260fca94/src/components/App.tsx#L740
|
// the issue, due to https://github.com/excalidraw/excalidraw/blob/46bff3daceb602accf60c40a84610797260fca94/src/components/App.tsx#L740
|
||||||
mouse.reset();
|
mouse.reset();
|
||||||
expect(h.state.editingLinearElement).not.toBe(null);
|
expect(h.state.editingLinearElement).not.toBe(null);
|
||||||
mouse.down(0, 0);
|
mouse.click();
|
||||||
await new Promise((r) => setTimeout(r, 100));
|
|
||||||
expect(h.state.editingLinearElement).toBe(null);
|
|
||||||
expect(API.getSelectedElement().type).toBe("rectangle");
|
|
||||||
mouse.up();
|
|
||||||
expect(API.getSelectedElement().type).toBe("rectangle");
|
expect(API.getSelectedElement().type).toBe("rectangle");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -187,23 +197,24 @@ describe("element binding", () => {
|
||||||
expect(arrow.endBinding?.elementId).toBe(rectangle.id);
|
expect(arrow.endBinding?.elementId).toBe(rectangle.id);
|
||||||
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
||||||
expect(arrow.endBinding?.elementId).toBe(rectangle.id);
|
expect(arrow.endBinding?.elementId).toBe(rectangle.id);
|
||||||
|
expect(API.getSelectedElement().type).toBe("arrow");
|
||||||
|
|
||||||
// Sever connection
|
// Sever connection
|
||||||
expect(API.getSelectedElement().type).toBe("arrow");
|
|
||||||
Keyboard.withModifierKeys({ shift: true }, () => {
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
// We have to move a significant distance to get out of the binding zone
|
// We have to move a significant distance to get out of the binding zone
|
||||||
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
Array.from({ length: 10 }).forEach(() => {
|
||||||
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
|
||||||
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
|
||||||
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
|
||||||
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
|
||||||
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
|
||||||
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
|
||||||
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
|
||||||
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
expect(arrow.endBinding).toBe(null);
|
expect(arrow.endBinding).toBe(null);
|
||||||
|
|
||||||
|
Keyboard.withModifierKeys({ shift: true }, () => {
|
||||||
|
// We have to move a significant distance to return to the binding
|
||||||
|
Array.from({ length: 10 }).forEach(() => {
|
||||||
Keyboard.keyPress(KEYS.ARROW_RIGHT);
|
Keyboard.keyPress(KEYS.ARROW_RIGHT);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// We are back in the binding zone but we shouldn't rebind
|
||||||
expect(arrow.endBinding).toBe(null);
|
expect(arrow.endBinding).toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,14 @@ import {
|
||||||
|
|
||||||
import { Excalidraw } from "@excalidraw/excalidraw";
|
import { Excalidraw } from "@excalidraw/excalidraw";
|
||||||
|
|
||||||
import { actionDuplicateSelection } from "@excalidraw/excalidraw/actions";
|
import {
|
||||||
|
actionDuplicateSelection,
|
||||||
|
actionSelectAll,
|
||||||
|
} from "@excalidraw/excalidraw/actions";
|
||||||
|
|
||||||
import { API } from "@excalidraw/excalidraw/tests/helpers/api";
|
import { API } from "@excalidraw/excalidraw/tests/helpers/api";
|
||||||
|
|
||||||
import { Keyboard, Pointer } from "@excalidraw/excalidraw/tests/helpers/ui";
|
import { Keyboard, Pointer, UI } from "@excalidraw/excalidraw/tests/helpers/ui";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
act,
|
act,
|
||||||
|
@ -28,7 +31,10 @@ import type { LocalPoint } from "@excalidraw/math";
|
||||||
import { mutateElement } from "../src/mutateElement";
|
import { mutateElement } from "../src/mutateElement";
|
||||||
import { duplicateElement, duplicateElements } from "../src/duplicate";
|
import { duplicateElement, duplicateElements } from "../src/duplicate";
|
||||||
|
|
||||||
import type { ExcalidrawLinearElement } from "../src/types";
|
import type {
|
||||||
|
ExcalidrawArrowElement,
|
||||||
|
ExcalidrawLinearElement,
|
||||||
|
} from "../src/types";
|
||||||
|
|
||||||
const { h } = window;
|
const { h } = window;
|
||||||
const mouse = new Pointer("mouse");
|
const mouse = new Pointer("mouse");
|
||||||
|
@ -408,6 +414,122 @@ describe("duplicating multiple elements", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("elbow arrow duplication", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await render(<Excalidraw />);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps arrow shape when the whole set of arrow and bindables are duplicated", async () => {
|
||||||
|
UI.createElement("rectangle", {
|
||||||
|
x: -150,
|
||||||
|
y: -150,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
});
|
||||||
|
UI.createElement("rectangle", {
|
||||||
|
x: 50,
|
||||||
|
y: 50,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
UI.clickTool("arrow");
|
||||||
|
UI.clickOnTestId("elbow-arrow");
|
||||||
|
|
||||||
|
mouse.reset();
|
||||||
|
mouse.moveTo(-43, -99);
|
||||||
|
mouse.click();
|
||||||
|
mouse.moveTo(43, 99);
|
||||||
|
mouse.click();
|
||||||
|
|
||||||
|
const arrow = h.scene.getSelectedElements(
|
||||||
|
h.state,
|
||||||
|
)[0] as ExcalidrawArrowElement;
|
||||||
|
const originalArrowId = arrow.id;
|
||||||
|
|
||||||
|
expect(arrow.startBinding).not.toBe(null);
|
||||||
|
expect(arrow.endBinding).not.toBe(null);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
h.app.actionManager.executeAction(actionSelectAll);
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
h.app.actionManager.executeAction(actionDuplicateSelection);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(h.elements.length).toEqual(6);
|
||||||
|
|
||||||
|
const duplicatedArrow = h.scene.getSelectedElements(
|
||||||
|
h.state,
|
||||||
|
)[2] as ExcalidrawArrowElement;
|
||||||
|
|
||||||
|
expect(duplicatedArrow.id).not.toBe(originalArrowId);
|
||||||
|
expect(duplicatedArrow.type).toBe("arrow");
|
||||||
|
expect(duplicatedArrow.elbowed).toBe(true);
|
||||||
|
expect(duplicatedArrow.points).toEqual([
|
||||||
|
[0, 0],
|
||||||
|
[45, 0],
|
||||||
|
[45, 200],
|
||||||
|
[90, 200],
|
||||||
|
]);
|
||||||
|
expect(arrow.startBinding).not.toBe(null);
|
||||||
|
expect(arrow.endBinding).not.toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("changes arrow shape to unbind variant if only the connected elbow arrow is duplicated", async () => {
|
||||||
|
UI.createElement("rectangle", {
|
||||||
|
x: -150,
|
||||||
|
y: -150,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
});
|
||||||
|
UI.createElement("rectangle", {
|
||||||
|
x: 50,
|
||||||
|
y: 50,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
UI.clickTool("arrow");
|
||||||
|
UI.clickOnTestId("elbow-arrow");
|
||||||
|
|
||||||
|
mouse.reset();
|
||||||
|
mouse.moveTo(-43, -99);
|
||||||
|
mouse.click();
|
||||||
|
mouse.moveTo(43, 99);
|
||||||
|
mouse.click();
|
||||||
|
|
||||||
|
const arrow = h.scene.getSelectedElements(
|
||||||
|
h.state,
|
||||||
|
)[0] as ExcalidrawArrowElement;
|
||||||
|
const originalArrowId = arrow.id;
|
||||||
|
|
||||||
|
expect(arrow.startBinding).not.toBe(null);
|
||||||
|
expect(arrow.endBinding).not.toBe(null);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
h.app.actionManager.executeAction(actionDuplicateSelection);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(h.elements.length).toEqual(4);
|
||||||
|
|
||||||
|
const duplicatedArrow = h.scene.getSelectedElements(
|
||||||
|
h.state,
|
||||||
|
)[0] as ExcalidrawArrowElement;
|
||||||
|
|
||||||
|
expect(duplicatedArrow.id).not.toBe(originalArrowId);
|
||||||
|
expect(duplicatedArrow.type).toBe("arrow");
|
||||||
|
expect(duplicatedArrow.elbowed).toBe(true);
|
||||||
|
expect(duplicatedArrow.points).toEqual([
|
||||||
|
[0, 0],
|
||||||
|
[0, 100],
|
||||||
|
[90, 100],
|
||||||
|
[90, 200],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("duplication z-order", () => {
|
describe("duplication z-order", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await render(<Excalidraw />);
|
await render(<Excalidraw />);
|
||||||
|
|
|
@ -3,14 +3,11 @@ import { pointFrom } from "@excalidraw/math";
|
||||||
import { Excalidraw, mutateElement } from "@excalidraw/excalidraw";
|
import { Excalidraw, mutateElement } from "@excalidraw/excalidraw";
|
||||||
|
|
||||||
import Scene from "@excalidraw/excalidraw/scene/Scene";
|
import Scene from "@excalidraw/excalidraw/scene/Scene";
|
||||||
import { actionSelectAll } from "@excalidraw/excalidraw/actions";
|
|
||||||
import { actionDuplicateSelection } from "@excalidraw/excalidraw/actions/actionDuplicateSelection";
|
|
||||||
|
|
||||||
import { API } from "@excalidraw/excalidraw/tests/helpers/api";
|
import { API } from "@excalidraw/excalidraw/tests/helpers/api";
|
||||||
import { Pointer, UI } from "@excalidraw/excalidraw/tests/helpers/ui";
|
import { Pointer, UI } from "@excalidraw/excalidraw/tests/helpers/ui";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
act,
|
|
||||||
fireEvent,
|
fireEvent,
|
||||||
GlobalTestState,
|
GlobalTestState,
|
||||||
queryByTestId,
|
queryByTestId,
|
||||||
|
@ -301,114 +298,4 @@ describe("elbow arrow ui", () => {
|
||||||
[103, 165],
|
[103, 165],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps arrow shape when the whole set of arrow and bindables are duplicated", async () => {
|
|
||||||
UI.createElement("rectangle", {
|
|
||||||
x: -150,
|
|
||||||
y: -150,
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
});
|
|
||||||
UI.createElement("rectangle", {
|
|
||||||
x: 50,
|
|
||||||
y: 50,
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
});
|
|
||||||
|
|
||||||
UI.clickTool("arrow");
|
|
||||||
UI.clickOnTestId("elbow-arrow");
|
|
||||||
|
|
||||||
mouse.reset();
|
|
||||||
mouse.moveTo(-43, -99);
|
|
||||||
mouse.click();
|
|
||||||
mouse.moveTo(43, 99);
|
|
||||||
mouse.click();
|
|
||||||
|
|
||||||
const arrow = h.scene.getSelectedElements(
|
|
||||||
h.state,
|
|
||||||
)[0] as ExcalidrawArrowElement;
|
|
||||||
const originalArrowId = arrow.id;
|
|
||||||
|
|
||||||
expect(arrow.startBinding).not.toBe(null);
|
|
||||||
expect(arrow.endBinding).not.toBe(null);
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
h.app.actionManager.executeAction(actionSelectAll);
|
|
||||||
});
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
h.app.actionManager.executeAction(actionDuplicateSelection);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(h.elements.length).toEqual(6);
|
|
||||||
|
|
||||||
const duplicatedArrow = h.scene.getSelectedElements(
|
|
||||||
h.state,
|
|
||||||
)[2] as ExcalidrawArrowElement;
|
|
||||||
|
|
||||||
expect(duplicatedArrow.id).not.toBe(originalArrowId);
|
|
||||||
expect(duplicatedArrow.type).toBe("arrow");
|
|
||||||
expect(duplicatedArrow.elbowed).toBe(true);
|
|
||||||
expect(duplicatedArrow.points).toEqual([
|
|
||||||
[0, 0],
|
|
||||||
[45, 0],
|
|
||||||
[45, 200],
|
|
||||||
[90, 200],
|
|
||||||
]);
|
|
||||||
expect(arrow.startBinding).not.toBe(null);
|
|
||||||
expect(arrow.endBinding).not.toBe(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("changes arrow shape to unbind variant if only the connected elbow arrow is duplicated", async () => {
|
|
||||||
UI.createElement("rectangle", {
|
|
||||||
x: -150,
|
|
||||||
y: -150,
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
});
|
|
||||||
UI.createElement("rectangle", {
|
|
||||||
x: 50,
|
|
||||||
y: 50,
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
});
|
|
||||||
|
|
||||||
UI.clickTool("arrow");
|
|
||||||
UI.clickOnTestId("elbow-arrow");
|
|
||||||
|
|
||||||
mouse.reset();
|
|
||||||
mouse.moveTo(-43, -99);
|
|
||||||
mouse.click();
|
|
||||||
mouse.moveTo(43, 99);
|
|
||||||
mouse.click();
|
|
||||||
|
|
||||||
const arrow = h.scene.getSelectedElements(
|
|
||||||
h.state,
|
|
||||||
)[0] as ExcalidrawArrowElement;
|
|
||||||
const originalArrowId = arrow.id;
|
|
||||||
|
|
||||||
expect(arrow.startBinding).not.toBe(null);
|
|
||||||
expect(arrow.endBinding).not.toBe(null);
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
h.app.actionManager.executeAction(actionDuplicateSelection);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(h.elements.length).toEqual(4);
|
|
||||||
|
|
||||||
const duplicatedArrow = h.scene.getSelectedElements(
|
|
||||||
h.state,
|
|
||||||
)[0] as ExcalidrawArrowElement;
|
|
||||||
|
|
||||||
expect(duplicatedArrow.id).not.toBe(originalArrowId);
|
|
||||||
expect(duplicatedArrow.type).toBe("arrow");
|
|
||||||
expect(duplicatedArrow.elbowed).toBe(true);
|
|
||||||
expect(duplicatedArrow.points).toEqual([
|
|
||||||
[0, 0],
|
|
||||||
[0, 100],
|
|
||||||
[90, 100],
|
|
||||||
[90, 200],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,6 +15,8 @@ import {
|
||||||
unmountComponent,
|
unmountComponent,
|
||||||
} from "@excalidraw/excalidraw/tests/test-utils";
|
} from "@excalidraw/excalidraw/tests/test-utils";
|
||||||
|
|
||||||
|
import { FIXED_BINDING_DISTANCE } from "@excalidraw/element/binding";
|
||||||
|
|
||||||
import type { LocalPoint } from "@excalidraw/math";
|
import type { LocalPoint } from "@excalidraw/math";
|
||||||
|
|
||||||
import { isLinearElement } from "../src/typeChecks";
|
import { isLinearElement } from "../src/typeChecks";
|
||||||
|
@ -1004,14 +1006,14 @@ describe("multiple selection", () => {
|
||||||
size: 100,
|
size: 100,
|
||||||
});
|
});
|
||||||
const leftBoundArrow = UI.createElement("arrow", {
|
const leftBoundArrow = UI.createElement("arrow", {
|
||||||
x: -110,
|
x: -100 - FIXED_BINDING_DISTANCE,
|
||||||
y: 50,
|
y: 50,
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 0,
|
height: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const rightBoundArrow = UI.createElement("arrow", {
|
const rightBoundArrow = UI.createElement("arrow", {
|
||||||
x: 210,
|
x: 200 + FIXED_BINDING_DISTANCE,
|
||||||
y: 50,
|
y: 50,
|
||||||
width: -100,
|
width: -100,
|
||||||
height: 0,
|
height: 0,
|
||||||
|
@ -1032,9 +1034,9 @@ describe("multiple selection", () => {
|
||||||
shift: true,
|
shift: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(leftBoundArrow.x).toBeCloseTo(-110);
|
expect(leftBoundArrow.x).toBeCloseTo(-100 - FIXED_BINDING_DISTANCE);
|
||||||
expect(leftBoundArrow.y).toBeCloseTo(50);
|
expect(leftBoundArrow.y).toBeCloseTo(50);
|
||||||
expect(leftBoundArrow.width).toBeCloseTo(146, 0);
|
expect(leftBoundArrow.width).toBeCloseTo(146 - FIXED_BINDING_DISTANCE, 0);
|
||||||
expect(leftBoundArrow.height).toBeCloseTo(7, 0);
|
expect(leftBoundArrow.height).toBeCloseTo(7, 0);
|
||||||
expect(leftBoundArrow.angle).toEqual(0);
|
expect(leftBoundArrow.angle).toEqual(0);
|
||||||
expect(leftBoundArrow.startBinding).toBeNull();
|
expect(leftBoundArrow.startBinding).toBeNull();
|
||||||
|
@ -1044,15 +1046,17 @@ describe("multiple selection", () => {
|
||||||
);
|
);
|
||||||
expect(leftBoundArrow.endBinding?.focus).toBe(leftArrowBinding.focus);
|
expect(leftBoundArrow.endBinding?.focus).toBe(leftArrowBinding.focus);
|
||||||
|
|
||||||
expect(rightBoundArrow.x).toBeCloseTo(210);
|
expect(rightBoundArrow.x).toBeCloseTo(210 - FIXED_BINDING_DISTANCE);
|
||||||
expect(rightBoundArrow.y).toBeCloseTo(
|
expect(rightBoundArrow.y).toBeCloseTo(
|
||||||
(selectionHeight - 50) * (1 - scale) + 50,
|
(selectionHeight - 50) * (1 - scale) + 50,
|
||||||
|
0,
|
||||||
);
|
);
|
||||||
expect(rightBoundArrow.width).toBeCloseTo(100 * scale);
|
//console.log(JSON.stringify(h.elements));
|
||||||
|
expect(rightBoundArrow.width).toBeCloseTo(100 * scale + 1, 0);
|
||||||
expect(rightBoundArrow.height).toBeCloseTo(0);
|
expect(rightBoundArrow.height).toBeCloseTo(0);
|
||||||
expect(rightBoundArrow.angle).toEqual(0);
|
expect(rightBoundArrow.angle).toEqual(0);
|
||||||
expect(rightBoundArrow.startBinding).toBeNull();
|
expect(rightBoundArrow.startBinding).toBeNull();
|
||||||
expect(rightBoundArrow.endBinding?.gap).toBeCloseTo(8.0952);
|
expect(rightBoundArrow.endBinding?.gap).toBeCloseTo(FIXED_BINDING_DISTANCE);
|
||||||
expect(rightBoundArrow.endBinding?.elementId).toBe(
|
expect(rightBoundArrow.endBinding?.elementId).toBe(
|
||||||
rightArrowBinding.elementId,
|
rightArrowBinding.elementId,
|
||||||
);
|
);
|
||||||
|
@ -1339,8 +1343,8 @@ describe("multiple selection", () => {
|
||||||
|
|
||||||
expect(boundArrow.x).toBeCloseTo(380 * scaleX);
|
expect(boundArrow.x).toBeCloseTo(380 * scaleX);
|
||||||
expect(boundArrow.y).toBeCloseTo(240 * scaleY);
|
expect(boundArrow.y).toBeCloseTo(240 * scaleY);
|
||||||
expect(boundArrow.points[1][0]).toBeCloseTo(-60 * scaleX);
|
expect(boundArrow.points[1][0]).toBeCloseTo(-60 * scaleX - 2, 0);
|
||||||
expect(boundArrow.points[1][1]).toBeCloseTo(-80 * scaleY);
|
expect(boundArrow.points[1][1]).toBeCloseTo(-80 * scaleY + 2, 0);
|
||||||
|
|
||||||
expect(arrowLabelPos.x + arrowLabel.width / 2).toBeCloseTo(
|
expect(arrowLabelPos.x + arrowLabel.width / 2).toBeCloseTo(
|
||||||
boundArrow.x + boundArrow.points[1][0] / 2,
|
boundArrow.x + boundArrow.points[1][0] / 2,
|
||||||
|
|
|
@ -87,6 +87,16 @@ describe("flipping arrowheads", () => {
|
||||||
await render(<Excalidraw />);
|
await render(<Excalidraw />);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// UX RATIONALE: If we flip bound arrows by the center axes then there could
|
||||||
|
// be a case where the bindable objects are offset and the arrow would lay
|
||||||
|
// outside both bindable objects binding range, yet remain bound to then,
|
||||||
|
// resulting in a jump on movement.
|
||||||
|
//
|
||||||
|
// We are aware that 2+ point simple arrows behave incorrectly when flipped
|
||||||
|
// this way but it was decided that there is no known use case for this so
|
||||||
|
// left as it is.
|
||||||
|
//
|
||||||
|
// Demo: https://excalidraw.com/#json=isE-S8LqNlD1u-LsS8Ezz,iZZ09PPasp6OWbGtJwOUGQ
|
||||||
it("flipping bound arrow should flip arrowheads only", () => {
|
it("flipping bound arrow should flip arrowheads only", () => {
|
||||||
const rect = API.createElement({
|
const rect = API.createElement({
|
||||||
type: "rectangle",
|
type: "rectangle",
|
||||||
|
@ -123,6 +133,7 @@ describe("flipping arrowheads", () => {
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe("arrow");
|
expect(API.getElement(arrow).endArrowhead).toBe("arrow");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// UX RATIONALE: See above for the reasoning.
|
||||||
it("flipping bound arrow should flip arrowheads only 2", () => {
|
it("flipping bound arrow should flip arrowheads only 2", () => {
|
||||||
const rect = API.createElement({
|
const rect = API.createElement({
|
||||||
type: "rectangle",
|
type: "rectangle",
|
||||||
|
@ -164,7 +175,9 @@ describe("flipping arrowheads", () => {
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe("circle");
|
expect(API.getElement(arrow).endArrowhead).toBe("circle");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("flipping unbound arrow shouldn't flip arrowheads", () => {
|
// UX RATIONALE: Unbound arrows are not constrained by other elements and
|
||||||
|
// should behave like any other element when flipped for consisency.
|
||||||
|
it("flipping unbound arrow should mirror on horizontal or vertical axis", () => {
|
||||||
const arrow = API.createElement({
|
const arrow = API.createElement({
|
||||||
type: "arrow",
|
type: "arrow",
|
||||||
id: "arrow1",
|
id: "arrow1",
|
||||||
|
|
|
@ -197,7 +197,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": "99.58947",
|
"height": "99.23572",
|
||||||
"id": "id172",
|
"id": "id172",
|
||||||
"index": "a2",
|
"index": "a2",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
|
@ -211,8 +211,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"99.58947",
|
"96.42891",
|
||||||
"99.58947",
|
"99.23572",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
@ -227,8 +227,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 40,
|
"version": 40,
|
||||||
"width": "99.58947",
|
"width": "96.42891",
|
||||||
"x": 0,
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -294,10 +294,10 @@ History {
|
||||||
"deleted": {
|
"deleted": {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id171",
|
"elementId": "id171",
|
||||||
"focus": "0.01099",
|
"focus": "0.01140",
|
||||||
"gap": 5,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"height": "0.96335",
|
"height": "1.00000",
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0,
|
0,
|
||||||
|
@ -305,22 +305,22 @@ History {
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"92.92893",
|
"92.92893",
|
||||||
"-0.96335",
|
"-1.00000",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id170",
|
"elementId": "id170",
|
||||||
"focus": "0.03005",
|
"focus": "0.03119",
|
||||||
"gap": 5,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id171",
|
"elementId": "id171",
|
||||||
"focus": "-0.02041",
|
"focus": "-0.02000",
|
||||||
"gap": 5,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"height": "0.03665",
|
"height": 0,
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0,
|
0,
|
||||||
|
@ -328,12 +328,12 @@ History {
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"92.92893",
|
"92.92893",
|
||||||
"0.03665",
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id170",
|
"elementId": "id170",
|
||||||
"focus": "0.01884",
|
"focus": "0.02000",
|
||||||
"gap": 5,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -389,29 +389,27 @@ History {
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 1,
|
"gap": 1,
|
||||||
},
|
},
|
||||||
"height": "99.58947",
|
"height": "99.23572",
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"99.58947",
|
"96.42891",
|
||||||
"99.58947",
|
"99.23572",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
"width": "99.58947",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
"elementId": "id171",
|
"elementId": "id171",
|
||||||
"focus": "0.01099",
|
"focus": "0.01140",
|
||||||
"gap": 5,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"height": "0.96335",
|
"height": "1.00000",
|
||||||
"points": [
|
"points": [
|
||||||
[
|
[
|
||||||
0,
|
0,
|
||||||
|
@ -419,17 +417,15 @@ History {
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"92.92893",
|
"92.92893",
|
||||||
"-0.96335",
|
"-1.00000",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": {
|
"startBinding": {
|
||||||
"elementId": "id170",
|
"elementId": "id170",
|
||||||
"focus": "0.03005",
|
"focus": "0.03119",
|
||||||
"gap": 5,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"width": "92.92893",
|
"y": "1.00000",
|
||||||
"x": "3.53553",
|
|
||||||
"y": "0.96335",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"id175" => Delta {
|
"id175" => Delta {
|
||||||
|
@ -569,7 +565,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -583,8 +579,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": "96.46447",
|
"width": "92.92893",
|
||||||
"x": 0,
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -806,7 +802,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -822,8 +818,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 30,
|
"version": 30,
|
||||||
"width": "96.46447",
|
"width": "0.00000",
|
||||||
"x": 150,
|
"x": "146.46447",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -923,13 +919,11 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"startBinding": null,
|
"startBinding": null,
|
||||||
"width": "96.46447",
|
|
||||||
"x": 150,
|
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
"endBinding": {
|
"endBinding": {
|
||||||
|
@ -952,8 +946,6 @@ History {
|
||||||
"focus": 0,
|
"focus": 0,
|
||||||
"gap": 5,
|
"gap": 5,
|
||||||
},
|
},
|
||||||
"width": "0.00000",
|
|
||||||
"x": "146.46447",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1080,7 +1072,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -1094,8 +1086,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": "96.46447",
|
"width": "92.92893",
|
||||||
"x": 0,
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -2328,7 +2320,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"fillStyle": "solid",
|
"fillStyle": "solid",
|
||||||
"frameId": null,
|
"frameId": null,
|
||||||
"groupIds": [],
|
"groupIds": [],
|
||||||
"height": "369.21589",
|
"height": "369.23631",
|
||||||
"id": "id186",
|
"id": "id186",
|
||||||
"index": "a2",
|
"index": "a2",
|
||||||
"isDeleted": false,
|
"isDeleted": false,
|
||||||
|
@ -2342,8 +2334,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"496.84035",
|
"496.83418",
|
||||||
"-369.21589",
|
"-369.23631",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
"roughness": 1,
|
"roughness": 1,
|
||||||
|
@ -2362,9 +2354,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"updated": 1,
|
"updated": 1,
|
||||||
"version": 10,
|
"version": 10,
|
||||||
"width": "496.84035",
|
"width": "496.83418",
|
||||||
"x": "2.18463",
|
"x": "2.19080",
|
||||||
"y": "-38.80748",
|
"y": "-38.78706",
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -2501,7 +2493,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -2519,8 +2511,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": "96.46447",
|
"width": "92.92893",
|
||||||
"x": 0,
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -15200,7 +15192,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -15213,7 +15205,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -15508,7 +15500,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -15526,8 +15518,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": "96.46447",
|
"width": "92.92893",
|
||||||
"x": 0,
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -16127,7 +16119,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -16145,8 +16137,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": "96.46447",
|
"width": "92.92893",
|
||||||
"x": 0,
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -16746,7 +16738,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -16764,8 +16756,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": "96.46447",
|
"width": "92.92893",
|
||||||
"x": 0,
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -17148,7 +17140,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -17165,7 +17157,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -17433,7 +17425,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -17451,8 +17443,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": "96.46447",
|
"width": "92.92893",
|
||||||
"x": 0,
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
@ -17875,7 +17867,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -17893,7 +17885,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -18161,7 +18153,7 @@ History {
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"96.46447",
|
"92.92893",
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -18179,8 +18171,8 @@ History {
|
||||||
"strokeStyle": "solid",
|
"strokeStyle": "solid",
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
"type": "arrow",
|
"type": "arrow",
|
||||||
"width": "96.46447",
|
"width": "92.92893",
|
||||||
"x": 0,
|
"x": "3.53553",
|
||||||
"y": 0,
|
"y": 0,
|
||||||
},
|
},
|
||||||
"inserted": {
|
"inserted": {
|
||||||
|
|
|
@ -101,3 +101,139 @@ exports[`move element > rectangle 5`] = `
|
||||||
"y": 40,
|
"y": 40,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`move element > rectangles with binding arrow 5`] = `
|
||||||
|
{
|
||||||
|
"angle": 0,
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"id": "id2",
|
||||||
|
"type": "arrow",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"customData": undefined,
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"frameId": null,
|
||||||
|
"groupIds": [],
|
||||||
|
"height": 100,
|
||||||
|
"id": "id0",
|
||||||
|
"index": "a0",
|
||||||
|
"isDeleted": false,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"opacity": 100,
|
||||||
|
"roughness": 1,
|
||||||
|
"roundness": {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
|
"seed": 1278240551,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"type": "rectangle",
|
||||||
|
"updated": 1,
|
||||||
|
"version": 4,
|
||||||
|
"versionNonce": 1723083209,
|
||||||
|
"width": 100,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`move element > rectangles with binding arrow 6`] = `
|
||||||
|
{
|
||||||
|
"angle": 0,
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"id": "id2",
|
||||||
|
"type": "arrow",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"customData": undefined,
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"frameId": null,
|
||||||
|
"groupIds": [],
|
||||||
|
"height": 300,
|
||||||
|
"id": "id1",
|
||||||
|
"index": "a1",
|
||||||
|
"isDeleted": false,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"opacity": 100,
|
||||||
|
"roughness": 1,
|
||||||
|
"roundness": {
|
||||||
|
"type": 3,
|
||||||
|
},
|
||||||
|
"seed": 1150084233,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"type": "rectangle",
|
||||||
|
"updated": 1,
|
||||||
|
"version": 7,
|
||||||
|
"versionNonce": 745419401,
|
||||||
|
"width": 300,
|
||||||
|
"x": 201,
|
||||||
|
"y": 2,
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`move element > rectangles with binding arrow 7`] = `
|
||||||
|
{
|
||||||
|
"angle": 0,
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"boundElements": null,
|
||||||
|
"customData": undefined,
|
||||||
|
"elbowed": false,
|
||||||
|
"endArrowhead": "arrow",
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "id1",
|
||||||
|
"focus": "-0.40764",
|
||||||
|
"gap": 5,
|
||||||
|
},
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"frameId": null,
|
||||||
|
"groupIds": [],
|
||||||
|
"height": "82.18136",
|
||||||
|
"id": "id2",
|
||||||
|
"index": "a2",
|
||||||
|
"isDeleted": false,
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"opacity": 100,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"93.92893",
|
||||||
|
"82.18136",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
"roughness": 1,
|
||||||
|
"roundness": {
|
||||||
|
"type": 2,
|
||||||
|
},
|
||||||
|
"seed": 1604849351,
|
||||||
|
"startArrowhead": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "id0",
|
||||||
|
"focus": "-0.49801",
|
||||||
|
"gap": 5,
|
||||||
|
},
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"type": "arrow",
|
||||||
|
"updated": 1,
|
||||||
|
"version": 11,
|
||||||
|
"versionNonce": 1051383431,
|
||||||
|
"width": "93.92893",
|
||||||
|
"x": "103.53553",
|
||||||
|
"y": "50.01536",
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
|
@ -109,8 +109,10 @@ describe("move element", () => {
|
||||||
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
|
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
|
||||||
expect([rectA.x, rectA.y]).toEqual([0, 0]);
|
expect([rectA.x, rectA.y]).toEqual([0, 0]);
|
||||||
expect([rectB.x, rectB.y]).toEqual([200, 0]);
|
expect([rectB.x, rectB.y]).toEqual([200, 0]);
|
||||||
expect([arrow.x, arrow.y]).toEqual([110, 50]);
|
expect([Math.round(arrow.x), Math.round(arrow.y)]).toEqual([104, 50]);
|
||||||
expect([arrow.width, arrow.height]).toEqual([80, 80]);
|
expect([Math.round(arrow.width), Math.round(arrow.height)]).toEqual([
|
||||||
|
93, 81,
|
||||||
|
]);
|
||||||
|
|
||||||
renderInteractiveScene.mockClear();
|
renderInteractiveScene.mockClear();
|
||||||
renderStaticScene.mockClear();
|
renderStaticScene.mockClear();
|
||||||
|
@ -128,8 +130,11 @@ describe("move element", () => {
|
||||||
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
|
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
|
||||||
expect([rectA.x, rectA.y]).toEqual([0, 0]);
|
expect([rectA.x, rectA.y]).toEqual([0, 0]);
|
||||||
expect([rectB.x, rectB.y]).toEqual([201, 2]);
|
expect([rectB.x, rectB.y]).toEqual([201, 2]);
|
||||||
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[107.07, 47.07]]);
|
|
||||||
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints([[86.86, 87.3]]);
|
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints([[103.53, 50.01]]);
|
||||||
|
expect([[arrow.width, arrow.height]]).toCloselyEqualPoints([
|
||||||
|
[93.9289, 82.1813],
|
||||||
|
]);
|
||||||
|
|
||||||
h.elements.forEach((element) => expect(element).toMatchSnapshot());
|
h.elements.forEach((element) => expect(element).toMatchSnapshot());
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { expect } from "vitest";
|
||||||
|
|
||||||
import { reseed } from "@excalidraw/common";
|
import { reseed } from "@excalidraw/common";
|
||||||
|
|
||||||
|
import "@excalidraw/utils/test-utils";
|
||||||
|
|
||||||
import { Excalidraw } from "../index";
|
import { Excalidraw } from "../index";
|
||||||
|
|
||||||
import { UI } from "./helpers/ui";
|
import { UI } from "./helpers/ui";
|
||||||
|
@ -71,14 +73,16 @@ test("unselected bound arrows update when rotating their target elements", async
|
||||||
expect(ellipseArrow.endBinding?.elementId).toEqual(ellipse.id);
|
expect(ellipseArrow.endBinding?.elementId).toEqual(ellipse.id);
|
||||||
expect(ellipseArrow.x).toEqual(0);
|
expect(ellipseArrow.x).toEqual(0);
|
||||||
expect(ellipseArrow.y).toEqual(0);
|
expect(ellipseArrow.y).toEqual(0);
|
||||||
expect(ellipseArrow.points[0]).toEqual([0, 0]);
|
|
||||||
expect(ellipseArrow.points[1][0]).toBeCloseTo(48.98, 1);
|
expect(ellipseArrow.points).toCloselyEqualPoints([
|
||||||
expect(ellipseArrow.points[1][1]).toBeCloseTo(125.79, 1);
|
[0, 0],
|
||||||
|
[90.1827, 98.5896],
|
||||||
|
]);
|
||||||
|
|
||||||
expect(textArrow.endBinding?.elementId).toEqual(text.id);
|
expect(textArrow.endBinding?.elementId).toEqual(text.id);
|
||||||
expect(textArrow.x).toEqual(360);
|
expect(textArrow.x).toEqual(360);
|
||||||
expect(textArrow.y).toEqual(300);
|
expect(textArrow.y).toEqual(300);
|
||||||
expect(textArrow.points[0]).toEqual([0, 0]);
|
expect(textArrow.points[0]).toEqual([0, 0]);
|
||||||
expect(textArrow.points[1][0]).toBeCloseTo(-94, 0);
|
expect(textArrow.points[1][0]).toBeCloseTo(-95, 0);
|
||||||
expect(textArrow.points[1][1]).toBeCloseTo(-116.1, 0);
|
expect(textArrow.points[1][1]).toBeCloseTo(-129.1, 0);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue