Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions test/fixtures/zeebe/filtering.bpmn
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?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:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0modwgr" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.44.0" modeler:executionPlatform="Camunda Cloud" modeler:executionPlatformVersion="8.7.0">
<bpmn:process id="Process_1" name="Process_1" isExecutable="true">
<bpmn:subProcess id="SubProcess_1" name="SubProcess_1">
<bpmn:extensionElements>
<zeebe:ioMapping>
<zeebe:input source="=globalFoo" target="subFoo" />
</zeebe:ioMapping>
</bpmn:extensionElements>
<bpmn:scriptTask id="Task_1" name="Task_1">
<bpmn:extensionElements>
<zeebe:script expression="=&#34;Task_1 :: result&#34; + taskFoo" resultVariable="localResult" />
<zeebe:ioMapping>
<zeebe:input source="=subFoo" target="taskFoo" />
<zeebe:output source="=localResult" target="taskResult" />
</zeebe:ioMapping>
</bpmn:extensionElements>
</bpmn:scriptTask>
</bpmn:subProcess>
<bpmn:textAnnotation id="TextAnnotation_0htuzu9">
<bpmn:text>declare: subFoo = globalFoo</bpmn:text>
</bpmn:textAnnotation>
<bpmn:association id="Association_0aa1wd0" associationDirection="None" sourceRef="SubProcess_1" targetRef="TextAnnotation_0htuzu9" />
<bpmn:textAnnotation id="TextAnnotation_07tfbe4">
<bpmn:text>declare: taskFoo = subFoo
read: taskFoo</bpmn:text>
</bpmn:textAnnotation>
<bpmn:association id="Association_17fzlji" associationDirection="None" sourceRef="Task_1" targetRef="TextAnnotation_07tfbe4" />
<bpmn:textAnnotation id="TextAnnotation_0x7whlg">
<bpmn:text>write: localResult (-&gt; depending on taskFoo)</bpmn:text>
</bpmn:textAnnotation>
<bpmn:association id="Association_0yn1gyn" associationDirection="None" sourceRef="Task_1" targetRef="TextAnnotation_0x7whlg" />
<bpmn:textAnnotation id="TextAnnotation_0cxitau">
<bpmn:text>produce: taskResult = localResult</bpmn:text>
</bpmn:textAnnotation>
<bpmn:association id="Association_14e87h9" associationDirection="None" sourceRef="Task_1" targetRef="TextAnnotation_0cxitau" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="Activity_0zpajl6_di" bpmnElement="SubProcess_1" isExpanded="true">
<dc:Bounds x="290" y="180" width="350" height="200" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1ie6k5k_di" bpmnElement="Task_1">
<dc:Bounds x="360" y="240" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Association_0aa1wd0_di" bpmnElement="Association_0aa1wd0">
<di:waypoint x="303" y="180" />
<di:waypoint x="250" y="100" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Association_14e87h9_di" bpmnElement="Association_14e87h9">
<di:waypoint x="451" y="320" />
<di:waypoint x="565" y="430" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Association_17fzlji_di" bpmnElement="Association_17fzlji">
<di:waypoint x="375" y="320" />
<di:waypoint x="283" y="424" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Association_0yn1gyn_di" bpmnElement="Association_0yn1gyn">
<di:waypoint x="404" y="320" />
<di:waypoint x="382" y="480" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="TextAnnotation_0htuzu9_di" bpmnElement="TextAnnotation_0htuzu9">
<dc:Bounds x="190" y="70" width="180" height="29.999998092651367" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="TextAnnotation_0cxitau_di" bpmnElement="TextAnnotation_0cxitau">
<dc:Bounds x="530" y="430" width="200" height="30" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="TextAnnotation_07tfbe4_di" bpmnElement="TextAnnotation_07tfbe4">
<dc:Bounds x="150" y="424" width="170" height="41" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="TextAnnotation_0x7whlg_di" bpmnElement="TextAnnotation_0x7whlg">
<dc:Bounds x="330" y="480" width="209.99998474121094" height="41" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
131 changes: 131 additions & 0 deletions test/spec/zeebe/ZeebeVariableResolver.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import usedVariablesXML from 'test/fixtures/zeebe/used-variables.bpmn';
import usedVariablesScopesXML from 'test/fixtures/zeebe/used-variables.scopes.bpmn';
import readWriteXML from 'test/fixtures/zeebe/read-write.bpmn';
import readWriteHierarchicalXML from 'test/fixtures/zeebe/read-write.hierarchical.bpmn';
import filteringXML from 'test/fixtures/zeebe/filtering.bpmn';

import VariableProvider from 'lib/VariableProvider';
import { getInputOutput } from '../../../lib/base/util/ExtensionElementsUtil';
Expand Down Expand Up @@ -2792,6 +2793,136 @@ describe('ZeebeVariableResolver', function() {

});


