bpmn-js/test/spec/features/auto-place/AutoPlaceSpec.js

395 lines
9.3 KiB
JavaScript

/* global sinon */
import {
bootstrapModeler,
inject
} from 'test/TestHelper';
import autoPlaceModule from 'lib/features/auto-place';
import coreModule from 'lib/core';
import labelEditingModule from 'lib/features/label-editing';
import modelingModule from 'lib/features/modeling';
import selectionModule from 'diagram-js/lib/features/selection';
import { getBusinessObject } from '../../../../lib/util/ModelUtil';
import { getMid } from 'diagram-js/lib/layout/LayoutUtil';
describe('features/auto-place', function() {
describe('element placement', function() {
var diagramXML = require('./AutoPlace.bpmn');
before(bootstrapModeler(diagramXML, {
modules: [
coreModule,
modelingModule,
autoPlaceModule,
selectionModule
]
}));
describe('should place bpmn:FlowNode', function() {
it('at default distance after START_EVENT_1', autoPlace({
element: 'bpmn:Task',
behind: 'START_EVENT_1',
expectedBounds: { x: 1052, y: 224, width: 100, height: 80 }
}));
it('at incoming distance after TASK_0', autoPlace({
element: 'bpmn:Task',
behind: 'TASK_0',
expectedBounds: { x: 262, y: 54, width: 100, height: 80 }
}));
it('at incoming distance / quorum after TASK_5', autoPlace({
element: 'bpmn:Task',
behind: 'TASK_5',
expectedBounds: { x: 296, y: 390, width: 100, height: 80 }
}));
it('at existing outgoing / below TASK_2', autoPlace({
element: 'bpmn:Task',
behind: 'TASK_1',
expectedBounds: { x: 279, y: 293, width: 100, height: 80 }
}));
it('ignoring existing, far away outgoing of TASK_3', autoPlace({
element: 'bpmn:Task',
behind: 'TASK_3',
expectedBounds: { x: 746, y: 127, width: 100, height: 80 }
}));
it('behind bpmn:SubProcess', autoPlace({
element: 'bpmn:Task',
behind: 'SUBPROCESS_1',
expectedBounds: { x: 925, y: 368, width: 100, height: 80 }
}));
});
describe('should place bpmn:DataStoreReference', function() {
it('bottom right of source', autoPlace({
element: 'bpmn:DataStoreReference',
behind: 'TASK_2',
expectedBounds: { x: 369, y: 303, width: 50, height: 50 }
}));
it('next to existing', autoPlace({
element: 'bpmn:DataStoreReference',
behind: 'TASK_3',
expectedBounds: { x: 769, y: 247, width: 50, height: 50 }
}));
});
describe('should place bpmn:TextAnnotation', function() {
it('top right of source', autoPlace({
element: 'bpmn:TextAnnotation',
behind: 'TASK_2',
expectedBounds: { x: 379, y: 103, width: 100, height: 30 }
}));
it('above existing', autoPlace({
element: 'bpmn:TextAnnotation',
behind: 'TASK_3',
expectedBounds: { x: 696, y: -4, width: 100, height: 30 }
}));
});
});
describe('integration', function() {
var diagramXML = require('./AutoPlace.bpmn');
before(bootstrapModeler(diagramXML, {
modules: [
autoPlaceModule,
coreModule,
labelEditingModule,
modelingModule,
selectionModule
]
}));
it('should complete direct edit on autoPlace', inject(
function(autoPlace, directEditing, elementFactory, elementRegistry) {
// given
var element = elementFactory.createShape({ type: 'bpmn:Task' });
var source = elementRegistry.get('TASK_2');
directEditing.activate(source);
directEditing._textbox.content.textContent = 'foo';
// when
autoPlace.append(source, element);
// then
expect(getBusinessObject(source).name).to.equal('foo');
}
));
it('should select + direct edit on autoPlace', inject(
function(autoPlace, elementRegistry, elementFactory, selection, directEditing) {
// given
var element = elementFactory.createShape({ type: 'bpmn:Task' });
var source = elementRegistry.get('TASK_2');
// when
var newShape = autoPlace.append(source, element);
// then
expect(selection.get()).to.eql([ newShape ]);
expect(directEditing.isActive()).to.be.true;
expect(directEditing._active.element).to.equal(newShape);
}
));
});
describe('multi connection handling', function() {
var diagramXML = require('./AutoPlace.multi-connection.bpmn');
before(bootstrapModeler(diagramXML, {
modules: [
coreModule,
modelingModule,
autoPlaceModule,
selectionModule,
labelEditingModule
]
}));
it('should ignore multiple source -> target connections', inject(
function(autoPlace, elementRegistry, elementFactory, selection, directEditing) {
// given
var element = elementFactory.createShape({ type: 'bpmn:Task' });
var source = elementRegistry.get('TASK_1');
var alignedElement = elementRegistry.get('TASK_3');
// when
var newShape = autoPlace.append(source, element);
// then
expect(newShape.x).to.eql(alignedElement.x);
}
));
});
describe('boundary event connection handling', function() {
var diagramXML = require('./AutoPlace.boundary-events.bpmn');
before(bootstrapModeler(diagramXML, {
modules: [
coreModule,
modelingModule,
autoPlaceModule,
selectionModule
]
}));
it('should place bottom right of BOUNDARY_BOTTOM', autoPlace({
element: 'bpmn:Task',
behind: 'BOUNDARY_BOTTOM',
expectedBounds: { x: 241, y: 213, width: 100, height: 80 }
}));
it('should place bottom right of BOUNDARY_SUBPROCESS_BOTTOM', autoPlace({
element: 'bpmn:Task',
behind: 'BOUNDARY_SUBPROCESS_BOTTOM',
expectedBounds: { x: 278, y: 495, width: 100, height: 80 }
}));
it('should place top right of BOUNDARY_TOP', autoPlace({
element: 'bpmn:Task',
behind: 'BOUNDARY_TOP',
expectedBounds: { x: 242, y: -27, width: 100, height: 80 }
}));
it('should place top right of BOUNDARY_TOP_RIGHT without infinite loop', autoPlace({
element: 'bpmn:Task',
behind: 'BOUNDARY_TOP_RIGHT',
expectedBounds: { x: 473, y: -27, width: 100, height: 80 }
}));
it('should place top right of BOUNDARY_SUBPROCESS_TOP', autoPlace({
element: 'bpmn:Task',
behind: 'BOUNDARY_SUBPROCESS_TOP',
expectedBounds: { x: 275, y: 194, width: 100, height: 80 }
}));
});
describe('eventbus integration', function() {
var diagramXML = require('./AutoPlace.bpmn');
beforeEach(bootstrapModeler(diagramXML, {
modules: [
autoPlaceModule,
coreModule,
labelEditingModule,
modelingModule,
selectionModule
]
}));
it('<autoPlace.start>', inject(
function(autoPlace, elementFactory, elementRegistry, eventBus) {
// given
var element = elementFactory.createShape({ type: 'bpmn:Task' });
var source = elementRegistry.get('TASK_2');
var listener = sinon.spy(function(event) {
// then
expect(event.shape).to.equal(element);
expect(event.source).to.equal(source);
});
eventBus.on('autoPlace.start', listener);
// when
autoPlace.append(source, element);
expect(listener).to.have.been.called;
}
));
it('<autoPlace>', inject(
function(autoPlace, elementFactory, elementRegistry, eventBus) {
// given
var element = elementFactory.createShape({ type: 'bpmn:Task' });
var source = elementRegistry.get('TASK_2');
var listener = sinon.spy(function(event) {
// then
expect(event.shape).to.equal(element);
expect(event.source).to.equal(source);
return {
x: 0,
y: 0
};
});
eventBus.on('autoPlace', listener);
// when
autoPlace.append(source, element);
expect(listener).to.have.been.called;
expect(getMid(element)).to.eql({
x: 0,
y: 0
});
}
));
it('<autoPlace.end>', inject(
function(autoPlace, elementFactory, elementRegistry, eventBus) {
// given
var element = elementFactory.createShape({ type: 'bpmn:Task' });
var source = elementRegistry.get('TASK_2');
var listener = sinon.spy(function(event) {
// then
expect(event.shape).to.equal(element);
expect(event.source).to.equal(source);
});
eventBus.on('autoPlace.end', listener);
// when
autoPlace.append(source, element);
expect(listener).to.have.been.called;
}
));
});
});
// helpers //////////////////////
function autoPlace(cfg) {
var element = cfg.element,
behind = cfg.behind,
expectedBounds = cfg.expectedBounds;
return inject(function(autoPlace, elementRegistry, elementFactory) {
var sourceEl = elementRegistry.get(behind);
// assume
expect(sourceEl).to.exist;
if (typeof element === 'string') {
element = { type: element };
}
var shape = elementFactory.createShape(element);
// when
var placedShape = autoPlace.append(sourceEl, shape);
// then
expect(placedShape).to.have.bounds(expectedBounds);
});
}