selection.test.tsx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import React from "react";
  2. import ReactDOM from "react-dom";
  3. import { render, fireEvent } from "./test-utils";
  4. import ExcalidrawApp from "../excalidraw-app";
  5. import * as Renderer from "../renderer/renderScene";
  6. import { KEYS } from "../keys";
  7. import { reseed } from "../random";
  8. // Unmount ReactDOM from root
  9. ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
  10. const renderScene = jest.spyOn(Renderer, "renderScene");
  11. beforeEach(() => {
  12. localStorage.clear();
  13. renderScene.mockClear();
  14. reseed(7);
  15. });
  16. const { h } = window;
  17. describe("selection element", () => {
  18. it("create selection element on pointer down", async () => {
  19. const { getByToolName, container } = await render(<ExcalidrawApp />);
  20. // select tool
  21. const tool = getByToolName("selection");
  22. fireEvent.click(tool);
  23. const canvas = container.querySelector("canvas")!;
  24. fireEvent.pointerDown(canvas, { clientX: 60, clientY: 100 });
  25. expect(renderScene).toHaveBeenCalledTimes(3);
  26. const selectionElement = h.state.selectionElement!;
  27. expect(selectionElement).not.toBeNull();
  28. expect(selectionElement.type).toEqual("selection");
  29. expect([selectionElement.x, selectionElement.y]).toEqual([60, 100]);
  30. expect([selectionElement.width, selectionElement.height]).toEqual([0, 0]);
  31. // TODO: There is a memory leak if pointer up is not triggered
  32. fireEvent.pointerUp(canvas);
  33. });
  34. it("resize selection element on pointer move", async () => {
  35. const { getByToolName, container } = await render(<ExcalidrawApp />);
  36. // select tool
  37. const tool = getByToolName("selection");
  38. fireEvent.click(tool);
  39. const canvas = container.querySelector("canvas")!;
  40. fireEvent.pointerDown(canvas, { clientX: 60, clientY: 100 });
  41. fireEvent.pointerMove(canvas, { clientX: 150, clientY: 30 });
  42. expect(renderScene).toHaveBeenCalledTimes(4);
  43. const selectionElement = h.state.selectionElement!;
  44. expect(selectionElement).not.toBeNull();
  45. expect(selectionElement.type).toEqual("selection");
  46. expect([selectionElement.x, selectionElement.y]).toEqual([60, 30]);
  47. expect([selectionElement.width, selectionElement.height]).toEqual([90, 70]);
  48. // TODO: There is a memory leak if pointer up is not triggered
  49. fireEvent.pointerUp(canvas);
  50. });
  51. it("remove selection element on pointer up", async () => {
  52. const { getByToolName, container } = await render(<ExcalidrawApp />);
  53. // select tool
  54. const tool = getByToolName("selection");
  55. fireEvent.click(tool);
  56. const canvas = container.querySelector("canvas")!;
  57. fireEvent.pointerDown(canvas, { clientX: 60, clientY: 100 });
  58. fireEvent.pointerMove(canvas, { clientX: 150, clientY: 30 });
  59. fireEvent.pointerUp(canvas);
  60. expect(renderScene).toHaveBeenCalledTimes(5);
  61. expect(h.state.selectionElement).toBeNull();
  62. });
  63. });
  64. describe("select single element on the scene", () => {
  65. it("rectangle", async () => {
  66. const { getByToolName, container } = await render(<ExcalidrawApp />);
  67. const canvas = container.querySelector("canvas")!;
  68. {
  69. // create element
  70. const tool = getByToolName("rectangle");
  71. fireEvent.click(tool);
  72. fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
  73. fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 });
  74. fireEvent.pointerUp(canvas);
  75. fireEvent.keyDown(document, { key: KEYS.ESCAPE });
  76. }
  77. const tool = getByToolName("selection");
  78. fireEvent.click(tool);
  79. // click on a line on the rectangle
  80. fireEvent.pointerDown(canvas, { clientX: 45, clientY: 20 });
  81. fireEvent.pointerUp(canvas);
  82. expect(renderScene).toHaveBeenCalledTimes(9);
  83. expect(h.state.selectionElement).toBeNull();
  84. expect(h.elements.length).toEqual(1);
  85. expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
  86. h.elements.forEach((element) => expect(element).toMatchSnapshot());
  87. });
  88. it("diamond", async () => {
  89. const { getByToolName, container } = await render(<ExcalidrawApp />);
  90. const canvas = container.querySelector("canvas")!;
  91. {
  92. // create element
  93. const tool = getByToolName("diamond");
  94. fireEvent.click(tool);
  95. fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
  96. fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 });
  97. fireEvent.pointerUp(canvas);
  98. fireEvent.keyDown(document, { key: KEYS.ESCAPE });
  99. }
  100. const tool = getByToolName("selection");
  101. fireEvent.click(tool);
  102. // click on a line on the rectangle
  103. fireEvent.pointerDown(canvas, { clientX: 45, clientY: 20 });
  104. fireEvent.pointerUp(canvas);
  105. expect(renderScene).toHaveBeenCalledTimes(9);
  106. expect(h.state.selectionElement).toBeNull();
  107. expect(h.elements.length).toEqual(1);
  108. expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
  109. h.elements.forEach((element) => expect(element).toMatchSnapshot());
  110. });
  111. it("ellipse", async () => {
  112. const { getByToolName, container } = await render(<ExcalidrawApp />);
  113. const canvas = container.querySelector("canvas")!;
  114. {
  115. // create element
  116. const tool = getByToolName("ellipse");
  117. fireEvent.click(tool);
  118. fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
  119. fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 });
  120. fireEvent.pointerUp(canvas);
  121. fireEvent.keyDown(document, { key: KEYS.ESCAPE });
  122. }
  123. const tool = getByToolName("selection");
  124. fireEvent.click(tool);
  125. // click on a line on the rectangle
  126. fireEvent.pointerDown(canvas, { clientX: 45, clientY: 20 });
  127. fireEvent.pointerUp(canvas);
  128. expect(renderScene).toHaveBeenCalledTimes(9);
  129. expect(h.state.selectionElement).toBeNull();
  130. expect(h.elements.length).toEqual(1);
  131. expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
  132. h.elements.forEach((element) => expect(element).toMatchSnapshot());
  133. });
  134. it("arrow", async () => {
  135. const { getByToolName, container } = await render(<ExcalidrawApp />);
  136. const canvas = container.querySelector("canvas")!;
  137. {
  138. // create element
  139. const tool = getByToolName("arrow");
  140. fireEvent.click(tool);
  141. fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
  142. fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 });
  143. fireEvent.pointerUp(canvas);
  144. fireEvent.keyDown(document, { key: KEYS.ESCAPE });
  145. }
  146. /*
  147. 1 2 3 4 5 6 7 8 9
  148. 1
  149. 2 x
  150. 3
  151. 4 .
  152. 5
  153. 6
  154. 7 x
  155. 8
  156. 9
  157. */
  158. const tool = getByToolName("selection");
  159. fireEvent.click(tool);
  160. // click on a line on the arrow
  161. fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 });
  162. fireEvent.pointerUp(canvas);
  163. expect(renderScene).toHaveBeenCalledTimes(9);
  164. expect(h.state.selectionElement).toBeNull();
  165. expect(h.elements.length).toEqual(1);
  166. expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
  167. h.elements.forEach((element) => expect(element).toMatchSnapshot());
  168. });
  169. it("arrow escape", async () => {
  170. const { getByToolName, container } = await render(<ExcalidrawApp />);
  171. const canvas = container.querySelector("canvas")!;
  172. {
  173. // create element
  174. const tool = getByToolName("line");
  175. fireEvent.click(tool);
  176. fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
  177. fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 });
  178. fireEvent.pointerUp(canvas);
  179. fireEvent.keyDown(document, { key: KEYS.ESCAPE });
  180. }
  181. /*
  182. 1 2 3 4 5 6 7 8 9
  183. 1
  184. 2 x
  185. 3
  186. 4 .
  187. 5
  188. 6
  189. 7 x
  190. 8
  191. 9
  192. */
  193. const tool = getByToolName("selection");
  194. fireEvent.click(tool);
  195. // click on a line on the arrow
  196. fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 });
  197. fireEvent.pointerUp(canvas);
  198. expect(renderScene).toHaveBeenCalledTimes(9);
  199. expect(h.state.selectionElement).toBeNull();
  200. expect(h.elements.length).toEqual(1);
  201. expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
  202. h.elements.forEach((element) => expect(element).toMatchSnapshot());
  203. });
  204. });