diff --git a/assets/bpmn-js.css b/assets/bpmn-js.css
index 044fec7fea..2c72545200 100644
--- a/assets/bpmn-js.css
+++ b/assets/bpmn-js.css
@@ -103,3 +103,11 @@
fill: var(--drilldown-fill-color);
background-color: var(--drilldown-background-color);
}
+
+.bjs-drilldown-empty {
+ display: none;
+}
+
+.selected .bjs-drilldown-empty {
+ display: inherit;
+}
\ No newline at end of file
diff --git a/lib/features/auto-resize/BpmnAutoResizeProvider.js b/lib/features/auto-resize/BpmnAutoResizeProvider.js
index d44e9aa6eb..721b08101a 100644
--- a/lib/features/auto-resize/BpmnAutoResizeProvider.js
+++ b/lib/features/auto-resize/BpmnAutoResizeProvider.js
@@ -33,6 +33,12 @@ BpmnAutoResizeProvider.$inject = [
*/
BpmnAutoResizeProvider.prototype.canResize = function(elements, target) {
+ // do not resize plane elements:
+ // root elements, collapsed sub-processes
+ if (is(target.di, 'bpmndi:BPMNPlane')) {
+ return false;
+ }
+
if (!is(target, 'bpmn:Participant') && !is(target, 'bpmn:Lane') && !(is(target, 'bpmn:SubProcess'))) {
return false;
}
diff --git a/lib/features/di-ordering/BpmnDiOrdering.js b/lib/features/di-ordering/BpmnDiOrdering.js
index 86e8df9452..5b66cd77da 100644
--- a/lib/features/di-ordering/BpmnDiOrdering.js
+++ b/lib/features/di-ordering/BpmnDiOrdering.js
@@ -2,6 +2,7 @@ import { getDi } from '../../util/ModelUtil';
import {
filter,
+ forEach,
map
} from 'min-dash';
@@ -10,27 +11,32 @@ import { selfAndAllChildren } from 'diagram-js/lib/util/Elements';
var HIGH_PRIORITY = 2000;
-export default function BpmnDiOrdering(eventBus, canvas) {
+export default function BpmnDiOrdering(eventBus, elementRegistry) {
eventBus.on('saveXML.start', HIGH_PRIORITY, orderDi);
function orderDi() {
- var root = canvas.getRootElement(),
- rootDi = getDi(root),
- elements,
- diElements;
+ var rootElements = elementRegistry.filter(function(element) {
+ return !element.parent;
+ });
- elements = selfAndAllChildren([ root ], false);
+ forEach(rootElements, function(root) {
+ var rootDi = getDi(root),
+ elements,
+ diElements;
- // only bpmndi:Shape and bpmndi:Edge can be direct children of bpmndi:Plane
- elements = filter(elements, function(element) {
- return element !== root && !element.labelTarget;
- });
+ elements = selfAndAllChildren([ root ], false);
- diElements = map(elements, getDi);
+ // only bpmndi:Shape and bpmndi:Edge can be direct children of bpmndi:Plane
+ elements = filter(elements, function(element) {
+ return element !== root && !element.labelTarget;
+ });
- rootDi.set('planeElement', diElements);
+ diElements = map(elements, getDi);
+
+ rootDi.set('planeElement', diElements);
+ });
}
}
-BpmnDiOrdering.$inject = [ 'eventBus', 'canvas' ];
+BpmnDiOrdering.$inject = [ 'eventBus', 'elementRegistry' ];
diff --git a/lib/features/drilldown/DrilldownOverlays.js b/lib/features/drilldown/DrilldownBreadcrumbs.js
similarity index 59%
rename from lib/features/drilldown/DrilldownOverlays.js
rename to lib/features/drilldown/DrilldownBreadcrumbs.js
index ccfbe686df..f234ecde6c 100644
--- a/lib/features/drilldown/DrilldownOverlays.js
+++ b/lib/features/drilldown/DrilldownBreadcrumbs.js
@@ -3,8 +3,6 @@ import { domify, classes } from 'min-dom';
import { escapeHTML } from 'diagram-js/lib/util/EscapeUtil';
import { getBusinessObject, is } from '../../util/ModelUtil';
-var ARROW_DOWN_SVG = '';
-
var OPEN_CLASS = 'bjs-breadcrumbs-shown';
/**
@@ -15,7 +13,7 @@ var OPEN_CLASS = 'bjs-breadcrumbs-shown';
* @param {overlays} overlays
* @param {canvas} canvas
*/
-export default function DrilldownOverlays(eventBus, elementRegistry, overlays, canvas) {
+export default function DrilldownBreadcrumbs(eventBus, elementRegistry, overlays, canvas) {
var breadcrumbs = domify('
');
var container = canvas.getContainer();
var containerClasses = classes(container);
@@ -58,40 +56,9 @@ export default function DrilldownOverlays(eventBus, elementRegistry, overlays, c
updateBreadcrumbs(plane);
});
- var createOverlay = function(element) {
- var html = domify('');
-
- html.addEventListener('click', function() {
- canvas.setActivePlane(element.id);
- });
-
- overlays.add(element, {
- position: {
- bottom: -7,
- right: -8
- },
- html: html
- });
- };
-
- var addOverlays = function(elements) {
- elements.forEach(function(element) {
- if (is(element, 'bpmn:SubProcess')
- && element.collapsed
- && canvas.getPlane(element.id)) {
- createOverlay(element);
- }
- });
- };
-
- eventBus.on('import.done', function() {
- addOverlays(elementRegistry.filter(function(el) {
- return is(el, 'bpmn:SubProcess');
- }));
- });
}
-DrilldownOverlays.$inject = [ 'eventBus', 'elementRegistry', 'overlays', 'canvas' ];
+DrilldownBreadcrumbs.$inject = [ 'eventBus', 'elementRegistry', 'overlays', 'canvas' ];
// helpers
diff --git a/lib/features/drilldown/DrilldownOverlayBehavior.js b/lib/features/drilldown/DrilldownOverlayBehavior.js
new file mode 100644
index 0000000000..fa2ddb4217
--- /dev/null
+++ b/lib/features/drilldown/DrilldownOverlayBehavior.js
@@ -0,0 +1,132 @@
+import inherits from 'inherits';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+import { is } from '../../util/ModelUtil';
+import { classes, domify } from 'min-dom';
+
+var LOW_PRIORITY = 250;
+var ARROW_DOWN_SVG = '';
+
+var EMPTY_MARKER = 'bjs-drilldown-empty';
+
+export default function DrilldownOverlayBehavior(
+ canvas, eventBus, elementRegistry, overlays
+) {
+ CommandInterceptor.call(this, eventBus);
+
+ this._canvas = canvas;
+ this._eventBus = eventBus;
+ this._elementRegistry = elementRegistry;
+ this._overlays = overlays;
+
+ var self = this;
+
+ this.executed('shape.create', LOW_PRIORITY, function(context) {
+ var shape = context.shape;
+
+ // Add overlay to the collapsed shape
+ if (self.canDrillDown(shape)) {
+ self.addOverlay(shape);
+ }
+
+ // with the first element added, we remove the overlay marker
+ // to make the drilldown button permanent
+ updateDrilldownOverlay(shape);
+ }, true);
+
+ this.reverted('shape.create', LOW_PRIORITY, function(context) {
+ updateDrilldownOverlay(context.parent);
+ }, true);
+
+ this.executed('shape.delete', LOW_PRIORITY, function(context) {
+ updateDrilldownOverlay(context.oldParent);
+ }, true);
+
+ this.reverted('shape.delete', LOW_PRIORITY, function(context) {
+ updateDrilldownOverlay(context.oldParent);
+ }, true);
+
+ // TODO(marstamm): remove overlays when expanding an element
+
+
+ eventBus.on('import.done', function() {
+ elementRegistry.filter(function(e) {
+ return self.canDrillDown(e);
+ }).map(function(el) {
+ self.addOverlay(el);
+ });
+ });
+
+ function updateDrilldownOverlay(shape) {
+ if (!shape) {
+ return;
+ }
+
+ var parentPlane = canvas.findPlane(shape);
+ if (parentPlane) {
+ self.updateOverlayVisibility(parentPlane.rootElement);
+ }
+ }
+}
+
+inherits(DrilldownOverlayBehavior, CommandInterceptor);
+
+DrilldownOverlayBehavior.prototype.canDrillDown = function(element) {
+ return is(element, 'bpmn:SubProcess') && this._canvas.getPlane(element.id);
+};
+
+/**
+ * Updates visibility of the drilldown overlay. If the plane has no elements,
+ * the drilldown will be only shown when the element is selected.
+ *
+ * @param {djs.model.Shape|djs.model.Root} element collapsed shape or root element
+ */
+DrilldownOverlayBehavior.prototype.updateOverlayVisibility = function(element) {
+ var overlays = this._overlays;
+
+ var bo = element.businessObject;
+
+ var overlay = overlays.get({ element: bo.id, type: 'drilldown' })[0];
+
+ if (!overlay) {
+ return;
+ }
+
+ var hasContent = bo && bo.flowElements && bo.flowElements.length;
+ classes(overlay.html).toggle(EMPTY_MARKER, !hasContent);
+};
+
+/**
+ * Attaches a drilldown button to the given element. We assume that the plane has
+ * the same id as the element.
+ *
+ * @param {djs.model.Shape} element collapsed shape
+ */
+DrilldownOverlayBehavior.prototype.addOverlay = function(element) {
+ var canvas = this._canvas;
+ var overlays = this._overlays;
+
+ var button = domify('');
+
+ button.addEventListener('click', function() {
+ canvas.setActivePlane(element.id);
+ });
+
+ overlays.add(element, 'drilldown', {
+ position: {
+ bottom: -7,
+ right: -8
+ },
+ html: button
+ });
+
+ this.updateOverlayVisibility(element);
+};
+
+
+DrilldownOverlayBehavior.$inject = [
+ 'canvas',
+ 'eventBus',
+ 'elementRegistry',
+ 'overlays'
+];
\ No newline at end of file
diff --git a/lib/features/drilldown/SubprocessCompatibility.js b/lib/features/drilldown/SubprocessCompatibility.js
index dd7eaed87c..5aa57b8a68 100644
--- a/lib/features/drilldown/SubprocessCompatibility.js
+++ b/lib/features/drilldown/SubprocessCompatibility.js
@@ -83,6 +83,15 @@ SubprocessCompatibility.prototype.createNewDiagrams = function(plane) {
var newDiagrams = [];
+ // create new planes for all collapsed subprocesses, even when they are empty
+ collapsedElements.forEach(function(element) {
+ if (!self._processToDiagramMap[element.id]) {
+ var diagram = self.createDiagram(element);
+ self._processToDiagramMap[element.id] = diagram;
+ newDiagrams.push(diagram);
+ }
+ });
+
elementsToMove.forEach(function(element) {
var diElement = element.diElement;
var parent = element.parent;
@@ -98,12 +107,6 @@ SubprocessCompatibility.prototype.createNewDiagrams = function(plane) {
}
var diagram = self._processToDiagramMap[parent.id];
- if (!diagram) {
- diagram = self.createDiagram(parent);
- self._processToDiagramMap[parent.id] = diagram;
- newDiagrams.push(diagram);
- }
-
self.moveToDiPlane(diElement, diagram.plane);
});
diff --git a/lib/features/drilldown/index.js b/lib/features/drilldown/index.js
index 51590c5114..328c53c01e 100644
--- a/lib/features/drilldown/index.js
+++ b/lib/features/drilldown/index.js
@@ -1,14 +1,17 @@
import OverlaysModule from 'diagram-js/lib/features/overlays';
import ChangeSupportModule from 'diagram-js/lib/features/change-support';
+import PlanesModule from 'diagram-js/lib/features/planes';
-import DrilldownOverlays from './DrilldownOverlays';
+import DrilldownBreadcrumbs from './DrilldownBreadcrumbs';
import DrilldownCentering from './DrilldownCentering';
import SubprocessCompatibility from './SubprocessCompatibility';
+import DrilldownOverlayBehavior from './DrilldownOverlayBehavior';
export default {
- __depends__: [ OverlaysModule, ChangeSupportModule ],
- __init__: [ 'drilldownOverlays', 'drilldownCentering', 'subprocessCompatibility'],
- drilldownOverlays: [ 'type', DrilldownOverlays ],
+ __depends__: [ OverlaysModule, ChangeSupportModule, PlanesModule ],
+ __init__: [ 'drilldownBreadcrumbs', 'drilldownOverlayBehavior', 'drilldownCentering', 'subprocessCompatibility'],
+ drilldownBreadcrumbs: [ 'type', DrilldownBreadcrumbs ],
drilldownCentering: [ 'type', DrilldownCentering ],
+ drilldownOverlayBehavior: [ 'type', DrilldownOverlayBehavior ],
subprocessCompatibility: [ 'type', SubprocessCompatibility ]
};
\ No newline at end of file
diff --git a/lib/features/modeling/behavior/SubProcessPlaneBehavior.js b/lib/features/modeling/behavior/SubProcessPlaneBehavior.js
new file mode 100644
index 0000000000..31ffe28879
--- /dev/null
+++ b/lib/features/modeling/behavior/SubProcessPlaneBehavior.js
@@ -0,0 +1,212 @@
+import inherits from 'inherits';
+
+import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
+
+import { isExpanded } from '../../../util/DiUtil';
+import { getBusinessObject, is } from '../../../util/ModelUtil';
+
+/**
+ * Creates diPlanes and canvas planes when collapses subprocesses are created.
+ *
+ * @param {Canvas} canvas
+ * @param {EventBus} eventBus
+ * @param {Modeling} modeling
+ * @param {ElementFactory} elementFactory
+ * @param {BpmnFactory} bpmnFactory
+ * @param {Bpmnjs} bpmnjs
+ */
+export default function SubProcessPlaneBehavior(
+ canvas, eventBus, modeling,
+ elementFactory, bpmnFactory, bpmnjs) {
+
+ CommandInterceptor.call(this, eventBus);
+
+ this._canvas = canvas;
+ this._eventBus = eventBus;
+ this._modeling = modeling;
+ this._elementFactory = elementFactory;
+ this._bpmnFactory = bpmnFactory;
+ this._bpmnjs = bpmnjs;
+
+ var self = this;
+
+ function isCollapsedSubProcess(element) {
+ return is(element, 'bpmn:SubProcess') && !isExpanded(element);
+ }
+
+ function createPlane(context) {
+ var shape = context.shape,
+ plane = context.targetPlane,
+ rootElement = plane && plane.rootElement;
+
+ var businessObject = getBusinessObject(shape);
+
+ rootElement = self._addDiagram(rootElement || businessObject);
+ context.targetPlane = canvas.createPlane(
+ plane ||
+ { name: businessObject.id, rootElement: rootElement });
+ }
+
+ function removePlane(context) {
+ var shape = context.shape;
+
+ var businessObject = getBusinessObject(shape);
+
+ self._removeDiagram(businessObject);
+
+ context.targetPlane = canvas.removePlane(businessObject.id);
+ }
+
+
+ // add plane elements for newly created sub-processes
+ // this ensures we can actually drill down into the element
+ this.executed('shape.create', function(context) {
+ var shape = context.shape;
+
+ if (!isCollapsedSubProcess(shape)) {
+ return;
+ }
+
+ createPlane(context);
+ }, true);
+
+
+ this.reverted('shape.create', 500, function(context) {
+ var shape = context.shape;
+
+ if (!isCollapsedSubProcess(shape)) {
+ return;
+ }
+
+ removePlane(context);
+ }, true);
+
+
+ this.executed('element.updateProperties', function(context) {
+ var shape = context.element;
+
+ if (!isCollapsedSubProcess(shape)) {
+ return;
+ }
+
+ var properties = context.properties;
+ var oldProperties = context.oldProperties;
+
+ var oldId = oldProperties.id,
+ newId = properties.id;
+
+ if (oldId === newId) {
+ return;
+ }
+
+ canvas.renamePlane(oldId, newId);
+ }, true);
+
+
+ this.reverted('element.updateProperties', function(context) {
+ var shape = context.element;
+ var properties = context.properties;
+ var oldProperties = context.oldProperties;
+
+ var oldId = oldProperties.id,
+ newId = properties.id;
+
+
+ if (!isCollapsedSubProcess(shape)) {
+ return;
+ }
+
+ if (oldId === newId) {
+ return;
+ }
+
+ canvas.renamePlane(newId, oldId);
+ }, true);
+
+}
+
+inherits(SubProcessPlaneBehavior, CommandInterceptor);
+
+
+/**
+* Adds a given diagram to the definitions and returns a .
+*
+* @param {Object} planeElement
+*/
+SubProcessPlaneBehavior.prototype._addDiagram = function(planeElement) {
+ var bpmnjs = this._bpmnjs;
+ var diagrams = bpmnjs.getDefinitions().diagrams;
+
+ if (!planeElement.businessObject) {
+ planeElement = this._createDiagram(planeElement);
+ }
+
+ diagrams.push(planeElement.di.$parent);
+
+ return planeElement;
+};
+
+/**
+* Creates a new plane element for the given sub process.
+*
+* @param {Object} bpmnElement
+*
+* @return {Object} new diagram element
+*/
+SubProcessPlaneBehavior.prototype._createDiagram = function(bpmnElement) {
+ var bpmnFactory = this._bpmnFactory;
+ var elementFactory = this._elementFactory;
+
+ var diPlane = bpmnFactory.create('bpmndi:BPMNPlane', {
+ bpmnElement: bpmnElement
+ });
+ var diDiagram = bpmnFactory.create('bpmndi:BPMNDiagram', {
+ plane: diPlane
+ });
+ diPlane.$parent = diDiagram;
+
+ // add a virtual element (not being drawn),
+ // a copy cat of our BpmnImporter code
+ var planeElement = elementFactory.createRoot({
+ id: bpmnElement.id + '_plane',
+ type: bpmnElement.$type,
+ di: diPlane,
+ businessObject: bpmnElement,
+ collapsed: true
+ });
+
+ return planeElement;
+};
+
+/**
+ * Removes the diagram for a given root element
+ *
+ * @param {Object} rootElement
+ * @returns {Object} removed bpmndi:BPMNDiagram
+ */
+SubProcessPlaneBehavior.prototype._removeDiagram = function(rootElement) {
+ var bpmnjs = this._bpmnjs;
+
+ var diagrams = bpmnjs.getDefinitions().diagrams;
+
+ var removedDiagram = diagrams.find(function(diagram) {
+ return diagram.plane.bpmnElement.id === rootElement.id;
+ });
+
+ diagrams.splice(diagrams.indexOf(removedDiagram), 1);
+
+ return removedDiagram;
+};
+
+
+SubProcessPlaneBehavior.$inject = [
+ 'canvas',
+ 'eventBus',
+ 'modeling',
+ 'elementFactory',
+ 'bpmnFactory',
+ 'bpmnjs'
+];
+
+
+
diff --git a/lib/features/modeling/behavior/index.js b/lib/features/modeling/behavior/index.js
index 6c99ee6f71..045613d3e1 100644
--- a/lib/features/modeling/behavior/index.js
+++ b/lib/features/modeling/behavior/index.js
@@ -28,6 +28,7 @@ import ResizeLaneBehavior from './ResizeLaneBehavior';
import RemoveElementBehavior from './RemoveElementBehavior';
import SpaceToolBehavior from './SpaceToolBehavior';
import SubProcessStartEventBehavior from './SubProcessStartEventBehavior';
+import SubProcessPlaneBehavior from './SubProcessPlaneBehavior';
import ToggleElementCollapseBehaviour from './ToggleElementCollapseBehaviour';
import UnclaimIdBehavior from './UnclaimIdBehavior';
import UpdateFlowNodeRefsBehavior from './UpdateFlowNodeRefsBehavior';
@@ -66,6 +67,7 @@ export default {
'toggleElementCollapseBehaviour',
'spaceToolBehavior',
'subProcessStartEventBehavior',
+ 'subProcessPlaneBehavior',
'unclaimIdBehavior',
'unsetDefaultFlowBehavior',
'updateFlowNodeRefsBehavior'
@@ -101,6 +103,7 @@ export default {
toggleElementCollapseBehaviour : [ 'type', ToggleElementCollapseBehaviour ],
spaceToolBehavior: [ 'type', SpaceToolBehavior ],
subProcessStartEventBehavior: [ 'type', SubProcessStartEventBehavior ],
+ subProcessPlaneBehavior: [ 'type', SubProcessPlaneBehavior ],
unclaimIdBehavior: [ 'type', UnclaimIdBehavior ],
updateFlowNodeRefsBehavior: [ 'type', UpdateFlowNodeRefsBehavior ],
unsetDefaultFlowBehavior: [ 'type', UnsetDefaultFlowBehavior ]
diff --git a/lib/import/BpmnImporter.js b/lib/import/BpmnImporter.js
index 78bdc96035..b0b38eb913 100644
--- a/lib/import/BpmnImporter.js
+++ b/lib/import/BpmnImporter.js
@@ -26,6 +26,13 @@ import {
} from './Util';
+/**
+ * @param {ModdleElement} semantic
+ * @param {ModdleElement} di
+ * @param {Object} [attrs=null]
+ *
+ * @return {Object}
+ */
function elementData(semantic, di, attrs) {
return assign({
id: semantic.id,
@@ -105,13 +112,12 @@ BpmnImporter.prototype.add = function(semantic, di, parentElement) {
// invisible root element (process, subprocess or collaboration)
if (is(di, 'bpmndi:BPMNPlane')) {
- // add a virtual element (not being drawn)
- element = this._elementFactory.createRoot(elementData(semantic, di));
+ var attrs = is(semantic, 'bpmn:SubProcess')
+ ? { id: semantic.id + '_plane' }
+ : {};
- // for subprocesses, the id is already defined on the collapsed shape
- if (is(semantic, 'bpmn:SubProcess')) {
- element.id = element.id + '_plane';
- }
+ // add a virtual element (not being drawn)
+ element = this._elementFactory.createRoot(elementData(semantic, di, attrs));
this._canvas.createPlane(semantic.id, element);
}
diff --git a/package-lock.json b/package-lock.json
index afa4dfac90..62c4dc6e59 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3333,9 +3333,8 @@
"dev": true
},
"diagram-js": {
- "version": "7.8.1",
- "resolved": "https://registry.npmjs.org/diagram-js/-/diagram-js-7.8.1.tgz",
- "integrity": "sha512-Ziy5vTmB8V/kxuhgxQXdnNxSYnqlWxFrBih37MOOglDzyQ5mBIA8tFNssp/ncHpZmhTGC8sb54lYknovzyrrzg==",
+ "version": "github:bpmn-io/diagram-js#ae86c626e7ec8ab021b5cf40f3e1a24e66365566",
+ "from": "github:bpmn-io/diagram-js#create-planes-from-descriptor",
"requires": {
"css.escape": "^1.5.1",
"didi": "^5.2.1",
diff --git a/package.json b/package.json
index 460bf35ad3..3e94661550 100644
--- a/package.json
+++ b/package.json
@@ -100,7 +100,7 @@
"dependencies": {
"bpmn-moddle": "^7.1.2",
"css.escape": "^1.5.1",
- "diagram-js": "^7.8.1",
+ "diagram-js": "github:bpmn-io/diagram-js#create-planes-from-descriptor",
"diagram-js-direct-editing": "^1.6.3",
"ids": "^1.0.0",
"inherits": "^2.0.4",
diff --git a/test/fixtures/bpmn/collapsed-sub-process-legacy.bpmn b/test/fixtures/bpmn/collapsed-sub-process-legacy.bpmn
new file mode 100644
index 0000000000..3641909928
--- /dev/null
+++ b/test/fixtures/bpmn/collapsed-sub-process-legacy.bpmn
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+ Flow_0obnxbt
+
+
+
+ Flow_1d6ajf7
+
+
+ Flow_0obnxbt
+ Flow_1d6ajf7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/spec/ModelerSpec.js b/test/spec/ModelerSpec.js
index c023e04630..d016f9a2c8 100644
--- a/test/spec/ModelerSpec.js
+++ b/test/spec/ModelerSpec.js
@@ -710,8 +710,7 @@ describe('Modeler', function() {
describe('drill down', function() {
- it('should allow drill down into collapsed sub-process', function() {
- var xml = require('../fixtures/bpmn/collapsed-sub-process.bpmn');
+ function verifyDrilldown(xml) {
return createModeler(xml).then(function() {
var drilldown = container.querySelector('.bjs-drilldown');
@@ -730,6 +729,19 @@ describe('Modeler', function() {
expect(djsContainer.classList.contains('bjs-breadcrumbs-shown')).to.be.true;
});
+ }
+
+ it('should allow drill down into collapsed sub-process', function() {
+ var xml = require('../fixtures/bpmn/collapsed-sub-process.bpmn');
+
+ return verifyDrilldown(xml);
+ });
+
+
+ it('should allow drill down into legacy collapsed sub-process', function() {
+ var xml = require('../fixtures/bpmn/collapsed-sub-process-legacy.bpmn');
+
+ return verifyDrilldown(xml);
});
});
diff --git a/test/spec/ViewerSpec.js b/test/spec/ViewerSpec.js
index 32f87c5d7a..d41c867b15 100644
--- a/test/spec/ViewerSpec.js
+++ b/test/spec/ViewerSpec.js
@@ -372,9 +372,7 @@ describe('Viewer', function() {
describe('drill down', function() {
- it('should allow drill down into collapsed sub-process', function() {
-
- var xml = require('../fixtures/bpmn/collapsed-sub-process.bpmn');
+ function verifyDrilldown(xml) {
return createViewer(container, Viewer, xml).then(function() {
var drilldown = container.querySelector('.bjs-drilldown');
@@ -393,6 +391,19 @@ describe('Viewer', function() {
expect(djsContainer.classList.contains('bjs-breadcrumbs-shown')).to.be.true;
});
+ }
+
+ it('should allow drill down into collapsed sub-process', function() {
+ var xml = require('../fixtures/bpmn/collapsed-sub-process.bpmn');
+
+ return verifyDrilldown(xml);
+ });
+
+
+ it('should allow drill down into legacy collapsed sub-process', function() {
+ var xml = require('../fixtures/bpmn/collapsed-sub-process-legacy.bpmn');
+
+ return verifyDrilldown(xml);
});
});
diff --git a/test/spec/features/drilldown/DrilldownOverlayBehaviorSpec.bpmn b/test/spec/features/drilldown/DrilldownOverlayBehaviorSpec.bpmn
new file mode 100644
index 0000000000..4164caee63
--- /dev/null
+++ b/test/spec/features/drilldown/DrilldownOverlayBehaviorSpec.bpmn
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/spec/features/drilldown/DrilldownOverlaysBehaviorSpec.js b/test/spec/features/drilldown/DrilldownOverlaysBehaviorSpec.js
new file mode 100644
index 0000000000..3f39ea8771
--- /dev/null
+++ b/test/spec/features/drilldown/DrilldownOverlaysBehaviorSpec.js
@@ -0,0 +1,265 @@
+import {
+ bootstrapModeler,
+ inject
+} from 'test/TestHelper';
+
+import coreModule from 'lib/core';
+import modelingModule from 'lib/features/modeling';
+import replaceModule from 'lib/features/replace';
+import drilldownModule from 'lib/features/drilldown';
+import { classes } from 'min-dom';
+
+
+describe('features/modeling/behavior - subprocess planes', function() {
+
+ var diagramXML = require('./DrilldownOverlayBehaviorSpec.bpmn');
+
+ beforeEach(bootstrapModeler(diagramXML, {
+ modules: [
+ coreModule,
+ modelingModule,
+ replaceModule,
+ drilldownModule
+ ]
+ }));
+
+
+ describe('create new drilldowns', function() {
+
+ it('should create drilldown for new process',
+ inject(function(elementFactory, modeling, canvas, overlays) {
+
+ // given
+ var subProcess = elementFactory.createShape({
+ type: 'bpmn:SubProcess',
+ isExpanded: false
+ });
+
+ // when
+ modeling.createShape(subProcess, { x: 300, y: 300 }, canvas.getRootElement());
+
+ // then
+ var elementOverlays = overlays.get({ element: subProcess });
+ expect(elementOverlays).to.not.be.empty;
+
+ })
+ );
+
+
+ it('should not create drilldown for expanded subprocess',
+ inject(function(elementFactory, modeling, canvas, overlays) {
+
+ // given
+ var subProcess = elementFactory.createShape({
+ type: 'bpmn:SubProcess',
+ isExpanded: true
+ });
+
+ // when
+ modeling.createShape(subProcess, { x: 300, y: 300 }, canvas.getRootElement());
+
+ // then
+ var elementOverlays = overlays.get({ element: subProcess });
+ expect(elementOverlays).to.be.empty;
+ })
+ );
+
+
+ it('should undo',
+ inject(function(elementFactory, modeling, commandStack, canvas, overlays) {
+
+ // given
+ var subProcess = elementFactory.createShape({
+ type: 'bpmn:SubProcess',
+ isExpanded: false
+ });
+ modeling.createShape(subProcess, { x: 300, y: 300 }, canvas.getRootElement());
+
+ // when
+ commandStack.undo();
+
+ // then
+ var elementOverlays = overlays.get({ element: subProcess });
+ expect(elementOverlays).to.be.empty;
+ })
+ );
+
+
+ it('should redo',
+ inject(function(elementFactory, modeling, commandStack, canvas, overlays) {
+
+ // given
+ var subProcess = elementFactory.createShape({
+ type: 'bpmn:SubProcess',
+ isExpanded: false
+ });
+ modeling.createShape(subProcess, { x: 300, y: 300 }, canvas.getRootElement());
+
+ // when
+ commandStack.undo();
+ commandStack.redo();
+
+ // then
+ var elementOverlays = overlays.get({ element: subProcess });
+ expect(elementOverlays).to.not.be.empty;
+ })
+ );
+
+ });
+
+
+ describe('overlay visibility', function() {
+
+ describe('empty subprocess', function() {
+
+ it('should hide drilldown', inject(function(elementRegistry, overlays) {
+
+ // given
+ var subProcess = elementRegistry.get('Subprocess_empty');
+
+ // then
+ var overlay = overlays.get({ element: subProcess })[0];
+
+ expect(classes(overlay.html).contains('bjs-drilldown-empty')).to.be.true;
+ }));
+
+
+ it('should show when content is added',
+ inject(function(elementRegistry, overlays, elementFactory, modeling, canvas) {
+
+ // given
+ var subProcess = elementRegistry.get('Subprocess_empty');
+ var task = elementFactory.createShape({ type: 'bpmn:Task' });
+ var planeRoot = canvas.getPlane('Subprocess_empty').rootElement;
+
+ // when
+ modeling.createShape(task, { x: 300, y: 300 }, planeRoot);
+
+ // then
+ var overlay = overlays.get({ element: subProcess })[0];
+
+ expect(classes(overlay.html).contains('bjs-drilldown-empty')).to.be.false;
+ })
+ );
+
+
+ it('should undo',
+ inject(function(elementRegistry, overlays, elementFactory,
+ modeling, canvas, commandStack) {
+
+ // given
+ var subProcess = elementRegistry.get('Subprocess_empty');
+ var task = elementFactory.createShape({ type: 'bpmn:Task' });
+ var planeRoot = canvas.getPlane('Subprocess_empty').rootElement;
+ modeling.createShape(task, { x: 300, y: 300 }, planeRoot);
+
+ // when
+ commandStack.undo();
+
+ // then
+ var overlay = overlays.get({ element: subProcess })[0];
+
+ expect(classes(overlay.html).contains('bjs-drilldown-empty')).to.be.true;
+ })
+ );
+
+
+ it('should redo',
+ inject(function(elementRegistry, overlays, elementFactory,
+ modeling, canvas, commandStack) {
+
+ // given
+ var subProcess = elementRegistry.get('Subprocess_empty');
+ var task = elementFactory.createShape({ type: 'bpmn:Task' });
+ var planeRoot = canvas.getPlane('Subprocess_empty').rootElement;
+ modeling.createShape(task, { x: 300, y: 300 }, planeRoot);
+
+ // when
+ commandStack.undo();
+ commandStack.redo();
+
+ // then
+ var overlay = overlays.get({ element: subProcess })[0];
+
+ expect(classes(overlay.html).contains('bjs-drilldown-empty')).to.be.false;
+ })
+ );
+
+ });
+
+
+ describe('subprocess with content', function() {
+
+ it('should show drilldown', inject(function(elementRegistry, overlays) {
+
+ // given
+ var subProcess = elementRegistry.get('Subprocess_with_content');
+
+ // then
+ var overlay = overlays.get({ element: subProcess })[0];
+
+ expect(classes(overlay.html).contains('bjs-drilldown-empty')).to.be.false;
+ }));
+
+
+ it('should hide when content is removed',
+ inject(function(elementRegistry, overlays, modeling) {
+
+ // given
+ var subProcess = elementRegistry.get('Subprocess_with_content');
+ var startEvent = elementRegistry.get('StartEvent_embedded');
+
+ // when
+ modeling.removeShape(startEvent);
+
+ // then
+ var overlay = overlays.get({ element: subProcess })[0];
+
+ expect(classes(overlay.html).contains('bjs-drilldown-empty')).to.be.true;
+ })
+ );
+
+
+ it('should undo',
+ inject(function(elementRegistry, overlays, modeling, commandStack) {
+
+ // given
+ var subProcess = elementRegistry.get('Subprocess_with_content');
+ var startEvent = elementRegistry.get('StartEvent_embedded');
+ modeling.removeShape(startEvent);
+
+ // when
+ commandStack.undo();
+
+ // then
+ var overlay = overlays.get({ element: subProcess })[0];
+
+ expect(classes(overlay.html).contains('bjs-drilldown-empty')).to.be.false;
+ })
+ );
+
+
+ it('should redo',
+ inject(function(elementRegistry, overlays, modeling, commandStack) {
+
+ // given
+ var subProcess = elementRegistry.get('Subprocess_with_content');
+ var startEvent = elementRegistry.get('StartEvent_embedded');
+ modeling.removeShape(startEvent);
+
+ // when
+ commandStack.undo();
+ commandStack.redo();
+
+ // then
+ var overlay = overlays.get({ element: subProcess })[0];
+
+ expect(classes(overlay.html).contains('bjs-drilldown-empty')).to.be.true;
+ })
+ );
+
+ });
+
+ });
+
+});
diff --git a/test/spec/features/drilldown/DrilldownSpec.js b/test/spec/features/drilldown/DrilldownSpec.js
index fe9b11a846..b1d95144ac 100644
--- a/test/spec/features/drilldown/DrilldownSpec.js
+++ b/test/spec/features/drilldown/DrilldownSpec.js
@@ -195,6 +195,16 @@ describe('features - drilldown', function() {
expect(startEvent.y).to.equal(160);
}));
+
+ it('should create new planes for empty processes', inject(function(canvas) {
+
+ // when
+ var emptyPlane = canvas.getPlane('emptyProcess');
+
+ // then
+ expect(emptyPlane).to.exist;
+ }));
+
});
});
diff --git a/test/spec/features/drilldown/legacy-subprocesses.bpmn b/test/spec/features/drilldown/legacy-subprocesses.bpmn
index 4626c1f769..777823e07b 100644
--- a/test/spec/features/drilldown/legacy-subprocesses.bpmn
+++ b/test/spec/features/drilldown/legacy-subprocesses.bpmn
@@ -17,6 +17,7 @@
+
@@ -37,15 +38,18 @@
+
+
+
-
-
+
+
-
+
\ No newline at end of file
diff --git a/test/spec/features/modeling/behavior/SubProcessBehavior.planes.bpmn b/test/spec/features/modeling/behavior/SubProcessBehavior.planes.bpmn
new file mode 100644
index 0000000000..25d99d994b
--- /dev/null
+++ b/test/spec/features/modeling/behavior/SubProcessBehavior.planes.bpmn
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/spec/features/modeling/behavior/SubProcessPlaneBehaviorSpec.js b/test/spec/features/modeling/behavior/SubProcessPlaneBehaviorSpec.js
new file mode 100644
index 0000000000..234e5253be
--- /dev/null
+++ b/test/spec/features/modeling/behavior/SubProcessPlaneBehaviorSpec.js
@@ -0,0 +1,199 @@
+import {
+ bootstrapModeler,
+ inject
+} from 'test/TestHelper';
+
+import coreModule from 'lib/core';
+import modelingModule from 'lib/features/modeling';
+import replaceModule from 'lib/features/replace';
+
+describe('features/modeling/behavior - subprocess planes', function() {
+
+ var diagramXML = require('./SubProcessBehavior.planes.bpmn');
+
+ beforeEach(bootstrapModeler(diagramXML, {
+ modules: [
+ coreModule,
+ modelingModule,
+ replaceModule
+ ]
+ }));
+
+
+ describe('create', function() {
+
+ it('should create new diagram for collapsed subprocess', inject(function(elementFactory, modeling, canvas, bpmnjs) {
+
+ // given
+ var subProcess = elementFactory.createShape({
+ type: 'bpmn:SubProcess',
+ isExpanded: false
+ });
+
+ // when
+ modeling.createShape(subProcess, { x: 300, y: 300 }, canvas.getRootElement());
+
+ // then
+ var diagrams = bpmnjs.getDefinitions().diagrams;
+ expect(diagrams.length).to.equal(2);
+ expect(canvas.getPlane(subProcess.id)).to.exist;
+ }));
+
+
+ it('should not create new plane for expanded subprocess', inject(function(elementFactory, modeling, canvas, bpmnjs) {
+
+ // given
+ var subProcess = elementFactory.createShape({
+ type: 'bpmn:SubProcess',
+ isExpanded: true
+ });
+
+ // when
+ modeling.createShape(subProcess, { x: 300, y: 300 }, canvas.getRootElement());
+
+ // then
+ var diagrams = bpmnjs.getDefinitions().diagrams;
+ expect(diagrams.length).to.equal(1);
+ expect(canvas.getPlane(subProcess.id)).to.not.exist;
+ }));
+
+
+ it('should undo', inject(function(elementFactory, modeling, commandStack, canvas, bpmnjs) {
+
+ // given
+ var subProcess = elementFactory.createShape({
+ type: 'bpmn:SubProcess',
+ isExpanded: false
+ });
+ modeling.createShape(subProcess, { x: 300, y: 300 }, canvas.getRootElement());
+
+ // when
+ commandStack.undo();
+
+ // then
+ var diagrams = bpmnjs.getDefinitions().diagrams;
+ expect(diagrams.length).to.equal(1);
+ expect(canvas.getPlane(subProcess.id)).to.not.exist;
+ }));
+
+
+ it('should redo', inject(function(elementFactory, modeling, commandStack, canvas, bpmnjs) {
+
+ // given
+ var subProcess = elementFactory.createShape({
+ type: 'bpmn:SubProcess',
+ isExpanded: false
+ });
+ modeling.createShape(subProcess, { x: 300, y: 300 }, canvas.getRootElement());
+ var plane = canvas.getPlane(subProcess.id);
+
+ // when
+ commandStack.undo();
+ commandStack.redo();
+
+ // then
+ var diagrams = bpmnjs.getDefinitions().diagrams;
+ expect(diagrams.length).to.equal(2);
+ expect(canvas.getPlane(subProcess.id)).to.exist;
+ expect(canvas.getPlane(subProcess.id)).to.equal(plane);
+ }));
+
+ });
+
+
+ describe('replace', function() {
+
+ describe('task -> collapsed subprocess', function() {
+
+ it('should add new diagram for collapsed subprocess', inject(
+ function(elementRegistry, bpmnReplace, bpmnjs, canvas) {
+
+ // given
+ var task = elementRegistry.get('Task_1'),
+ collapsedSubProcess;
+
+ // when
+ collapsedSubProcess = bpmnReplace.replaceElement(task, {
+ type: 'bpmn:SubProcess',
+ isExpanded: false
+ });
+
+ // then
+ var diagrams = bpmnjs.getDefinitions().diagrams;
+ expect(diagrams.length).to.equal(2);
+ expect(canvas.getPlane(collapsedSubProcess.id)).to.exist;
+ }
+ ));
+
+
+ it('should undo', inject(
+ function(elementRegistry, bpmnReplace, bpmnjs, canvas, commandStack) {
+
+ // given
+ var task = elementRegistry.get('Task_1'),
+ collapsedSubProcess = bpmnReplace.replaceElement(task, {
+ type: 'bpmn:SubProcess',
+ isExpanded: false
+ });
+
+ // when
+ commandStack.undo();
+
+
+ // then
+ var diagrams = bpmnjs.getDefinitions().diagrams;
+ expect(diagrams.length).to.equal(1);
+ expect(canvas.getPlane(collapsedSubProcess.id)).to.not.exist;
+ }
+ ));
+
+
+ it('should redo', inject(
+ function(elementRegistry, bpmnReplace, bpmnjs, canvas, commandStack) {
+
+ // given
+ var task = elementRegistry.get('Task_1'),
+ collapsedSubProcess = bpmnReplace.replaceElement(task, {
+ type: 'bpmn:SubProcess',
+ isExpanded: false
+ });
+
+ // when
+ commandStack.undo();
+ commandStack.redo();
+
+ // then
+ var diagrams = bpmnjs.getDefinitions().diagrams;
+ expect(diagrams.length).to.equal(2);
+ expect(canvas.getPlane(collapsedSubProcess.id)).to.exist;
+ }
+ ));
+ });
+
+ describe('task -> expanded subprocess', function() {
+
+ it('should not add new diagram for collapsed subprocess', inject(
+ function(elementRegistry, bpmnReplace, bpmnjs, canvas) {
+
+ // given
+ var task = elementRegistry.get('Task_1'),
+ collapsedSubProcess;
+
+ // when
+ collapsedSubProcess = bpmnReplace.replaceElement(task, {
+ type: 'bpmn:SubProcess',
+ isExpanded: true
+ });
+
+ // then
+ var diagrams = bpmnjs.getDefinitions().diagrams;
+ expect(diagrams.length).to.equal(1);
+ expect(canvas.getPlane(collapsedSubProcess.id)).to.not.exist;
+ }
+ ));
+
+ });
+
+ });
+
+});
diff --git a/test/spec/features/ordering/BpmnDiOrderingSpec.js b/test/spec/features/ordering/BpmnDiOrderingSpec.js
index 665cdfb021..450da69d59 100644
--- a/test/spec/features/ordering/BpmnDiOrderingSpec.js
+++ b/test/spec/features/ordering/BpmnDiOrderingSpec.js
@@ -109,6 +109,33 @@ describe('features/modeling - di ordering', function() {
task1.id,
]);
});
+
+ it('should order subprocess planes', function() {
+
+ // given
+ var canvas = getBpmnJS().get('canvas'),
+ root;
+
+ // when
+ var subProcess = add(
+ { type: 'bpmn:SubProcess', isExpanded: false, width: 300, height: 200 }, { x: 300, y: 200 }
+ );
+
+ var participant = add({ type: 'bpmn:Participant', width: 500, height: 300 }, { x: 300, y: 200 }),
+ task1 = add({ type: 'bpmn:Task' }, { x: 250, y: 200 }, subProcess.id + '_plane');
+
+ root = canvas.getRootElement();
+
+ // then
+ // subProcess id exists twice: once as collapsed shape and once as plane element
+ return expectDiOrder([
+ root.id,
+ participant.id,
+ subProcess.id,
+ subProcess.id,
+ task1.id,
+ ]);
+ });
});
diff --git a/test/spec/features/replace/BpmnReplace.collapsedSubProcess.bpmn b/test/spec/features/replace/BpmnReplace.collapsedSubProcess.bpmn
new file mode 100644
index 0000000000..7c9d08aee5
--- /dev/null
+++ b/test/spec/features/replace/BpmnReplace.collapsedSubProcess.bpmn
@@ -0,0 +1,377 @@
+
+
+
+
+
+ sid-89A3F9F2-CCC8-46C7-816B-DD8AC8A98300
+
+
+ sid-89A3F9F2-CCC8-46C7-816B-DD8AC8A98300
+ sid-F06605E1-AEC1-4B39-8843-4AD3F547B557
+ sid-FC2ECAF5-771E-4ED3-BEF6-EFAB45E79500
+
+
+ sid-F06605E1-AEC1-4B39-8843-4AD3F547B557
+ sid-31F6EC44-E44C-4121-B4FE-BD69AF208C05
+
+ sid-EB275CF2-5EF1-44FA-B41B-71EB37CC2657
+
+
+ sid-EB275CF2-5EF1-44FA-B41B-71EB37CC2657
+ sid-FB543319-8DFB-4445-AAA3-720137FB230B
+
+
+
+
+
+
+ sid-FB543319-8DFB-4445-AAA3-720137FB230B
+ sid-B99D259B-1BD5-45FF-BD57-FB99C360BAC0
+
+ sid-472B540C-A0CD-46F4-9640-DF692EC1BFFC
+
+
+ sid-472B540C-A0CD-46F4-9640-DF692EC1BFFC
+ sid-910420B0-D11B-4F9D-B285-703D8AC0BA90
+
+ sid-A7460113-CB75-491D-817B-5E1A8C606B8C
+
+
+ sid-A7460113-CB75-491D-817B-5E1A8C606B8C
+ sid-01982395-64E8-43EF-A6D3-CDD276C312AA
+
+
+ sid-01982395-64E8-43EF-A6D3-CDD276C312AA
+
+
+
+
+
+
+
+ sid-910420B0-D11B-4F9D-B285-703D8AC0BA90
+
+
+
+
+
+
+
+ sid-B99D259B-1BD5-45FF-BD57-FB99C360BAC0
+
+
+
+
+
+
+
+
+
+ sid-FC2ECAF5-771E-4ED3-BEF6-EFAB45E79500
+ sid-5B23450F-AF5E-4519-B134-32107776BD44
+
+ sid-E71F5783-AFE7-44ED-8A9C-378C95087448
+
+
+ sid-E71F5783-AFE7-44ED-8A9C-378C95087448
+ sid-6B9741CD-D94B-41C7-A2EA-63A4C9445E16
+
+
+ sid-6B9741CD-D94B-41C7-A2EA-63A4C9445E16
+ sid-1A9DABC6-6079-4BF2-9D49-C4DC9569C519
+
+ sid-E5404926-738D-4447-87FE-FC6DD1E8BEFC
+
+
+ sid-E5404926-738D-4447-87FE-FC6DD1E8BEFC
+ sid-FED62A8F-6C3A-4BB2-8DE9-18FB0B35B50E
+
+
+ sid-FED62A8F-6C3A-4BB2-8DE9-18FB0B35B50E
+
+
+
+
+
+
+
+ sid-1A9DABC6-6079-4BF2-9D49-C4DC9569C519
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5B23450F-AF5E-4519-B134-32107776BD44
+ sid-31F6EC44-E44C-4121-B4FE-BD69AF208C05
+ sid-F7DA1903-6A1A-4858-AF4B-286A968C957F
+
+
+ sid-DCB98638-BEBD-4548-B501-F0E29AC71ED4
+
+
+
+ sid-DCB98638-BEBD-4548-B501-F0E29AC71ED4
+
+
+ sid-F7DA1903-6A1A-4858-AF4B-286A968C957F
+ sid-3FAE72F2-4037-4CBA-8B89-01D7FC7FF3E3
+
+
+ sid-3FAE72F2-4037-4CBA-8B89-01D7FC7FF3E3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/spec/features/replace/BpmnReplaceSpec.js b/test/spec/features/replace/BpmnReplaceSpec.js
index e4c1b345ec..1df88c2e83 100644
--- a/test/spec/features/replace/BpmnReplaceSpec.js
+++ b/test/spec/features/replace/BpmnReplaceSpec.js
@@ -311,6 +311,81 @@ describe('features/replace - bpmn replace', function() {
});
+ describe('should replace in sub-process (collapsed)', function() {
+
+ var diagramXML = require('./BpmnReplace.collapsedSubProcess.bpmn');
+
+ beforeEach(bootstrapModeler(diagramXML, {
+ modules: testModules,
+ moddleExtensions: {
+ camunda: camundaPackage
+ }
+ }));
+
+
+ beforeEach(inject(function(canvas) {
+ canvas.setActivePlane('SubProcess_Collapsed');
+ }));
+
+
+ it('task', inject(function(elementRegistry, bpmnReplace) {
+
+ // given
+ var task = elementRegistry.get('UserTask');
+ var newElementData = {
+ type: 'bpmn:ServiceTask'
+ };
+
+ // when
+ var newElement = bpmnReplace.replaceElement(task, newElementData);
+
+ // then
+ var businessObject = newElement.businessObject;
+
+ expect(newElement).to.exist;
+ expect(is(businessObject, 'bpmn:ServiceTask')).to.be.true;
+ }));
+
+
+ it('task with collapsed sub-process', inject(function(elementRegistry, bpmnReplace) {
+
+ // given
+ var task = elementRegistry.get('UserTask');
+ var newElementData = {
+ type: 'bpmn:SubProcess'
+ };
+
+ // when
+ var newElement = bpmnReplace.replaceElement(task, newElementData);
+
+ // then
+ var businessObject = newElement.businessObject;
+
+ expect(newElement).to.exist;
+ expect(is(businessObject, 'bpmn:SubProcess')).to.be.true;
+ }));
+
+
+ it('collapsed sub-process with task', inject(function(elementRegistry, bpmnReplace) {
+
+ // given
+ var task = elementRegistry.get('NestedCollapsed_SubProcess');
+ var newElementData = {
+ type: 'bpmn:Task'
+ };
+
+ // when
+ var newElement = bpmnReplace.replaceElement(task, newElementData);
+
+ // then
+ var businessObject = newElement.businessObject;
+
+ expect(newElement).to.exist;
+ expect(is(businessObject, 'bpmn:Task')).to.be.true;
+ }));
+ });
+
+
describe('should replace in collaboration', function() {
var diagramXML = require('./BpmnReplace.collaboration.bpmn');