diff --git a/CHANGELOG.md b/CHANGELOG.md index 14ff02cd..a2673e06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,10 @@ All notable changes to [bpmn-js](https://github.com/bpmn-io/bpmn-js) are documen ___Note:__ Yet to be released changes appear here._ -### BREAKING CHANGES +### Breaking Changes * `CHORE`: update to [`diagram-js@2.0.0`](https://github.com/bpmn-io/diagram-js/blob/master/CHANGELOG.md#200) +* `FIX`: correctly handle missing `bpmndi:Label` bounds during model updating ([#794](https://github.com/bpmn-io/bpmn-js/issues/794)) ## 1.3.3 diff --git a/lib/features/modeling/BpmnUpdater.js b/lib/features/modeling/BpmnUpdater.js index c395c701..8212856b 100644 --- a/lib/features/modeling/BpmnUpdater.js +++ b/lib/features/modeling/BpmnUpdater.js @@ -361,7 +361,14 @@ BpmnUpdater.prototype.updateBounds = function(shape) { var di = shape.businessObject.di; - var bounds = (shape instanceof Label) ? this._getLabel(di).bounds : di.bounds; + var target = (shape instanceof Label) ? this._getLabel(di) : di; + + var bounds = target.bounds; + + if (!bounds) { + bounds = this._bpmnFactory.createDiBounds(); + target.set('bounds', bounds); + } assign(bounds, { x: shape.x, diff --git a/test/spec/features/modeling/BpmnUpdater.missingBounds.bpmn b/test/spec/features/modeling/BpmnUpdater.missingBounds.bpmn new file mode 100644 index 00000000..29963b82 --- /dev/null +++ b/test/spec/features/modeling/BpmnUpdater.missingBounds.bpmn @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/spec/features/modeling/BpmnUpdaterSpec.js b/test/spec/features/modeling/BpmnUpdaterSpec.js index 5e485901..013f8200 100644 --- a/test/spec/features/modeling/BpmnUpdaterSpec.js +++ b/test/spec/features/modeling/BpmnUpdaterSpec.js @@ -6,71 +6,120 @@ import { import modelingModule from 'lib/features/modeling'; import coreModule from 'lib/core'; +var testModules = [ modelingModule, coreModule ]; + describe('features - bpmn-updater', function() { - var diagramXML = require('./BpmnUpdater.bpmn'); - - var testModules = [ modelingModule, coreModule ]; - - beforeEach(bootstrapModeler(diagramXML, { modules: testModules })); - - describe('connection di', function() { - it('should update after deleting intermediate element', inject(function(modeling, elementRegistry) { + var diagramXML = require('./BpmnUpdater.bpmn'); - // given - // sequence flow with existing sourceElement and targetElement di information - var task = elementRegistry.get('Task_1'), - sequenceFlowDi = elementRegistry.get('SequenceFlow_1').businessObject.di, - startEventDi = elementRegistry.get('StartEvent_1').businessObject.di, - endEventDi = elementRegistry.get('EndEvent_1').businessObject.di; - - // when - modeling.removeElements([ task ]); - - // then - expect(sequenceFlowDi.sourceElement).to.equal(startEventDi); - expect(sequenceFlowDi.targetElement).to.equal(endEventDi); + beforeEach(bootstrapModeler(diagramXML, { + modules: testModules })); - it('should update on drop on flow', inject(function(modeling, elementRegistry, elementFactory) { + it('should update after deleting intermediate element', inject( + function(modeling, elementRegistry) { - // given - // sequence flow with existing sourceElement and targetElement di information - var sequenceFlow = elementRegistry.get('SequenceFlow_3'), - startEventDi = elementRegistry.get('StartEvent_2').businessObject.di; + // given + // sequence flow with existing sourceElement and targetElement di information + var task = elementRegistry.get('Task_1'), + sequenceFlowDi = elementRegistry.get('SequenceFlow_1').businessObject.di, + startEventDi = elementRegistry.get('StartEvent_1').businessObject.di, + endEventDi = elementRegistry.get('EndEvent_1').businessObject.di; - var intermediateThrowEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent' }), - dropPosition = { x: 320, y: 260 }; + // when + modeling.removeElements([ task ]); - // when - var event = modeling.createShape(intermediateThrowEvent, dropPosition, sequenceFlow); + // then + expect(sequenceFlowDi.sourceElement).to.equal(startEventDi); + expect(sequenceFlowDi.targetElement).to.equal(endEventDi); + } + )); - // then - expect(sequenceFlow.businessObject.di.sourceElement).to.equal(startEventDi); - expect(sequenceFlow.businessObject.di.targetElement).to.equal(event.businessObject.di); + + it('should update on drop on flow', inject( + function(modeling, elementRegistry, elementFactory) { + + // given + // sequence flow with existing sourceElement and targetElement di information + var sequenceFlow = elementRegistry.get('SequenceFlow_3'), + startEventDi = elementRegistry.get('StartEvent_2').businessObject.di; + + var intermediateThrowEvent = elementFactory.createShape({ + type: 'bpmn:IntermediateThrowEvent' + }); + + var dropPosition = { x: 320, y: 260 }; + + // when + var event = modeling.createShape(intermediateThrowEvent, dropPosition, sequenceFlow); + + // then + expect(sequenceFlow.businessObject.di.sourceElement).to.equal(startEventDi); + expect(sequenceFlow.businessObject.di.targetElement).to.equal(event.businessObject.di); + } + )); + + + it('should not create new di refs', inject( + function(modeling, elementRegistry, elementFactory) { + + // given + // sequence flow without any sourceElement and targetElement di information + var sequenceFlow = elementRegistry.get('SequenceFlow_4'); + + var intermediateThrowEvent = elementFactory.createShape({ + type: 'bpmn:IntermediateThrowEvent' + }); + + var dropPosition = { x: 320, y: 260 }; + + // when + modeling.createShape(intermediateThrowEvent, dropPosition, sequenceFlow); + + // then + expect(sequenceFlow.businessObject.di.sourceElement).not.to.exist; + expect(sequenceFlow.businessObject.di.targetElement).not.to.exist; + } + )); + + }); + + + describe('missing bpmndi:Bounds', function() { + + var diagramXML = require('./BpmnUpdater.missingBounds.bpmn'); + + beforeEach(bootstrapModeler(diagramXML, { + modules: testModules })); - it('should not create new di refs', inject(function(modeling, elementRegistry, elementFactory) { + it('should add bpmndi:Bounds', inject( + function(modeling, elementRegistry) { - // given - // sequence flow without any sourceElement and targetElement di information - var sequenceFlow = elementRegistry.get('SequenceFlow_4'); + // given + var event = elementRegistry.get('StartEvent'), + label = event.label, + di = event.businessObject.di; - var intermediateThrowEvent = elementFactory.createShape({ type: 'bpmn:IntermediateThrowEvent' }), - dropPosition = { x: 320, y: 260 }; + // when + modeling.moveElements([ label ], { x: 20, y: 20 }); - // when - modeling.createShape(intermediateThrowEvent, dropPosition, sequenceFlow); + var labelBounds = di.label.bounds; - // then - expect(sequenceFlow.businessObject.di.sourceElement).not.to.exist; - expect(sequenceFlow.businessObject.di.targetElement).not.to.exist; - })); + // then + expect(labelBounds).to.exist; + + expect(labelBounds).to.include.keys( + 'x', 'y', + 'width', 'height' + ); + } + )); });