describe('filtering', function() {

beforeEach(bootstrapModeler(filteringXML, {
additionalModules: [
ZeebeVariableResolverModule
],
moddleExtensions: {
zeebe: ZeebeModdle
}
}));



Comment on lines +2807 to +2809
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are multiple consecutive blank lines here (after beforeEach(...)), which is inconsistent with the surrounding test formatting and makes the block harder to scan. Consider removing the extra empty line(s) to match the existing style in this spec file.

Copilot uses AI. Check for mistakes.
it('should NOT filter', inject(async function(elementRegistry, variableResolver) {

// given
const task = elementRegistry.get('Task_1');

// when
const variables = await variableResolver.getVariablesForElement(task);

// then
expect(variables).to.variableEqual([
{ name: 'globalFoo', scope: undefined, usedBy: [ 'SubProcess_1' ] },
{ name: 'subFoo', scope: 'SubProcess_1', origin: [ 'SubProcess_1' ], usedBy: [ 'Task_1' ] },
{ name: 'taskFoo', scope: 'Task_1', origin: [ 'Task_1' ], usedBy: [ 'Task_1' ] },
{ name: 'localResult', scope: 'Task_1', origin: [ 'Task_1' ], usedBy: [ 'Task_1' ] },
{ name: 'taskResult', scope: 'Process_1', origin: [ 'Task_1' ] }
]);
}));


it('should filter read', inject(async function(elementRegistry, variableResolver) {

// given
const task = elementRegistry.get('Task_1');

// when
const variables = await variableResolver.getVariablesForElement(task, { read: true });

Comment on lines +2834 to +2836
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variableResolver.getVariablesForElement in lib/zeebe/VariableResolver.js currently expects the 2nd argument to be a Zeebe moddle element (e.g. a zeebe:Input/zeebe:Output) used by getElementNamesToRemove, not an options object like { read: true }. Passing an options object will be treated as a moddle element and will trigger the IO-mapping name filtering logic (e.g. filtering all outputs), so these assertions won't validate the intended read/written/local behavior and may fail for the wrong reasons. Either update the resolver API to support these filter options, or adjust the tests to pass the appropriate moddle element(s) that the current implementation can filter against.

Copilot uses AI. Check for mistakes.
// then
expect(variables).to.variableEqual([
{ name: 'subFoo', scope: 'SubProcess_1', origin: [ 'SubProcess_1' ], usedBy: [ 'Task_1' ] },
{ name: 'taskFoo', scope: 'Task_1', origin: [ 'Task_1' ], usedBy: [ 'Task_1' ] },
{ name: 'localResult', scope: 'Task_1', origin: [ 'Task_1' ], usedBy: [ 'Task_1' ] }
]);
}));


it('should filter read / local', inject(async function(elementRegistry, variableResolver) {

// given
const task = elementRegistry.get('Task_1');

// when
const variables = await variableResolver.getVariablesForElement(task, { read: true, local: true });

// then
expect(variables).to.variableEqual([
{ name: 'taskFoo', scope: 'Task_1', origin: [ 'Task_1' ], usedBy: [ 'Task_1' ] },
{ name: 'localResult', scope: 'Task_1', origin: [ 'Task_1' ], usedBy: [ 'Task_1' ] }
]);
}));


it('should filter read / global', inject(async function(elementRegistry, variableResolver) {

// given
const task = elementRegistry.get('Task_1');

// when
const variables = await variableResolver.getVariablesForElement(task, { read: true, local: false });

// then
expect(variables).to.variableEqual([
{ name: 'subFoo', scope: 'SubProcess_1', origin: [ 'SubProcess_1' ], usedBy: [ 'Task_1' ] }
]);
}));


it('should filter write', inject(async function(elementRegistry, variableResolver) {

// given
const task = elementRegistry.get('Task_1');

// when
const variables = await variableResolver.getVariablesForElement(task, { written: true });

// then
expect(variables).to.variableEqual([
{ name: 'taskFoo', scope: 'Task_1', origin: [ 'Task_1' ], usedBy: [ 'Task_1' ] },
{ name: 'localResult', scope: 'Task_1', origin: [ 'Task_1' ], usedBy: [ 'Task_1' ] },
{ name: 'taskResult', scope: 'Process_1', origin: [ 'Task_1' ] }
]);
}));


it('should filter written / local', inject(async function(elementRegistry, variableResolver) {

// given
const task = elementRegistry.get('Task_1');

// when
const variables = await variableResolver.getVariablesForElement(task, { written: true, local: true });

// then
expect(variables).to.variableEqual([
{ name: 'taskFoo', scope: 'Task_1', origin: [ 'Task_1' ], usedBy: [ 'Task_1' ] },
{ name: 'localResult', scope: 'Task_1', origin: [ 'Task_1' ], usedBy: [ 'Task_1' ] }
]);
}));


it('should filter written / global', inject(async function(elementRegistry, variableResolver) {

// given
const task = elementRegistry.get('Task_1');

// when
const variables = await variableResolver.getVariablesForElement(task, { written: true, local: false });

// then
expect(variables).to.variableEqual([
{ name: 'taskResult', scope: 'Process_1', origin: [ 'Task_1' ] }
]);
}));

});

});

// helpers //////////////////////
Expand Down
Loading