feat(replace): clone properties when morphing to new element

Closes #647
This commit is contained in:
Ricardo Matias 2017-01-11 15:22:32 +01:00
parent 3d0adc6493
commit a9b68b69e0
10 changed files with 334 additions and 65 deletions

View File

@ -192,8 +192,7 @@ Modeler.prototype._modelingModules = [
require('./features/modeling'),
require('./features/palette'),
require('./features/replace-preview'),
require('./features/snapping'),
require('./features/bpmn-clone')
require('./features/snapping')
];

View File

@ -1,6 +0,0 @@
'use strict';
module.exports = {
__init__: [ 'bpmnClone' ],
bpmnClone: [ 'type', require('./BpmnClone') ]
};

View File

@ -2,11 +2,16 @@
var pick = require('lodash/object/pick'),
assign = require('lodash/object/assign'),
intersection = require('lodash/array/intersection'),
filter = require('lodash/collection/filter'),
has = require('lodash/object/has');
var is = require('../../util/ModelUtil').is,
isExpanded = require('../../util/DiUtil').isExpanded,
isEventSubProcess = require('../../util/DiUtil').isEventSubProcess;
isEventSubProcess = require('../../util/DiUtil').isEventSubProcess,
getProperties = require('../../util/model/ModelCloneUtils').getProperties;
var ModelCloneHelper = require('../../util/model/ModelCloneHelper');
var CUSTOM_PROPERTIES = [
'cancelActivity',
@ -16,6 +21,21 @@ var CUSTOM_PROPERTIES = [
'isInterrupting'
];
var IGNORED_PROPERTIES = [
'id',
'lanes',
'incoming',
'outgoing',
'eventDefinitions',
'processRef',
'flowElements',
'triggeredByEvent',
'dataInputAssociations',
'dataOutputAssociations',
'incomingConversationLinks',
'outgoingConversationLinks'
];
function toggeling(element, target) {
var oldCollapsed = has(element, 'collapsed') ?
@ -41,10 +61,13 @@ function toggeling(element, target) {
}
/**
* This module takes care of replacing BPMN elements
*/
function BpmnReplace(bpmnFactory, replace, selection, modeling) {
function BpmnReplace(bpmnFactory, replace, selection, modeling, moddle) {
var helper = new ModelCloneHelper(moddle);
/**
* Prepares a new business object for the replacement element
@ -63,8 +86,6 @@ function BpmnReplace(bpmnFactory, replace, selection, modeling) {
var type = target.type,
oldBusinessObject = element.businessObject;
if (is(oldBusinessObject, 'bpmn:SubProcess')) {
if (type === 'bpmn:SubProcess') {
if (toggeling(element, target)) {
@ -76,7 +97,6 @@ function BpmnReplace(bpmnFactory, replace, selection, modeling) {
}
}
var newBusinessObject = bpmnFactory.create(type);
var newElement = {
@ -84,6 +104,16 @@ function BpmnReplace(bpmnFactory, replace, selection, modeling) {
businessObject: newBusinessObject
};
var elementProps = getProperties(oldBusinessObject.$descriptor),
newElementProps = getProperties(newBusinessObject.$descriptor, true),
properties = intersection(elementProps, newElementProps);
properties = filter(properties, function(property) {
return IGNORED_PROPERTIES.indexOf(property.replace(/bpmn:/, '')) === -1;
});
newBusinessObject = helper.clone(oldBusinessObject, newBusinessObject, properties);
// initialize custom BPMN extensions
if (target.eventDefinitionType) {
newElement.eventDefinitionType = target.eventDefinitionType;
@ -162,6 +192,6 @@ function BpmnReplace(bpmnFactory, replace, selection, modeling) {
this.replaceElement = replaceElement;
}
BpmnReplace.$inject = [ 'bpmnFactory', 'replace', 'selection', 'modeling' ];
BpmnReplace.$inject = [ 'bpmnFactory', 'replace', 'selection', 'modeling', 'moddle' ];
module.exports = BpmnReplace;

View File

@ -4,4 +4,4 @@ module.exports = {
require('diagram-js/lib/features/selection')
],
bpmnReplace: [ 'type', require('./BpmnReplace') ]
};
};

View File

@ -3,24 +3,33 @@
var forEach = require('lodash/collection/forEach'),
filter = require('lodash/collection/filter'),
isArray = require('lodash/lang/isArray'),
contains = require('lodash/collection/contains'),
map = require('lodash/collection/map');
contains = require('lodash/collection/contains');
function isAllowedIn(extProp, type) {
var allowedIn = extProp.meta.allowedIn;
// '*' is a wildcard, which means any element is allowed to use this property
if (allowedIn.length === 1 && allowedIn[0] === '*') {
return true;
}
return allowedIn.indexOf(type) !== -1;
}
/**
* A bpmn properties cloning interface
*
* @param {Moddle} moddle
*/
function BpmnClone(moddle) {
function ModelCloneHelper(moddle) {
this._moddle = moddle;
}
module.exports = BpmnClone;
BpmnClone.$inject = [ 'moddle' ];
module.exports = ModelCloneHelper;
BpmnClone.prototype.clone = function(oldElement, newElement, properties) {
ModelCloneHelper.prototype.clone = function(oldElement, newElement, properties) {
var moddle = this._moddle;
forEach(properties, function(propName) {
@ -45,10 +54,12 @@ BpmnClone.prototype.clone = function(oldElement, newElement, properties) {
var extProp = moddle.registry.typeMap[extElement.$type];
if (extProp.meta.allowedIn && extProp.meta.allowedIn.indexOf(newElement.$type) !== -1) {
if (extProp.meta.allowedIn && isAllowedIn(extProp, newElement.$type)) {
var newProp = this._deepClone(extElement);
newProp.$parent = newElement.extensionElements;
newElement.extensionElements.values.push(newProp);
}
}, this);
@ -58,6 +69,8 @@ BpmnClone.prototype.clone = function(oldElement, newElement, properties) {
forEach(oldElementProp, function(extElement) {
var newProp = this._deepClone(extElement);
newProp.$parent = newElement;
newElement.documentation.push(newProp);
}, this);
}
@ -66,19 +79,9 @@ BpmnClone.prototype.clone = function(oldElement, newElement, properties) {
return newElement;
};
BpmnClone.prototype._deepClone = function _deepClone(extElement) {
ModelCloneHelper.prototype._deepClone = function _deepClone(extElement) {
var newProp = extElement.$model.create(extElement.$type),
properties;
// figure out which properties we want to assign to the newElement
// we're interested in enumerable ones (todo: double check this)
if (isArray(extElement)) {
properties = map(extElement, function(item) {
return item.$type;
});
} else {
properties = filter(Object.keys(extElement), function(prop) { return prop !== '$type'; });
}
properties = filter(Object.keys(extElement), function(prop) { return prop !== '$type'; });
forEach(properties, function(propName) {
// check if the extElement has this property defined
@ -88,11 +91,17 @@ BpmnClone.prototype._deepClone = function _deepClone(extElement) {
newProp[propName] = [];
forEach(extElement[propName], function(property) {
newProp[propName].push(this._deepClone(property));
var newDeepProp = this._deepClone(property);
newDeepProp.$parent = newProp;
newProp[propName].push(newDeepProp);
}, this);
} else if (extElement[propName].$type) {
newProp[propName] = this._deepClone(extElement[propName]);
newProp[propName].$parent = newProp;
}
} else {
// just assign directly if it's a value

View File

@ -0,0 +1,20 @@
'use strict';
var forEach = require('lodash/collection/forEach');
function getProperties(descriptor, keepDefault) {
var properties = [];
forEach(descriptor.properties, function(property) {
if (keepDefault && property.default) {
return;
}
properties.push(property.ns.name);
});
return properties;
}
module.exports.getProperties = getProperties;

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.7.0-dev">
<bpmn:collaboration id="Collaboration_0j2pyna">
<bpmn:participant id="Participant_0x9lnke" processRef="Process_1" />
</bpmn:collaboration>
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:dataStoreReference id="DataStoreReference_1elrt45" />
<bpmn:dataStoreReference id="DataStoreReference_1j8ymac" />
<bpmn:dataObjectReference id="DataObjectReference_1js94kb" dataObjectRef="DataObject_1l0h55k" />
<bpmn:dataObject id="DataObject_1l0h55k" />
<bpmn:dataObjectReference id="DataObjectReference_0hkbt95" dataObjectRef="DataObject_1iu55n1" />
<bpmn:dataObject id="DataObject_1iu55n1" />
<bpmn:subProcess id="SubProcess_04tmqcs">
<bpmn:userTask id="Task_1" camunda:asyncBefore="true" camunda:jobPriority="100">
<bpmn:documentation>hello world</bpmn:documentation>
<bpmn:extensionElements>
<camunda:inputOutput>
<camunda:inputParameter name="Input_1">foo</camunda:inputParameter>
<camunda:outputParameter name="Output_1">bar</camunda:outputParameter>
</camunda:inputOutput>
<camunda:properties>
<camunda:property name="bar" value="foo" />
</camunda:properties>
<camunda:executionListener class="reallyClassy" event="start" />
<camunda:failedJobRetryTimeCycle>10</camunda:failedJobRetryTimeCycle>
<camunda:taskListener class="foobar" event="create" />
</bpmn:extensionElements>
<bpmn:incoming>SequenceFlow_1e74z8m</bpmn:incoming>
<bpmn:outgoing>SequenceFlow_1tdxph9</bpmn:outgoing>
<bpmn:property id="Property_0j0o7pl" name="__targetRef_placeholder" />
<bpmn:dataInputAssociation id="DataInputAssociation_0xdwl7n">
<bpmn:sourceRef>DataStoreReference_1elrt45</bpmn:sourceRef>
<bpmn:targetRef>Property_0j0o7pl</bpmn:targetRef>
</bpmn:dataInputAssociation>
<bpmn:dataInputAssociation id="DataInputAssociation_188je0k">
<bpmn:sourceRef>DataObjectReference_0hkbt95</bpmn:sourceRef>
<bpmn:targetRef>Property_0j0o7pl</bpmn:targetRef>
</bpmn:dataInputAssociation>
<bpmn:dataOutputAssociation id="DataOutputAssociation_1wf2bxo">
<bpmn:targetRef>DataStoreReference_1j8ymac</bpmn:targetRef>
</bpmn:dataOutputAssociation>
<bpmn:dataOutputAssociation id="DataOutputAssociation_0hr21ne">
<bpmn:targetRef>DataObjectReference_1js94kb</bpmn:targetRef>
</bpmn:dataOutputAssociation>
</bpmn:userTask>
<bpmn:startEvent id="StartEvent_1a4dsh8">
<bpmn:outgoing>SequenceFlow_1e74z8m</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="SequenceFlow_1e74z8m" sourceRef="StartEvent_1a4dsh8" targetRef="Task_1" />
<bpmn:task id="Task_042z61e">
<bpmn:incoming>SequenceFlow_1tdxph9</bpmn:incoming>
</bpmn:task>
<bpmn:sequenceFlow id="SequenceFlow_1tdxph9" sourceRef="Task_1" targetRef="Task_042z61e" />
</bpmn:subProcess>
<bpmn:textAnnotation id="TextAnnotation_1cghzwc" />
<bpmn:association id="Association_0edc446" sourceRef="Task_1" targetRef="TextAnnotation_1cghzwc" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_0j2pyna">
<bpmndi:BPMNShape id="UserTask_033cl9l_di" bpmnElement="Task_1">
<dc:Bounds x="261" y="159.5" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="StartEvent_1a4dsh8_di" bpmnElement="StartEvent_1a4dsh8">
<dc:Bounds x="168" y="181.5" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="186" y="217.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_1e74z8m_di" bpmnElement="SequenceFlow_1e74z8m">
<di:waypoint xsi:type="dc:Point" x="204" y="199.5" />
<di:waypoint xsi:type="dc:Point" x="261" y="199.5" />
<bpmndi:BPMNLabel>
<dc:Bounds x="233" y="174.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Task_042z61e_di" bpmnElement="Task_042z61e">
<dc:Bounds x="441" y="159.5" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_1tdxph9_di" bpmnElement="SequenceFlow_1tdxph9">
<di:waypoint xsi:type="dc:Point" x="361" y="199.5" />
<di:waypoint xsi:type="dc:Point" x="441" y="199.5" />
<bpmndi:BPMNLabel>
<dc:Bounds x="401" y="184.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Participant_0x9lnke_di" bpmnElement="Participant_0x9lnke">
<dc:Bounds x="0" y="0" width="632" height="417" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="TextAnnotation_1cghzwc_di" bpmnElement="TextAnnotation_1cghzwc">
<dc:Bounds x="50" y="30.5" width="100" height="30" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_1elrt45_di" bpmnElement="DataStoreReference_1elrt45">
<dc:Bounds x="211" y="347.5" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="236" y="397.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataStoreReference_1j8ymac_di" bpmnElement="DataStoreReference_1j8ymac">
<dc:Bounds x="345" y="347.5" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="370" y="397.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataObjectReference_1js94kb_di" bpmnElement="DataObjectReference_1js94kb">
<dc:Bounds x="352" y="20.5" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="370" y="70.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataObjectReference_0hkbt95_di" bpmnElement="DataObjectReference_0hkbt95">
<dc:Bounds x="218" y="20.5" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="236" y="70.5" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="SubProcess_04tmqcs_di" bpmnElement="SubProcess_04tmqcs" isExpanded="true">
<dc:Bounds x="153" y="104.5" width="459" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Association_0edc446_di" bpmnElement="Association_0edc446">
<di:waypoint xsi:type="dc:Point" x="265" y="165.5" />
<di:waypoint xsi:type="dc:Point" x="121" y="60.5" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DataInputAssociation_0xdwl7n_di" bpmnElement="DataInputAssociation_0xdwl7n">
<di:waypoint xsi:type="dc:Point" x="244" y="347.5" />
<di:waypoint xsi:type="dc:Point" x="276" y="239.5" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DataOutputAssociation_1wf2bxo_di" bpmnElement="DataOutputAssociation_1wf2bxo">
<di:waypoint xsi:type="dc:Point" x="323" y="239.5" />
<di:waypoint xsi:type="dc:Point" x="354" y="347.5" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DataOutputAssociation_0hr21ne_di" bpmnElement="DataOutputAssociation_0hr21ne">
<di:waypoint xsi:type="dc:Point" x="329" y="159.5" />
<di:waypoint xsi:type="dc:Point" x="368" y="70.5" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DataInputAssociation_188je0k_di" bpmnElement="DataInputAssociation_188je0k">
<di:waypoint xsi:type="dc:Point" x="245" y="70.5" />
<di:waypoint xsi:type="dc:Point" x="275" y="159.5" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -460,6 +460,9 @@
"superClass": [
"Element"
],
"meta": {
"allowedIn": [ "*" ]
},
"properties": [
{
"name": "values",

View File

@ -1169,4 +1169,69 @@ describe('features/replace - bpmn replace', function() {
});
describe('properties', function() {
var clonePropertiesXML = require('../../../fixtures/bpmn/features/replace/clone-properties.bpmn');
var camundaPackage = require('../../../fixtures/json/model/camunda');
beforeEach(bootstrapModeler(clonePropertiesXML, {
modules: testModules,
moddleExtensions: {
camunda: camundaPackage
}
}));
it('should copy properties', inject(function(elementRegistry, bpmnReplace) {
// given
var task = elementRegistry.get('Task_1');
var newElementData = {
type: 'bpmn:ServiceTask'
};
// when
var newElement = bpmnReplace.replaceElement(task, newElementData);
// then
var businessObject = newElement.businessObject;
expect(businessObject.asyncBefore).to.be.true;
expect(businessObject.jobPriority).to.equal('100');
expect(businessObject.documentation[0].text).to.equal('hello world');
var extensionElements = businessObject.extensionElements.values;
expect(extensionElements).to.have.length(4);
expect(is(extensionElements[0], 'camunda:InputOutput')).to.be.true;
expect(is(extensionElements[0].inputParameters[0], 'camunda:InputParameter')).to.be.true;
expect(extensionElements[0].inputParameters[0].name).to.equal('Input_1');
expect(extensionElements[0].inputParameters[0].value).to.equal('foo');
expect(is(extensionElements[0].outputParameters[0], 'camunda:OutputParameter')).to.be.true;
expect(extensionElements[0].outputParameters[0].name).to.equal('Output_1');
expect(extensionElements[0].outputParameters[0].value).to.equal('bar');
expect(is(extensionElements[1], 'camunda:Properties')).to.be.true;
expect(is(extensionElements[1].values[0], 'camunda:Property')).to.be.true;
expect(extensionElements[1].values[0].name).to.equal('bar');
expect(extensionElements[1].values[0].value).to.equal('foo');
expect(is(extensionElements[2], 'camunda:ExecutionListener')).to.be.true;
expect(extensionElements[2].class).to.equal('reallyClassy');
expect(extensionElements[2].event).to.equal('start');
expect(is(extensionElements[3], 'camunda:FailedJobRetryTimeCycle')).to.be.true;
expect(extensionElements[3].body).to.equal('10');
}));
});
});

View File

@ -1,23 +1,24 @@
'use strict';
require('../../../TestHelper');
require('../../TestHelper');
/* global bootstrapModeler, inject */
var bpmnCloneModule = require('../../../../lib/features/bpmn-clone'),
coreModule = require('../../../../lib/core');
var coreModule = require('../../../lib/core');
var camundaPackage = require('../../../fixtures/json/model/camunda');
var ModelCloneHelper = require('../../../lib/util/model/ModelCloneHelper');
var camundaPackage = require('../../fixtures/json/model/camunda');
function getProp(element, property) {
return element && element.$model.properties.get(element, property);
}
describe('features/bpmn-clone', function() {
describe('util/ModelCloneHelper', function() {
var testModules = [ bpmnCloneModule, coreModule ];
var testModules = [ coreModule ];
var basicXML = require('../../../fixtures/bpmn/basic.bpmn');
var basicXML = require('../../fixtures/bpmn/basic.bpmn');
beforeEach(bootstrapModeler(basicXML, {
modules: testModules,
@ -26,33 +27,35 @@ describe('features/bpmn-clone', function() {
}
}));
var helper;
beforeEach(inject(function(moddle) {
helper = new ModelCloneHelper(moddle);
}));
describe('simple', function() {
it('should pass property', inject(function(moddle, bpmnClone) {
it('should pass property', inject(function(moddle) {
// given
var userTask = moddle.create('bpmn:UserTask', {
name: 'Field_1',
stringValue: 'myFieldValue',
asyncBefore: true
});
var serviceTask = bpmnClone.clone(userTask, moddle.create('bpmn:ServiceTask'), [ 'camunda:asyncBefore' ]);
var serviceTask = helper.clone(userTask, moddle.create('bpmn:ServiceTask'), [ 'camunda:asyncBefore' ]);
expect(getProp(serviceTask, 'camunda:asyncBefore')).to.be.true;
}));
it('should not pass property', inject(function(bpmnClone, moddle) {
it('should not pass property', inject(function(moddle) {
// given
var userTask = moddle.create('bpmn:UserTask', {
name: 'Field_1',
stringValue: 'myFieldValue',
assignee: 'foobar'
});
var serviceTask = bpmnClone.clone(userTask, moddle.create('bpmn:ServiceTask'), []);
var serviceTask = helper.clone(userTask, moddle.create('bpmn:ServiceTask'), []);
expect(getProp(serviceTask, 'camunda:assignee')).to.not.exist;
}));
@ -61,26 +64,25 @@ describe('features/bpmn-clone', function() {
describe('nested', function() {
it('should pass nested property - documentation', inject(function(moddle, bpmnClone) {
it('should pass nested property - documentation', inject(function(moddle) {
// given
var userTask = moddle.create('bpmn:UserTask', {
name: 'Field_1',
stringValue: 'myFieldValue'
});
var userTask = moddle.create('bpmn:UserTask');
var docs = userTask.get('documentation');
docs.push(moddle.create('bpmn:Documentation', { textFormat: 'xyz', text: 'FOO\nBAR' }));
docs.push(moddle.create('bpmn:Documentation', { text: '<some /><html></html>' }));
var serviceTask = bpmnClone.clone(userTask, moddle.create('bpmn:ServiceTask'), [ 'bpmn:documentation' ]);
var serviceTask = helper.clone(userTask, moddle.create('bpmn:ServiceTask'), [ 'bpmn:documentation' ]);
var serviceTaskDocs = getProp(serviceTask, 'bpmn:documentation'),
userTaskDocs = getProp(userTask, 'bpmn:documentation');
expect(userTaskDocs[0]).to.not.equal(serviceTaskDocs[0]);
expect(serviceTaskDocs[0].$parent).to.equal(serviceTask);
expect(serviceTaskDocs[0].text).to.equal('FOO\nBAR');
expect(serviceTaskDocs[0].textFormat).to.equal('xyz');
@ -88,7 +90,7 @@ describe('features/bpmn-clone', function() {
}));
it('should pass deeply nested property - executionListener', inject(function(moddle, bpmnClone) {
it('should pass deeply nested property - executionListener', inject(function(moddle) {
// given
var script = moddle.create('camunda:Script', {
@ -104,12 +106,10 @@ describe('features/bpmn-clone', function() {
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ execListener ] });
var userTask = moddle.create('bpmn:UserTask', {
name: 'Field_1',
stringValue: 'myFieldValue',
extensionElements: extensionElements
});
var serviceTask = bpmnClone.clone(userTask, moddle.create('bpmn:ServiceTask'), [
var serviceTask = helper.clone(userTask, moddle.create('bpmn:ServiceTask'), [
'bpmn:extensionElements',
'camunda:executionListener'
]);
@ -118,15 +118,19 @@ describe('features/bpmn-clone', function() {
// then
expect(executionListener.$type).to.equal('camunda:ExecutionListener');
expect(executionListener.$parent).to.equal(serviceTask.extensionElements);
expect(executionListener.event).to.equal('start');
expect(executionListener.script.$type).to.equal('camunda:Script');
expect(executionListener.script.$parent).to.equal(executionListener);
expect(executionListener.script.scriptFormat).to.equal('groovy');
expect(executionListener.script.value).to.equal('foo = bar;');
}));
it('should pass deeply nested property - inputOutput', inject(function(moddle, bpmnClone) {
it('should pass deeply nested property - inputOutput', inject(function(moddle) {
// given
var outputParameter = moddle.create('camunda:OutputParameter', {
@ -147,12 +151,10 @@ describe('features/bpmn-clone', function() {
var extensionElements = moddle.create('bpmn:ExtensionElements', { values: [ inputOutput ] });
var userTask = moddle.create('bpmn:UserTask', {
name: 'Field_1',
stringValue: 'myFieldValue',
extensionElements: extensionElements
});
var serviceTask = bpmnClone.clone(userTask, moddle.create('bpmn:ServiceTask'), [
var serviceTask = helper.clone(userTask, moddle.create('bpmn:ServiceTask'), [
'bpmn:extensionElements',
'camunda:inputOutput'
]);
@ -166,9 +168,15 @@ describe('features/bpmn-clone', function() {
var oldOutParam = userTask.extensionElements.values[0].outputParameters[0];
expect(newOutParam).to.not.equal(oldOutParam);
expect(newOutParam.$parent).to.equal(executionListener);
expect(newOutParam.definition).to.not.equal(oldOutParam.definition);
expect(newOutParam.definition.$parent).to.equal(newOutParam);
expect(newOutParam.definition.items[0]).to.not.equal(oldOutParam.definition.items[0]);
expect(newOutParam.definition.items[0].$parent).to.not.equal(newOutParam.definition.$parent);
expect(newOutParam.$type).to.equal('camunda:OutputParameter');
expect(newOutParam.definition.$type).to.equal('camunda:List');
expect(newOutParam.definition.items[0].value).to.equal('${1+1}');