diff --git a/lib/import/BpmnImporter.js b/lib/import/BpmnImporter.js
index be3c5c10..f9636bdd 100644
--- a/lib/import/BpmnImporter.js
+++ b/lib/import/BpmnImporter.js
@@ -5,6 +5,8 @@ var assign = require('lodash/object/assign'),
var LabelUtil = require('../util/LabelUtil');
+var is = require('../util/ModelUtil').is;
+
var hasExternalLabel = LabelUtil.hasExternalLabel,
getExternalLabelBounds = LabelUtil.getExternalLabelBounds,
isExpanded = require('../util/DiUtil').isExpanded,
@@ -25,6 +27,11 @@ function collectWaypoints(waypoints) {
});
}
+function notYetDrawn(semantic, refSemantic, property) {
+ return new Error(
+ 'element ' + elementToString(refSemantic) + ' referenced by ' +
+ elementToString(semantic) + '#' + property + ' not yet drawn');
+}
/**
* An importer that adds bpmn elements to the canvas
@@ -84,6 +91,10 @@ BpmnImporter.prototype.add = function(semantic, parentElement) {
height: Math.round(bounds.height)
}));
+ if (is(semantic, 'bpmn:BoundaryEvent')) {
+ this._attachBoundary(semantic, element);
+ }
+
this._canvas.addShape(element, parentElement);
}
@@ -116,6 +127,40 @@ BpmnImporter.prototype.add = function(semantic, parentElement) {
};
+/**
+ * Attach the boundary element to the given host
+ *
+ * @param {ModdleElement} boundarySemantic
+ * @param {djs.model.Base} boundaryElement
+ */
+BpmnImporter.prototype._attachBoundary = function(boundarySemantic, boundaryElement) {
+
+ var hostSemantic = boundarySemantic.attachedToRef;
+
+ if (!hostSemantic) {
+ throw new Error('missing ' + elementToString(boundarySemantic) + '#attachedToRef');
+ }
+
+ var host = this._elementRegistry.get(hostSemantic.id),
+ attachers = host && host.attachers;
+
+ if (!host) {
+ throw notYetDrawn(boundarySemantic, hostSemantic, 'attachedToRef');
+ }
+
+ // wire element.host <> host.attachers
+ boundaryElement.host = host;
+
+ if (!attachers) {
+ host.attachers = attachers = [];
+ }
+
+ if (attachers.indexOf(boundaryElement) === -1) {
+ attachers.push(boundaryElement);
+ }
+};
+
+
/**
* add label for an element
*/
@@ -168,9 +213,7 @@ BpmnImporter.prototype._getEnd = function(semantic, side) {
}
if (refSemantic) {
- throw new Error(
- 'element ' + elementToString(refSemantic) + ' referenced by ' +
- elementToString(semantic) + '#' + side + 'Ref not yet drawn');
+ throw notYetDrawn(semantic, refSemantic, side + 'Ref');
} else {
throw new Error(elementToString(semantic) + '#' + side + 'Ref not specified');
}
diff --git a/test/fixtures/bpmn/import/boundaryEvent.bpmn b/test/fixtures/bpmn/import/boundaryEvent.bpmn
new file mode 100644
index 00000000..75f04f4c
--- /dev/null
+++ b/test/fixtures/bpmn/import/boundaryEvent.bpmn
@@ -0,0 +1,34 @@
+
+
+
+
+
+ SequenceFlow_1
+
+
+ SequenceFlow_1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/fixtures/bpmn/import/collaboration.bpmn b/test/fixtures/bpmn/import/collaboration.bpmn
new file mode 100644
index 00000000..a3cbcfb7
--- /dev/null
+++ b/test/fixtures/bpmn/import/collaboration.bpmn
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Task_1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/fixtures/bpmn/import/collapsed-collaboration.bpmn b/test/fixtures/bpmn/import/collapsed/collaboration.bpmn
similarity index 100%
rename from test/fixtures/bpmn/import/collapsed-collaboration.bpmn
rename to test/fixtures/bpmn/import/collapsed/collaboration.bpmn
diff --git a/test/fixtures/bpmn/import/collapsed.bpmn b/test/fixtures/bpmn/import/collapsed/process.bpmn
similarity index 100%
rename from test/fixtures/bpmn/import/collapsed.bpmn
rename to test/fixtures/bpmn/import/collapsed/process.bpmn
diff --git a/test/fixtures/bpmn/import/error/boundaryEvent-invalidAttachToRef.bpmn b/test/fixtures/bpmn/import/error/boundaryEvent-invalidAttachToRef.bpmn
new file mode 100644
index 00000000..0ae7c037
--- /dev/null
+++ b/test/fixtures/bpmn/import/error/boundaryEvent-invalidAttachToRef.bpmn
@@ -0,0 +1,30 @@
+
+
+
+
+ SequenceFlow_1
+
+
+ SequenceFlow_1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/bpmn/import/error/boundaryEvent-missingAttachToRef.bpmn b/test/fixtures/bpmn/import/error/boundaryEvent-missingAttachToRef.bpmn
new file mode 100644
index 00000000..61bd1f04
--- /dev/null
+++ b/test/fixtures/bpmn/import/error/boundaryEvent-missingAttachToRef.bpmn
@@ -0,0 +1,34 @@
+
+
+
+
+
+ SequenceFlow_1
+
+
+ SequenceFlow_1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/fixtures/bpmn/import/dangling-process-message-flow.bpmn b/test/fixtures/bpmn/import/error/dangling-process-message-flow.bpmn
similarity index 100%
rename from test/fixtures/bpmn/import/dangling-process-message-flow.bpmn
rename to test/fixtures/bpmn/import/error/dangling-process-message-flow.bpmn
diff --git a/test/fixtures/bpmn/error/invalid-flow-element.bpmn b/test/fixtures/bpmn/import/error/invalid-flow-element.bpmn
similarity index 100%
rename from test/fixtures/bpmn/error/invalid-flow-element.bpmn
rename to test/fixtures/bpmn/import/error/invalid-flow-element.bpmn
diff --git a/test/fixtures/bpmn/error/multiple-dis.bpmn b/test/fixtures/bpmn/import/error/multiple-dis.bpmn
similarity index 100%
rename from test/fixtures/bpmn/error/multiple-dis.bpmn
rename to test/fixtures/bpmn/import/error/multiple-dis.bpmn
diff --git a/test/fixtures/bpmn/import/process.bpmn b/test/fixtures/bpmn/import/process.bpmn
new file mode 100644
index 00000000..f9ec5d4e
--- /dev/null
+++ b/test/fixtures/bpmn/import/process.bpmn
@@ -0,0 +1,61 @@
+
+
+
+
+ SequenceFlow_3
+ SequenceFlow_2
+
+ SequenceFlow_1
+
+
+ SequenceFlow_1
+
+
+
+
+ SequenceFlow_2
+
+
+
+ SequenceFlow_3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/fixtures/bpmn/simple.bpmn b/test/fixtures/bpmn/simple.bpmn
index f9ec5d4e..3635af9e 100644
--- a/test/fixtures/bpmn/simple.bpmn
+++ b/test/fixtures/bpmn/simple.bpmn
@@ -1,5 +1,5 @@
-
+
SequenceFlow_3
@@ -10,52 +10,52 @@
SequenceFlow_1
-
+
SequenceFlow_2
-
+
SequenceFlow_3
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
\ No newline at end of file
+
diff --git a/test/spec/import/ImporterSpec.js b/test/spec/import/ImporterSpec.js
index 5947c103..55d51f1f 100644
--- a/test/spec/import/ImporterSpec.js
+++ b/test/spec/import/ImporterSpec.js
@@ -2,6 +2,9 @@
var TestHelper = require('../../TestHelper');
+/* global bootstrapViewer, inject */
+
+
var TestContainer = require('mocha-test-container-support');
var Diagram = require('diagram-js/lib/Diagram'),
@@ -10,6 +13,8 @@ var Diagram = require('diagram-js/lib/Diagram'),
Viewer = require('../../../lib/Viewer');
+var is = require('../../../lib/util/ModelUtil').is;
+
describe('import - Importer', function() {
var moddle = new BpmnModdle();
@@ -48,10 +53,10 @@ describe('import - Importer', function() {
describe('event emitter', function() {
- it('should fire during import', function(done) {
+ it('should fire during import', function(done) {
// given
- var xml = require('../../fixtures/bpmn/simple.bpmn');
+ var xml = require('../../fixtures/bpmn/import/process.bpmn');
var eventCount = 0;
@@ -75,10 +80,10 @@ describe('import - Importer', function() {
describe('basics', function() {
- it('should import simple process', function(done) {
+ it('should import process', function(done) {
// given
- var xml = require('../../fixtures/bpmn/simple.bpmn');
+ var xml = require('../../fixtures/bpmn/import/process.bpmn');
var events = [];
@@ -116,7 +121,7 @@ describe('import - Importer', function() {
it('should import collaboration', function(done) {
// given
- var xml = require('../../fixtures/bpmn/collaboration.bpmn');
+ var xml = require('../../fixtures/bpmn/import/collaboration.bpmn');
var events = [];
@@ -148,109 +153,168 @@ describe('import - Importer', function() {
done(err);
});
});
+
+
+ it('should import boundary events', function(done) {
+
+ // given
+ var xml = require('../../fixtures/bpmn/import/boundaryEvent.bpmn');
+
+ var events = [];
+
+ // log events
+ diagram.get('eventBus').on('bpmnElement.added', function(e) {
+ events.push({
+ type: 'add',
+ semantic: e.element.businessObject.id,
+ di: e.element.businessObject.di.id,
+ diagramElement: e.element && e.element.id
+ });
+ });
+
+ // when
+ runImport(diagram, xml, function(err, warnings) {
+
+ // then
+ expect(events).to.eql([
+ { type: 'add', semantic: 'Process_1', di: 'BPMNPlane_1', diagramElement: 'Process_1'},
+ { type: 'add', semantic: 'Task_1', di: '_BPMNShape_Task_2', diagramElement: 'Task_1'},
+ { type: 'add', semantic: 'Task_2', di: '_BPMNShape_Task_3', diagramElement: 'Task_2'},
+ { type: 'add', semantic: 'BoundaryEvent_1', di: '_BPMNShape_BoundaryEvent_2', diagramElement: 'BoundaryEvent_1'},
+ { type: 'add', semantic: 'SequenceFlow_1', di: 'BPMNEdge_SequenceFlow_1', diagramElement: 'SequenceFlow_1'}
+ ]);
+
+ done(err);
+ });
+ });
});
describe('model wiring', function() {
- var xml = require('../../fixtures/bpmn/simple.bpmn');
+ describe('basics', function() {
- var elements;
+ var xml = require('../../fixtures/bpmn/import/process.bpmn');
- beforeEach(function(done) {
- elements = [];
+ beforeEach(bootstrapViewer(xml));
- // log events
- diagram.get('eventBus').on('bpmnElement.added', function(e) {
- elements.push(e.element);
- });
- runImport(diagram, xml, done);
+ it('should wire root element', inject(function(elementRegistry, canvas) {
+
+ // when
+ var processElement = elementRegistry.get('Process_1');
+ var subProcessShape = elementRegistry.get('SubProcess_1');
+
+ // then
+ expect(subProcessShape.parent).to.eql(processElement);
+ expect(canvas.getRootElement()).to.eql(processElement);
+
+ expect(is(processElement, 'bpmn:Process')).to.be.true;
+ }));
+
+
+ it('should wire parent child relationship', inject(function(elementRegistry) {
+
+ // when
+ var subProcessShape = elementRegistry.get('SubProcess_1');
+ var startEventShape = elementRegistry.get('StartEvent_1');
+
+ // then
+ expect(startEventShape.type).to.equal('bpmn:StartEvent');
+ expect(startEventShape.parent).to.eql(subProcessShape);
+
+ expect(subProcessShape.children.length).to.equal(5);
+ }));
+
+
+ it('should wire label relationship', inject(function(elementRegistry) {
+
+ // when
+ var startEventShape = elementRegistry.get('StartEvent_1');
+ var label = startEventShape.label;
+
+ // then
+ expect(label).to.be.defined;
+ expect(label.id).to.equal(startEventShape.id + '_label');
+
+ expect(label.labelTarget).to.eql(startEventShape);
+ }));
+
+
+ it('should wire businessObject', inject(function(elementRegistry) {
+
+ // when
+ var subProcessShape = elementRegistry.get('SubProcess_1');
+ var startEventShape = elementRegistry.get('StartEvent_1');
+
+ var subProcess = subProcessShape.businessObject,
+ startEvent = startEventShape.businessObject;
+
+ // then
+ expect(subProcess).to.be.defined;
+ expect(is(subProcess, 'bpmn:SubProcess')).to.be.true;
+
+ expect(startEvent).to.be.defined;
+ expect(is(startEvent, 'bpmn:StartEvent')).to.be.true;
+ }));
+
+
+ it('should wire shape di', inject(function(elementRegistry) {
+
+ // when
+ var subProcessShape = elementRegistry.get('SubProcess_1');
+
+ var subProcess = subProcessShape.businessObject;
+ var subProcessDi = subProcess.di;
+
+ // then
+ expect(subProcessDi).to.be.defined;
+ expect(subProcessDi.bpmnElement).to.eql(subProcess);
+ }));
+
+
+ it('should wire connection di', inject(function(elementRegistry) {
+
+ // when
+ var sequenceFlowElement = elementRegistry.get('SequenceFlow_1');
+
+ var sequenceFlow = sequenceFlowElement.businessObject;
+ var sequenceFlowDi = sequenceFlow.di;
+
+ // then
+ expect(sequenceFlowDi).to.be.defined;
+ expect(sequenceFlowDi.bpmnElement).to.eql(sequenceFlow);
+ }));
+
});
- it('should wire root element', function() {
+ describe('boundary events', function() {
- // given
- var canvas = diagram.get('canvas');
+ var xml = require('../../fixtures/bpmn/import/boundaryEvent.bpmn');
- // when
- var root = elements[0];
- var anyChild = elements[1];
-
- // assume
- expect(root.businessObject.$instanceOf('bpmn:Process')).to.be.true;
- expect(anyChild.parent).to.eql(root);
-
- // then
- expect(canvas.getRootElement()).to.eql(root);
- });
+ beforeEach(bootstrapViewer(xml));
- it('should wire parent child relationship', function() {
+ it('should wire host attacher relationship', inject(function(elementRegistry) {
- // when
- var subProcessShape = elements[1];
- var startEventShape = elements[2];
+ // when
+ var boundaryEventShape = elementRegistry.get('BoundaryEvent_1'),
+ boundaryEvent = boundaryEventShape.businessObject;
- // then
- expect(startEventShape.type).to.equal('bpmn:StartEvent');
- expect(startEventShape.parent).to.eql(subProcessShape);
+ var taskShape = elementRegistry.get('Task_1'),
+ task = taskShape.businessObject;
- expect(subProcessShape.children.length).to.equal(5);
- });
+ // assume
+ expect(boundaryEvent.attachedToRef).to.eql(task);
+ // then
+ expect(boundaryEventShape.host).to.eql(taskShape);
- it('should wire label relationship', function() {
+ expect(taskShape.attachers).to.exist;
+ expect(taskShape.attachers).to.contain(boundaryEventShape);
+ }));
- // when
- var startEventShape = elements[2];
- var label = startEventShape.label;
-
- // then
- expect(label).to.be.defined;
- expect(label.id).to.equal(startEventShape.id + '_label');
-
- expect(label.labelTarget).to.eql(startEventShape);
- });
-
-
- it('should wire businessObject', function() {
-
- // when
- var subProcessShape = elements[1];
- var startEventShape = elements[2];
-
- var subProcess = subProcessShape.businessObject,
- startEvent = startEventShape.businessObject;
-
- // then
- expect(subProcess).to.be.defined;
- expect(subProcess.$instanceOf('bpmn:SubProcess')).to.be.true;
-
- expect(startEvent).to.be.defined;
- expect(startEvent.$instanceOf('bpmn:StartEvent')).to.be.true;
- });
-
-
- it('should wire di', function() {
-
- // when
- var subProcessShape = elements[1];
- var startEventShape = elements[2];
-
- var subProcess = subProcessShape.businessObject,
- startEvent = startEventShape.businessObject;
-
- var subProcessDi = subProcess.di,
- startEventDi = startEvent.di;
-
- // then
- expect(subProcessDi).to.be.defined;
- expect(subProcessDi.bpmnElement).to.eql(subProcess);
-
- expect(startEventDi).to.be.defined;
- expect(startEventDi.bpmnElement).to.eql(startEvent);
});
});
@@ -261,7 +325,7 @@ describe('import - Importer', function() {
it('should import invalid flowElement', function(done) {
// given
- var xml = require('../../fixtures/bpmn/error/invalid-flow-element.bpmn');
+ var xml = require('../../fixtures/bpmn/import/error/invalid-flow-element.bpmn');
// when
runImport(diagram, xml, function(err, warnings) {
@@ -276,7 +340,7 @@ describe('import - Importer', function() {
it('should import multiple DIs', function(done) {
// given
- var xml = require('../../fixtures/bpmn/error/multiple-dis.bpmn');
+ var xml = require('../../fixtures/bpmn/import/error/multiple-dis.bpmn');
// when
runImport(diagram, xml, function(err, warnings) {
@@ -310,6 +374,48 @@ describe('import - Importer', function() {
});
});
+
+ describe('boundary events', function() {
+
+ it('should handle missing attachToRef', function(done) {
+
+ // given
+ var xml = require('../../fixtures/bpmn/import/error/boundaryEvent-missingAttachToRef.bpmn');
+
+ // when
+ runImport(diagram, xml, function(err, warnings) {
+
+ // then
+ expect(warnings.length).to.eql(2);
+
+ expect(warnings[0].message).to.eql('missing #attachedToRef');
+ expect(warnings[1].message).to.eql('element referenced by #sourceRef not yet drawn');
+
+ done(err);
+ });
+ });
+
+
+ it('should handle invalid attachToRef', function(done) {
+
+ // given
+ var xml = require('../../fixtures/bpmn/import/error/boundaryEvent-invalidAttachToRef.bpmn');
+
+ // when
+ runImport(diagram, xml, function(err, warnings) {
+
+ // then
+ expect(warnings.length).to.eql(2);
+
+ expect(warnings[0].message).to.eql('missing #attachedToRef');
+ expect(warnings[1].message).to.eql('element referenced by #sourceRef not yet drawn');
+
+ done(err);
+ });
+ });
+
+ });
+
});
@@ -334,7 +440,7 @@ describe('import - Importer', function() {
it('should import dangling process message flows', function(done) {
// given
- var xml = require('../../fixtures/bpmn/import/dangling-process-message-flow.bpmn');
+ var xml = require('../../fixtures/bpmn/import/error/dangling-process-message-flow.bpmn');
// when
runImport(diagram, xml, function(err, warnings) {
@@ -348,12 +454,13 @@ describe('import - Importer', function() {
done(err);
});
});
+
});
describe('position', function() {
- var xml1 = require('../../fixtures/bpmn/import/position/position-testcase.bpmn');
+ var xml = require('../../fixtures/bpmn/import/position/position-testcase.bpmn');
it('should round shape\'s x and y coordinates', function(done) {
@@ -366,7 +473,7 @@ describe('import - Importer', function() {
events[e.element.id] = e.element;
});
- runImport(diagram, xml1, function(err, warnings) {
+ runImport(diagram, xml, function(err, warnings) {
//round up
expect(events.ID_End.x).to.equal(Math.round(340.6));
@@ -392,7 +499,7 @@ describe('import - Importer', function() {
events[e.element.id] = e.element;
});
- runImport(diagram, xml1, function(err, warnings) {
+ runImport(diagram, xml, function(err, warnings) {
//round down
expect(events.ID_Start.height).to.equal(Math.round(30.4));
diff --git a/test/spec/import/elements/CollapsedSpec.js b/test/spec/import/elements/CollapsedSpec.js
index 2bf57de3..7ba347cd 100644
--- a/test/spec/import/elements/CollapsedSpec.js
+++ b/test/spec/import/elements/CollapsedSpec.js
@@ -9,7 +9,7 @@ describe('import - collapsed container', function() {
describe('in process', function() {
- var diagramXML = require('../../../fixtures/bpmn/import/collapsed.bpmn');
+ var diagramXML = require('../../../fixtures/bpmn/import/collapsed/process.bpmn');
beforeEach(bootstrapViewer(diagramXML));
@@ -74,7 +74,7 @@ describe('import - collapsed container', function() {
describe('in collaboration', function() {
- var diagramXML = require('../../../fixtures/bpmn/import/collapsed-collaboration.bpmn');
+ var diagramXML = require('../../../fixtures/bpmn/import/collapsed/collaboration.bpmn');
beforeEach(bootstrapViewer(diagramXML));