align.test.tsx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. import ReactDOM from "react-dom";
  2. import { render } from "./test-utils";
  3. import ExcalidrawApp from "../excalidraw-app";
  4. import { defaultLang, setLanguage } from "../i18n";
  5. import { UI, Pointer, Keyboard } from "./helpers/ui";
  6. import { API } from "./helpers/api";
  7. import { KEYS } from "../keys";
  8. import {
  9. actionAlignVerticallyCentered,
  10. actionAlignHorizontallyCentered,
  11. actionGroup,
  12. actionAlignTop,
  13. actionAlignBottom,
  14. actionAlignLeft,
  15. actionAlignRight,
  16. } from "../actions";
  17. const { h } = window;
  18. const mouse = new Pointer("mouse");
  19. const createAndSelectTwoRectangles = () => {
  20. UI.clickTool("rectangle");
  21. mouse.down();
  22. mouse.up(100, 100);
  23. UI.clickTool("rectangle");
  24. mouse.down(10, 10);
  25. mouse.up(100, 100);
  26. // Select the first element.
  27. // The second rectangle is already reselected because it was the last element created
  28. mouse.reset();
  29. Keyboard.withModifierKeys({ shift: true }, () => {
  30. mouse.click();
  31. });
  32. };
  33. const createAndSelectTwoRectanglesWithDifferentSizes = () => {
  34. UI.clickTool("rectangle");
  35. mouse.down();
  36. mouse.up(100, 100);
  37. UI.clickTool("rectangle");
  38. mouse.down(10, 10);
  39. mouse.up(110, 110);
  40. // Select the first element.
  41. // The second rectangle is already reselected because it was the last element created
  42. mouse.reset();
  43. Keyboard.withModifierKeys({ shift: true }, () => {
  44. mouse.click();
  45. });
  46. };
  47. describe("aligning", () => {
  48. beforeEach(async () => {
  49. // Unmount ReactDOM from root
  50. ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
  51. mouse.reset();
  52. await setLanguage(defaultLang);
  53. await render(<ExcalidrawApp />);
  54. });
  55. it("aligns two objects correctly to the top", () => {
  56. createAndSelectTwoRectangles();
  57. expect(API.getSelectedElements()[0].x).toEqual(0);
  58. expect(API.getSelectedElements()[1].x).toEqual(110);
  59. expect(API.getSelectedElements()[0].y).toEqual(0);
  60. expect(API.getSelectedElements()[1].y).toEqual(110);
  61. Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
  62. Keyboard.keyPress(KEYS.ARROW_UP);
  63. });
  64. // Check if x position did not change
  65. expect(API.getSelectedElements()[0].x).toEqual(0);
  66. expect(API.getSelectedElements()[1].x).toEqual(110);
  67. expect(API.getSelectedElements()[0].y).toEqual(0);
  68. expect(API.getSelectedElements()[1].y).toEqual(0);
  69. });
  70. it("aligns two objects correctly to the bottom", () => {
  71. createAndSelectTwoRectangles();
  72. expect(API.getSelectedElements()[0].x).toEqual(0);
  73. expect(API.getSelectedElements()[1].x).toEqual(110);
  74. expect(API.getSelectedElements()[0].y).toEqual(0);
  75. expect(API.getSelectedElements()[1].y).toEqual(110);
  76. Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
  77. Keyboard.keyPress(KEYS.ARROW_DOWN);
  78. });
  79. // Check if x position did not change
  80. expect(API.getSelectedElements()[0].x).toEqual(0);
  81. expect(API.getSelectedElements()[1].x).toEqual(110);
  82. expect(API.getSelectedElements()[0].y).toEqual(110);
  83. expect(API.getSelectedElements()[1].y).toEqual(110);
  84. });
  85. it("aligns two objects correctly to the left", () => {
  86. createAndSelectTwoRectangles();
  87. expect(API.getSelectedElements()[0].x).toEqual(0);
  88. expect(API.getSelectedElements()[1].x).toEqual(110);
  89. expect(API.getSelectedElements()[0].y).toEqual(0);
  90. expect(API.getSelectedElements()[1].y).toEqual(110);
  91. Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
  92. Keyboard.keyPress(KEYS.ARROW_LEFT);
  93. });
  94. expect(API.getSelectedElements()[0].x).toEqual(0);
  95. expect(API.getSelectedElements()[1].x).toEqual(0);
  96. // Check if y position did not change
  97. expect(API.getSelectedElements()[0].y).toEqual(0);
  98. expect(API.getSelectedElements()[1].y).toEqual(110);
  99. });
  100. it("aligns two objects correctly to the right", () => {
  101. createAndSelectTwoRectangles();
  102. expect(API.getSelectedElements()[0].x).toEqual(0);
  103. expect(API.getSelectedElements()[1].x).toEqual(110);
  104. expect(API.getSelectedElements()[0].y).toEqual(0);
  105. expect(API.getSelectedElements()[1].y).toEqual(110);
  106. Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
  107. Keyboard.keyPress(KEYS.ARROW_RIGHT);
  108. });
  109. expect(API.getSelectedElements()[0].x).toEqual(110);
  110. expect(API.getSelectedElements()[1].x).toEqual(110);
  111. // Check if y position did not change
  112. expect(API.getSelectedElements()[0].y).toEqual(0);
  113. expect(API.getSelectedElements()[1].y).toEqual(110);
  114. });
  115. it("centers two objects with different sizes correctly vertically", () => {
  116. createAndSelectTwoRectanglesWithDifferentSizes();
  117. expect(API.getSelectedElements()[0].x).toEqual(0);
  118. expect(API.getSelectedElements()[1].x).toEqual(110);
  119. expect(API.getSelectedElements()[0].y).toEqual(0);
  120. expect(API.getSelectedElements()[1].y).toEqual(110);
  121. h.app.actionManager.executeAction(actionAlignVerticallyCentered);
  122. // Check if x position did not change
  123. expect(API.getSelectedElements()[0].x).toEqual(0);
  124. expect(API.getSelectedElements()[1].x).toEqual(110);
  125. expect(API.getSelectedElements()[0].y).toEqual(60);
  126. expect(API.getSelectedElements()[1].y).toEqual(55);
  127. });
  128. it("centers two objects with different sizes correctly horizontally", () => {
  129. createAndSelectTwoRectanglesWithDifferentSizes();
  130. expect(API.getSelectedElements()[0].x).toEqual(0);
  131. expect(API.getSelectedElements()[1].x).toEqual(110);
  132. expect(API.getSelectedElements()[0].y).toEqual(0);
  133. expect(API.getSelectedElements()[1].y).toEqual(110);
  134. h.app.actionManager.executeAction(actionAlignHorizontallyCentered);
  135. expect(API.getSelectedElements()[0].x).toEqual(60);
  136. expect(API.getSelectedElements()[1].x).toEqual(55);
  137. // Check if y position did not change
  138. expect(API.getSelectedElements()[0].y).toEqual(0);
  139. expect(API.getSelectedElements()[1].y).toEqual(110);
  140. });
  141. const createAndSelectGroupAndRectangle = () => {
  142. UI.clickTool("rectangle");
  143. mouse.down();
  144. mouse.up(100, 100);
  145. UI.clickTool("rectangle");
  146. mouse.down(0, 0);
  147. mouse.up(100, 100);
  148. // Select the first element.
  149. // The second rectangle is already reselected because it was the last element created
  150. mouse.reset();
  151. Keyboard.withModifierKeys({ shift: true }, () => {
  152. mouse.click();
  153. });
  154. h.app.actionManager.executeAction(actionGroup);
  155. mouse.reset();
  156. UI.clickTool("rectangle");
  157. mouse.down(200, 200);
  158. mouse.up(100, 100);
  159. // Add the created group to the current selection
  160. mouse.restorePosition(0, 0);
  161. Keyboard.withModifierKeys({ shift: true }, () => {
  162. mouse.click();
  163. });
  164. };
  165. it("aligns a group with another element correctly to the top", () => {
  166. createAndSelectGroupAndRectangle();
  167. expect(API.getSelectedElements()[0].y).toEqual(0);
  168. expect(API.getSelectedElements()[1].y).toEqual(100);
  169. expect(API.getSelectedElements()[2].y).toEqual(200);
  170. h.app.actionManager.executeAction(actionAlignTop);
  171. expect(API.getSelectedElements()[0].y).toEqual(0);
  172. expect(API.getSelectedElements()[1].y).toEqual(100);
  173. expect(API.getSelectedElements()[2].y).toEqual(0);
  174. });
  175. it("aligns a group with another element correctly to the bottom", () => {
  176. createAndSelectGroupAndRectangle();
  177. expect(API.getSelectedElements()[0].y).toEqual(0);
  178. expect(API.getSelectedElements()[1].y).toEqual(100);
  179. expect(API.getSelectedElements()[2].y).toEqual(200);
  180. h.app.actionManager.executeAction(actionAlignBottom);
  181. expect(API.getSelectedElements()[0].y).toEqual(100);
  182. expect(API.getSelectedElements()[1].y).toEqual(200);
  183. expect(API.getSelectedElements()[2].y).toEqual(200);
  184. });
  185. it("aligns a group with another element correctly to the left", () => {
  186. createAndSelectGroupAndRectangle();
  187. expect(API.getSelectedElements()[0].x).toEqual(0);
  188. expect(API.getSelectedElements()[1].x).toEqual(100);
  189. expect(API.getSelectedElements()[2].x).toEqual(200);
  190. h.app.actionManager.executeAction(actionAlignLeft);
  191. expect(API.getSelectedElements()[0].x).toEqual(0);
  192. expect(API.getSelectedElements()[1].x).toEqual(100);
  193. expect(API.getSelectedElements()[2].x).toEqual(0);
  194. });
  195. it("aligns a group with another element correctly to the right", () => {
  196. createAndSelectGroupAndRectangle();
  197. expect(API.getSelectedElements()[0].x).toEqual(0);
  198. expect(API.getSelectedElements()[1].x).toEqual(100);
  199. expect(API.getSelectedElements()[2].x).toEqual(200);
  200. h.app.actionManager.executeAction(actionAlignRight);
  201. expect(API.getSelectedElements()[0].x).toEqual(100);
  202. expect(API.getSelectedElements()[1].x).toEqual(200);
  203. expect(API.getSelectedElements()[2].x).toEqual(200);
  204. });
  205. it("centers a group with another element correctly vertically", () => {
  206. createAndSelectGroupAndRectangle();
  207. expect(API.getSelectedElements()[0].y).toEqual(0);
  208. expect(API.getSelectedElements()[1].y).toEqual(100);
  209. expect(API.getSelectedElements()[2].y).toEqual(200);
  210. h.app.actionManager.executeAction(actionAlignVerticallyCentered);
  211. expect(API.getSelectedElements()[0].y).toEqual(50);
  212. expect(API.getSelectedElements()[1].y).toEqual(150);
  213. expect(API.getSelectedElements()[2].y).toEqual(100);
  214. });
  215. it("centers a group with another element correctly horizontally", () => {
  216. createAndSelectGroupAndRectangle();
  217. expect(API.getSelectedElements()[0].x).toEqual(0);
  218. expect(API.getSelectedElements()[1].x).toEqual(100);
  219. expect(API.getSelectedElements()[2].x).toEqual(200);
  220. h.app.actionManager.executeAction(actionAlignHorizontallyCentered);
  221. expect(API.getSelectedElements()[0].x).toEqual(50);
  222. expect(API.getSelectedElements()[1].x).toEqual(150);
  223. expect(API.getSelectedElements()[2].x).toEqual(100);
  224. });
  225. const createAndSelectTwoGroups = () => {
  226. UI.clickTool("rectangle");
  227. mouse.down();
  228. mouse.up(100, 100);
  229. UI.clickTool("rectangle");
  230. mouse.down(0, 0);
  231. mouse.up(100, 100);
  232. // Select the first element.
  233. // The second rectangle is already selected because it was the last element created
  234. mouse.reset();
  235. Keyboard.withModifierKeys({ shift: true }, () => {
  236. mouse.click();
  237. });
  238. h.app.actionManager.executeAction(actionGroup);
  239. mouse.reset();
  240. UI.clickTool("rectangle");
  241. mouse.down(200, 200);
  242. mouse.up(100, 100);
  243. UI.clickTool("rectangle");
  244. mouse.down();
  245. mouse.up(100, 100);
  246. mouse.restorePosition(200, 200);
  247. Keyboard.withModifierKeys({ shift: true }, () => {
  248. mouse.click();
  249. });
  250. h.app.actionManager.executeAction(actionGroup);
  251. // Select the first group.
  252. // The second group is already selected because it was the last group created
  253. mouse.reset();
  254. Keyboard.withModifierKeys({ shift: true }, () => {
  255. mouse.click();
  256. });
  257. };
  258. it("aligns two groups correctly to the top", () => {
  259. createAndSelectTwoGroups();
  260. expect(API.getSelectedElements()[0].y).toEqual(0);
  261. expect(API.getSelectedElements()[1].y).toEqual(100);
  262. expect(API.getSelectedElements()[2].y).toEqual(200);
  263. expect(API.getSelectedElements()[3].y).toEqual(300);
  264. h.app.actionManager.executeAction(actionAlignTop);
  265. expect(API.getSelectedElements()[0].y).toEqual(0);
  266. expect(API.getSelectedElements()[1].y).toEqual(100);
  267. expect(API.getSelectedElements()[2].y).toEqual(0);
  268. expect(API.getSelectedElements()[3].y).toEqual(100);
  269. });
  270. it("aligns two groups correctly to the bottom", () => {
  271. createAndSelectTwoGroups();
  272. expect(API.getSelectedElements()[0].y).toEqual(0);
  273. expect(API.getSelectedElements()[1].y).toEqual(100);
  274. expect(API.getSelectedElements()[2].y).toEqual(200);
  275. expect(API.getSelectedElements()[3].y).toEqual(300);
  276. h.app.actionManager.executeAction(actionAlignBottom);
  277. expect(API.getSelectedElements()[0].y).toEqual(200);
  278. expect(API.getSelectedElements()[1].y).toEqual(300);
  279. expect(API.getSelectedElements()[2].y).toEqual(200);
  280. expect(API.getSelectedElements()[3].y).toEqual(300);
  281. });
  282. it("aligns two groups correctly to the left", () => {
  283. createAndSelectTwoGroups();
  284. expect(API.getSelectedElements()[0].x).toEqual(0);
  285. expect(API.getSelectedElements()[1].x).toEqual(100);
  286. expect(API.getSelectedElements()[2].x).toEqual(200);
  287. expect(API.getSelectedElements()[3].x).toEqual(300);
  288. h.app.actionManager.executeAction(actionAlignLeft);
  289. expect(API.getSelectedElements()[0].x).toEqual(0);
  290. expect(API.getSelectedElements()[1].x).toEqual(100);
  291. expect(API.getSelectedElements()[2].x).toEqual(0);
  292. expect(API.getSelectedElements()[3].x).toEqual(100);
  293. });
  294. it("aligns two groups correctly to the right", () => {
  295. createAndSelectTwoGroups();
  296. expect(API.getSelectedElements()[0].x).toEqual(0);
  297. expect(API.getSelectedElements()[1].x).toEqual(100);
  298. expect(API.getSelectedElements()[2].x).toEqual(200);
  299. expect(API.getSelectedElements()[3].x).toEqual(300);
  300. h.app.actionManager.executeAction(actionAlignRight);
  301. expect(API.getSelectedElements()[0].x).toEqual(200);
  302. expect(API.getSelectedElements()[1].x).toEqual(300);
  303. expect(API.getSelectedElements()[2].x).toEqual(200);
  304. expect(API.getSelectedElements()[3].x).toEqual(300);
  305. });
  306. it("centers two groups correctly vertically", () => {
  307. createAndSelectTwoGroups();
  308. expect(API.getSelectedElements()[0].y).toEqual(0);
  309. expect(API.getSelectedElements()[1].y).toEqual(100);
  310. expect(API.getSelectedElements()[2].y).toEqual(200);
  311. expect(API.getSelectedElements()[3].y).toEqual(300);
  312. h.app.actionManager.executeAction(actionAlignVerticallyCentered);
  313. expect(API.getSelectedElements()[0].y).toEqual(100);
  314. expect(API.getSelectedElements()[1].y).toEqual(200);
  315. expect(API.getSelectedElements()[2].y).toEqual(100);
  316. expect(API.getSelectedElements()[3].y).toEqual(200);
  317. });
  318. it("centers two groups correctly horizontally", () => {
  319. createAndSelectTwoGroups();
  320. expect(API.getSelectedElements()[0].x).toEqual(0);
  321. expect(API.getSelectedElements()[1].x).toEqual(100);
  322. expect(API.getSelectedElements()[2].x).toEqual(200);
  323. expect(API.getSelectedElements()[3].x).toEqual(300);
  324. h.app.actionManager.executeAction(actionAlignHorizontallyCentered);
  325. expect(API.getSelectedElements()[0].x).toEqual(100);
  326. expect(API.getSelectedElements()[1].x).toEqual(200);
  327. expect(API.getSelectedElements()[2].x).toEqual(100);
  328. expect(API.getSelectedElements()[3].x).toEqual(200);
  329. });
  330. const createAndSelectNestedGroupAndRectangle = () => {
  331. UI.clickTool("rectangle");
  332. mouse.down();
  333. mouse.up(100, 100);
  334. UI.clickTool("rectangle");
  335. mouse.down(0, 0);
  336. mouse.up(100, 100);
  337. // Select the first element.
  338. // The second rectangle is already reselected because it was the last element created
  339. mouse.reset();
  340. Keyboard.withModifierKeys({ shift: true }, () => {
  341. mouse.click();
  342. });
  343. // Create first group of rectangles
  344. h.app.actionManager.executeAction(actionGroup);
  345. mouse.reset();
  346. UI.clickTool("rectangle");
  347. mouse.down(200, 200);
  348. mouse.up(100, 100);
  349. // Add group to current selection
  350. mouse.restorePosition(0, 0);
  351. Keyboard.withModifierKeys({ shift: true }, () => {
  352. mouse.click();
  353. });
  354. // Create the nested group
  355. h.app.actionManager.executeAction(actionGroup);
  356. mouse.reset();
  357. UI.clickTool("rectangle");
  358. mouse.down(300, 300);
  359. mouse.up(100, 100);
  360. // Select the nested group, the rectangle is already selected
  361. mouse.reset();
  362. Keyboard.withModifierKeys({ shift: true }, () => {
  363. mouse.click();
  364. });
  365. };
  366. it("aligns nested group and other element correctly to the top", () => {
  367. createAndSelectNestedGroupAndRectangle();
  368. expect(API.getSelectedElements()[0].y).toEqual(0);
  369. expect(API.getSelectedElements()[1].y).toEqual(100);
  370. expect(API.getSelectedElements()[2].y).toEqual(200);
  371. expect(API.getSelectedElements()[3].y).toEqual(300);
  372. h.app.actionManager.executeAction(actionAlignTop);
  373. expect(API.getSelectedElements()[0].y).toEqual(0);
  374. expect(API.getSelectedElements()[1].y).toEqual(100);
  375. expect(API.getSelectedElements()[2].y).toEqual(200);
  376. expect(API.getSelectedElements()[3].y).toEqual(0);
  377. });
  378. it("aligns nested group and other element correctly to the bottom", () => {
  379. createAndSelectNestedGroupAndRectangle();
  380. expect(API.getSelectedElements()[0].y).toEqual(0);
  381. expect(API.getSelectedElements()[1].y).toEqual(100);
  382. expect(API.getSelectedElements()[2].y).toEqual(200);
  383. expect(API.getSelectedElements()[3].y).toEqual(300);
  384. h.app.actionManager.executeAction(actionAlignBottom);
  385. expect(API.getSelectedElements()[0].y).toEqual(100);
  386. expect(API.getSelectedElements()[1].y).toEqual(200);
  387. expect(API.getSelectedElements()[2].y).toEqual(300);
  388. expect(API.getSelectedElements()[3].y).toEqual(300);
  389. });
  390. it("aligns nested group and other element correctly to the left", () => {
  391. createAndSelectNestedGroupAndRectangle();
  392. expect(API.getSelectedElements()[0].x).toEqual(0);
  393. expect(API.getSelectedElements()[1].x).toEqual(100);
  394. expect(API.getSelectedElements()[2].x).toEqual(200);
  395. expect(API.getSelectedElements()[3].x).toEqual(300);
  396. h.app.actionManager.executeAction(actionAlignLeft);
  397. expect(API.getSelectedElements()[0].x).toEqual(0);
  398. expect(API.getSelectedElements()[1].x).toEqual(100);
  399. expect(API.getSelectedElements()[2].x).toEqual(200);
  400. expect(API.getSelectedElements()[3].x).toEqual(0);
  401. });
  402. it("aligns nested group and other element correctly to the right", () => {
  403. createAndSelectNestedGroupAndRectangle();
  404. expect(API.getSelectedElements()[0].x).toEqual(0);
  405. expect(API.getSelectedElements()[1].x).toEqual(100);
  406. expect(API.getSelectedElements()[2].x).toEqual(200);
  407. expect(API.getSelectedElements()[3].x).toEqual(300);
  408. h.app.actionManager.executeAction(actionAlignRight);
  409. expect(API.getSelectedElements()[0].x).toEqual(100);
  410. expect(API.getSelectedElements()[1].x).toEqual(200);
  411. expect(API.getSelectedElements()[2].x).toEqual(300);
  412. expect(API.getSelectedElements()[3].x).toEqual(300);
  413. });
  414. it("centers nested group and other element correctly vertically", () => {
  415. createAndSelectNestedGroupAndRectangle();
  416. expect(API.getSelectedElements()[0].y).toEqual(0);
  417. expect(API.getSelectedElements()[1].y).toEqual(100);
  418. expect(API.getSelectedElements()[2].y).toEqual(200);
  419. expect(API.getSelectedElements()[3].y).toEqual(300);
  420. h.app.actionManager.executeAction(actionAlignVerticallyCentered);
  421. expect(API.getSelectedElements()[0].y).toEqual(50);
  422. expect(API.getSelectedElements()[1].y).toEqual(150);
  423. expect(API.getSelectedElements()[2].y).toEqual(250);
  424. expect(API.getSelectedElements()[3].y).toEqual(150);
  425. });
  426. it("centers nested group and other element correctly horizontally", () => {
  427. createAndSelectNestedGroupAndRectangle();
  428. expect(API.getSelectedElements()[0].x).toEqual(0);
  429. expect(API.getSelectedElements()[1].x).toEqual(100);
  430. expect(API.getSelectedElements()[2].x).toEqual(200);
  431. expect(API.getSelectedElements()[3].x).toEqual(300);
  432. h.app.actionManager.executeAction(actionAlignHorizontallyCentered);
  433. expect(API.getSelectedElements()[0].x).toEqual(50);
  434. expect(API.getSelectedElements()[1].x).toEqual(150);
  435. expect(API.getSelectedElements()[2].x).toEqual(250);
  436. expect(API.getSelectedElements()[3].x).toEqual(150);
  437. });
  438. });