MoveElementsSpec.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. import {
  2. bootstrapDiagram,
  3. inject
  4. } from 'test/TestHelper';
  5. import {
  6. pick
  7. } from 'min-dash';
  8. import modelingModule from 'lib/features/modeling';
  9. function containment(element) {
  10. return pick(element, [ 'x', 'y', 'parent' ]);
  11. }
  12. describe('features/modeling - move elements', function() {
  13. beforeEach(bootstrapDiagram({ modules: [ modelingModule ] }));
  14. var rootShape, parentShape, otherParentShape, childShape, otherChildShape, connection;
  15. beforeEach(inject(function(elementFactory, canvas) {
  16. rootShape = elementFactory.createRoot({
  17. id: 'root'
  18. });
  19. canvas.setRootElement(rootShape);
  20. parentShape = elementFactory.createShape({
  21. id: 'parent',
  22. x: 100, y: 100,
  23. width: 300, height: 300
  24. });
  25. canvas.addShape(parentShape, rootShape);
  26. otherParentShape = elementFactory.createShape({
  27. id: 'other-parent',
  28. x: 500, y: 200,
  29. width: 300, height: 300
  30. });
  31. canvas.addShape(otherParentShape, rootShape);
  32. childShape = elementFactory.createShape({
  33. id: 'child',
  34. x: 110, y: 110,
  35. width: 100, height: 100
  36. });
  37. canvas.addShape(childShape, parentShape);
  38. otherChildShape = elementFactory.createShape({
  39. id: 'other-child',
  40. x: 250, y: 160,
  41. width: 100, height: 100
  42. });
  43. canvas.addShape(otherChildShape, parentShape);
  44. connection = elementFactory.createConnection({
  45. id: 'connection',
  46. waypoints: [
  47. { x: 160, y: 160 },
  48. { x: 160, y: 300 },
  49. { x: 300, y: 210 }
  50. ],
  51. source: childShape,
  52. target: otherChildShape
  53. });
  54. canvas.addConnection(connection, parentShape);
  55. }));
  56. describe('should move', function() {
  57. it('execute', inject(function(modeling) {
  58. // when
  59. modeling.moveElements([ childShape, otherChildShape ], { x: -20, y: +20 }, otherParentShape);
  60. // then
  61. expect(childShape.x).to.equal(90);
  62. expect(childShape.y).to.equal(130);
  63. expect(otherChildShape.x).to.equal(230);
  64. expect(otherChildShape.y).to.equal(180);
  65. // update parent(s)
  66. expect(childShape.parent).to.equal(otherParentShape);
  67. expect(otherChildShape.parent).to.equal(otherParentShape);
  68. }));
  69. it('undo', inject(function(modeling, commandStack) {
  70. var oldContainment = containment(childShape),
  71. oldContainment2 = containment(otherChildShape);
  72. // given
  73. modeling.moveElements([ childShape, otherChildShape ], { x: -20, y: +20 }, otherParentShape);
  74. modeling.moveElements([ childShape ], { x: +40, y: -40 }, parentShape);
  75. // when
  76. commandStack.undo();
  77. commandStack.undo();
  78. // then
  79. expect(containment(childShape)).to.eql(oldContainment);
  80. expect(containment(otherChildShape)).to.eql(oldContainment2);
  81. }));
  82. it('redo', inject(function(modeling, commandStack) {
  83. // given
  84. modeling.moveElements([ childShape, otherChildShape ], { x: -20, y: +20 }, otherParentShape);
  85. modeling.moveElements([ childShape ], { x: +40, y: -40 }, parentShape);
  86. var newContainment = containment(childShape),
  87. newContainment2 = containment(otherChildShape);
  88. // when
  89. commandStack.undo();
  90. commandStack.undo();
  91. commandStack.redo();
  92. commandStack.redo();
  93. // then
  94. expect(containment(childShape)).to.eql(newContainment);
  95. expect(containment(otherChildShape)).to.eql(newContainment2);
  96. // correct positioning
  97. expect(childShape.x).to.equal(130);
  98. expect(childShape.y).to.equal(90);
  99. expect(otherChildShape.x).to.equal(230);
  100. expect(otherChildShape.y).to.equal(180);
  101. }));
  102. });
  103. describe('move children with container', function() {
  104. it('execute', inject(function(modeling) {
  105. // when
  106. modeling.moveElements([ parentShape ], { x: -20, y: +20 }, otherParentShape);
  107. // then
  108. expect(childShape.x).to.eql(90);
  109. expect(childShape.y).to.eql(130);
  110. expect(otherChildShape.x).to.eql(230);
  111. expect(otherChildShape.y).to.eql(180);
  112. // children remain unaffected
  113. expect(childShape.parent).to.equal(parentShape);
  114. expect(otherChildShape.parent).to.equal(parentShape);
  115. expect(parentShape.parent).to.equal(otherParentShape);
  116. expect(otherParentShape.children).to.eql([ parentShape ]);
  117. expect(parentShape.children).to.eql([ childShape, otherChildShape, connection ]);
  118. }));
  119. it('undo', inject(function(modeling, commandStack) {
  120. // given
  121. modeling.moveElements([ parentShape ], { x: -20, y: +20 }, otherParentShape);
  122. // when
  123. commandStack.undo();
  124. // then
  125. expect(childShape.x).to.eql(110);
  126. expect(childShape.y).to.eql(110);
  127. expect(otherChildShape.x).to.eql(250);
  128. expect(otherChildShape.y).to.eql(160);
  129. expect(childShape.parent).to.eql(parentShape);
  130. expect(otherChildShape.parent).to.eql(parentShape);
  131. expect(parentShape.children).to.eql([ childShape, otherChildShape, connection ]);
  132. expect(otherParentShape.children).to.be.empty;
  133. }));
  134. it('redo', inject(function(modeling, commandStack) {
  135. // given
  136. modeling.moveElements([ parentShape ], { x: -20, y: 20 }, otherParentShape);
  137. // when
  138. commandStack.undo();
  139. commandStack.redo();
  140. // then
  141. expect(childShape.x).to.eql(90);
  142. expect(childShape.y).to.eql(130);
  143. expect(otherChildShape.x).to.eql(230);
  144. expect(otherChildShape.y).to.eql(180);
  145. // children remain unaffected
  146. expect(childShape.parent).to.equal(parentShape);
  147. expect(otherChildShape.parent).to.equal(parentShape);
  148. expect(parentShape.parent).to.equal(otherParentShape);
  149. expect(otherParentShape.children).to.eql([ parentShape ]);
  150. expect(parentShape.children).to.eql([ childShape, otherChildShape, connection ]);
  151. }));
  152. });
  153. function waypoints(connection) {
  154. return connection.waypoints.map(function(p) {
  155. return { x: p.x, y: p.y };
  156. });
  157. }
  158. // See https://github.com/bpmn-io/bpmn-js/issues/200
  159. // If a connection is moved without moving the source
  160. // and target shape the connection should be relayouted
  161. // instead of beeing moved
  162. it('should layout dangling connection', inject(function(modeling) {
  163. // when
  164. modeling.moveElements([ childShape, connection ], { x: 0, y: -50 }, rootShape);
  165. // then
  166. // expect relayouted connection
  167. expect(connection).to.have.waypoints([
  168. { x: 160, y: 110 },
  169. { x: 300, y: 210 }
  170. ]);
  171. }));
  172. it('should move included connection', inject(function(modeling) {
  173. // when
  174. modeling.moveElements([ childShape, connection, otherChildShape ], { x: 0, y: -50 }, rootShape);
  175. // then
  176. // expect moved
  177. expect(waypoints(connection)).to.eql([
  178. { x: 160, y: 110 },
  179. { x: 160, y: 250 },
  180. { x: 300, y: 160 }
  181. ]);
  182. }));
  183. describe('multiple selection', function() {
  184. it('should keep parent of secondary shape (scenario 1)', inject(function(modeling) {
  185. // scenario 1:
  186. // primary shape parent hover: does not change
  187. // secondary shape parent hover: does not change
  188. // given
  189. modeling.moveElements([ childShape ], { x: 350, y: -50 }, rootShape);
  190. // when
  191. modeling.moveElements([ childShape, otherChildShape ], { x: 0, y: 20 }, parentShape,
  192. { primaryShape: otherChildShape });
  193. // then
  194. expect(otherChildShape.parent).to.equal(parentShape);
  195. expect(childShape.parent).to.equal(rootShape);
  196. }));
  197. it('should keep parent of secondary shape (scenario 2)', inject(function(modeling) {
  198. // scenario 2:
  199. // primary shape parent hover: does not change
  200. // secondary shape parent hover: does change
  201. // given
  202. modeling.moveElements([ childShape ], { x: 330, y: -50 }, rootShape);
  203. // when
  204. modeling.moveElements([ childShape, otherChildShape ], { x: -145, y: 100 }, parentShape,
  205. { primaryShape: otherChildShape });
  206. // then
  207. expect(otherChildShape.parent).to.equal(parentShape);
  208. expect(childShape.parent).to.equal(rootShape);
  209. }));
  210. it('should set parent of sec. shape to parent of prim. shape (scenario 3)', inject(function(modeling) {
  211. // scenario 3:
  212. // primary shape parent hover: does change
  213. // secondary shape parent hover: does not change
  214. // given
  215. modeling.moveElements([ childShape ], { x: 350, y: -50 }, rootShape);
  216. // when
  217. modeling.moveElements(
  218. [ childShape, otherChildShape ],
  219. { x: 400, y: 200 },
  220. otherParentShape,
  221. { primaryShape: otherChildShape }
  222. );
  223. // then
  224. expect(otherChildShape.parent).to.equal(otherParentShape);
  225. expect(childShape.parent).to.equal(otherParentShape);
  226. }));
  227. it('should set parent of sec. shape to parent of prim. shape (scenario 4)', inject(function(modeling) {
  228. // scenario 4:
  229. // primary shape parent hover: does change
  230. // secondary shape parent hover: does change
  231. // given
  232. modeling.moveElements([ childShape ], { x: 300, y: -50 }, rootShape);
  233. // when
  234. modeling.moveElements(
  235. [ childShape, otherChildShape ],
  236. { x: 280, y: 200 },
  237. otherParentShape,
  238. { primaryShape: otherChildShape }
  239. );
  240. // then
  241. expect(otherChildShape.parent).to.equal(otherParentShape);
  242. expect(childShape.parent).to.equal(otherParentShape);
  243. }));
  244. // See https://github.com/bpmn-io/bpmn-js/issues/525
  245. it('should keep parent of connection',
  246. inject(function(modeling) {
  247. // given
  248. var elements = [
  249. childShape,
  250. otherChildShape,
  251. otherParentShape
  252. ];
  253. // when
  254. modeling.moveElements(
  255. elements,
  256. { x: 0, y: -50 },
  257. rootShape,
  258. { primaryShape: otherParentShape }
  259. );
  260. // then
  261. expect(connection.parent).to.equal(parentShape);
  262. })
  263. );
  264. // See https://github.com/bpmn-io/bpmn-js/issues/525
  265. it('should keep parent of connection when moving with selection',
  266. inject(function(modeling) {
  267. // given
  268. var elements = [
  269. childShape,
  270. connection,
  271. otherChildShape,
  272. otherParentShape
  273. ];
  274. // when
  275. modeling.moveElements(
  276. elements,
  277. { x: 0, y: -50 },
  278. rootShape,
  279. { primaryShape: otherParentShape }
  280. );
  281. // then
  282. expect(connection.parent).to.equal(parentShape);
  283. })
  284. );
  285. });
  286. describe('drop', function() {
  287. // @see DropShapeSpec.js
  288. });
  289. });