Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TEST] Add visual tests for edges targeting collapsed elements #1867

Merged
merged 3 commits into from
Mar 16, 2022
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
29 changes: 29 additions & 0 deletions dev/ts/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export * from './helper';

let bpmnVisualization: ThemedBpmnVisualization;
let loadOptions: LoadOptions = {};
let bpmnElementIdToCollapse: string;

export function updateLoadOptions(fitOptions: FitOptions): void {
log('Updating load options', fitOptions);
Expand All @@ -45,6 +46,7 @@ function loadBpmn(bpmn: string): void {
try {
bpmnVisualization.load(bpmn, loadOptions);
log('BPMN loaded with configuration', stringify(loadOptions));
collapseBpmnElement(bpmnElementIdToCollapse);
document.dispatchEvent(new CustomEvent('diagramLoaded'));
} catch (e) {
logErrorAndOpenAlert(e, `Cannot load the BPMN diagram: ${e.message}`);
Expand Down Expand Up @@ -81,6 +83,28 @@ export function removeAllOverlays(bpmnElementId: string): void {
return bpmnVisualization.bpmnElementsRegistry.removeAllOverlays(bpmnElementId);
}

// Not natively supported by bpmn-visualization for now but demonstrated in https://cdn.statically.io/gh/process-analytics/bpmn-visualization-examples/v0.22.0/examples/custom-behavior/select-elements-by-bpmn-kind/index.html
// We want to ensure that the edges terminal waypoints are correctly set to the enclosing parent (pool or subprocess), whatever the terminal waypoint computation is.
function collapseBpmnElement(bpmnElementId: string): void {
if (!bpmnElementIdToCollapse) {
return;
}
log('Updating model, bpmnElement to collapse:', bpmnElementId);
const model = bpmnVisualization.graph.getModel();
const cell = model.getCell(bpmnElementId);
if (!cell) {
log('Element not found in the model, do nothing');
} else {
model.beginUpdate();
try {
model.setCollapsed(cell, true);
} finally {
model.endUpdate();
}
log('Model updated');
}
}

// callback function for opening | dropping the file to be loaded
function readAndLoadFile(f: File): void {
const reader = new FileReader();
Expand Down Expand Up @@ -177,6 +201,10 @@ function configureStyleFromParameters(parameters: URLSearchParams): void {
}
}

function configureBpmnElementIdToCollapseFromParameters(parameters: URLSearchParams): void {
bpmnElementIdToCollapse = parameters.get('bpmn.element.id.collapsed');
}

export function startBpmnVisualization(config: BpmnVisualizationDemoConfiguration): void {
const log = logStartup;
const container = config.globalOptions.container;
Expand All @@ -194,6 +222,7 @@ export function startBpmnVisualization(config: BpmnVisualizationDemoConfiguratio
loadOptions.fit = getFitOptionsFromParameters(config, parameters);

configureStyleFromParameters(parameters);
configureBpmnElementIdToCollapseFromParameters(parameters);

log("Checking if an 'url to fetch BPMN content' is provided as query parameter");
const urlParameterValue = parameters.get('url');
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 65 additions & 0 deletions test/e2e/bpmn.elements.collapsed.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* Copyright 2022 Bonitasoft S.A.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import type { MatchImageSnapshotOptions } from 'jest-image-snapshot';
import { ImageSnapshotConfigurator, MultiBrowserImageSnapshotThresholds } from './helpers/visu/image-snapshot-config';
import { PageTester } from './helpers/visu/bpmn-page-utils';
import type { Page } from 'playwright';
import { getBpmnDiagramNames } from './helpers/test-utils';

// key: diagram name
// values: the ids of the elements to collapse. The elements are collapsed one by one, in dedicated tests
const elementsToCollapsePerDiagram = new Map<string, Array<string>>([
['pools', ['Participant_1', 'Participant_2', 'Participant_3', 'Participant_4']],
['subprocess', ['SubProcess_1']],
]);

class CollapsedElementImageSnapshotConfigurator extends ImageSnapshotConfigurator {
override getConfig(param: { fileName: string; collapsedElement: string }): MatchImageSnapshotOptions {
const config = super.getConfig(param);
config.customSnapshotIdentifier = `${param.fileName}-collapse-${param.collapsedElement}`;
return config;
}
}

const getElementsToCollapse = (bpmnDiagramName: string): Array<string> => {
const elementsToCollapse = elementsToCollapsePerDiagram.get(bpmnDiagramName);
// add 'none' to test the diagram rendering without collapsing any element. There is no element in diagrams with the 'none' id (in this case, the value is ignored and there is no collapsing).
return ['none', ...elementsToCollapse];
};

describe('Collapse BPMN elements', () => {
const diagramSubfolder = 'collapse-expand';
const imageSnapshotConfigurator = new CollapsedElementImageSnapshotConfigurator(
// firefox: max 0.2640822887892802%
// webkit: max 0.29993542878872237%
new MultiBrowserImageSnapshotThresholds({ chromium: 0, firefox: 0.27 / 100, webkit: 0.3 / 100 }),
diagramSubfolder,
);
const pageTester = new PageTester({ pageFileName: 'non-regression', expectedPageTitle: 'BPMN Visualization Non Regression', diagramSubfolder }, <Page>page);
const bpmnDiagramNames = getBpmnDiagramNames(diagramSubfolder);

describe.each(bpmnDiagramNames)(`%s`, (bpmnDiagramName: string) => {
it.each(getElementsToCollapse(bpmnDiagramName))(`collapse %s`, async (bpmnElementIdToCollapse: string) => {
await pageTester.gotoPageAndLoadBpmnDiagram(bpmnDiagramName, {
bpmnElementIdToCollapse: bpmnElementIdToCollapse,
});
const image = await page.screenshot({ fullPage: true });
const config = imageSnapshotConfigurator.getConfig({ fileName: bpmnDiagramName, collapsedElement: bpmnElementIdToCollapse });
expect(image).toMatchImageSnapshot(config);
});
});
});
15 changes: 12 additions & 3 deletions test/e2e/helpers/visu/bpmn-page-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export interface StyleOptions {
export interface PageOptions {
loadOptions?: LoadOptions;
styleOptions?: StyleOptions;
bpmnElementIdToCollapse?: string;
}

export interface Point {
Expand Down Expand Up @@ -111,7 +112,12 @@ export class PageTester {
}

async gotoPageAndLoadBpmnDiagram(bpmnDiagramName: string, pageOptions?: PageOptions): Promise<void> {
const url = this.computePageUrl(bpmnDiagramName, pageOptions?.loadOptions ?? { fit: { type: FitType.HorizontalVertical } }, pageOptions?.styleOptions);
const url = this.computePageUrl(
bpmnDiagramName,
pageOptions?.loadOptions ?? { fit: { type: FitType.HorizontalVertical } },
pageOptions?.styleOptions,
pageOptions?.bpmnElementIdToCollapse,
);
await this.doGotoPageAndLoadBpmnDiagram(url);
}

Expand All @@ -131,9 +137,9 @@ export class PageTester {
/**
* @param bpmnDiagramName the name of the BPMN file without extension
* @param loadOptions optional fit options
* @param styleOptions optional style options
* @param styleOptions? optional style options
*/
private computePageUrl(bpmnDiagramName: string, loadOptions: LoadOptions, styleOptions?: StyleOptions): string {
private computePageUrl(bpmnDiagramName: string, loadOptions: LoadOptions, styleOptions?: StyleOptions, bpmndElementIdToCollapse?: string | undefined): string {
let url = this.baseUrl;
url += `&url=./static/bpmn/${this.diagramSubfolder}/${bpmnDiagramName}.bpmn`;

Expand All @@ -147,6 +153,9 @@ export class PageTester {
(url += `&style.container.alternative.background.color=${styleOptions.bpmnContainer.useAlternativeBackgroundColor}`);
styleOptions?.theme && (url += `&style.theme=${styleOptions.theme}`);

// elements to collapse
bpmndElementIdToCollapse && (url += `&bpmn.element.id.collapsed=${bpmndElementIdToCollapse}`);

return url;
}

Expand Down
199 changes: 199 additions & 0 deletions test/fixtures/bpmn/collapse-expand/pools.bpmn
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1" targetNamespace="http://example.com/schema/bpmn">
<bpmn:collaboration id="Collaboration_16qn7f7">
<bpmn:participant id="Participant_1" processRef="Process_1" />
<bpmn:participant id="Participant_2" processRef="Process_2" />
<bpmn:participant id="Participant_3" processRef="Process_3" />
<bpmn:participant id="Participant_4" processRef="Process_4" />
<bpmn:messageFlow id="Flow_1oodl1k" sourceRef="Activity_14jx6w8" targetRef="StartEvent_17g4nu8" />
<bpmn:messageFlow id="Flow_1xspsn1" sourceRef="Event_0r61dg1" targetRef="Activity_14jx6w8" />
<bpmn:messageFlow id="Flow_09jmgm4" sourceRef="Event_0z01vb5" targetRef="Event_0f92tj3" />
<bpmn:messageFlow id="Flow_10w9tdb" sourceRef="Activity_1ka7pcl" targetRef="Activity_0ltcxpv" />
</bpmn:collaboration>
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:sequenceFlow id="Flow_0jsdvpk" sourceRef="StartEvent_17g4nu8" targetRef="Activity_0puqzjv" />
<bpmn:sequenceFlow id="Flow_17ljr6c" sourceRef="Activity_0puqzjv" targetRef="Event_0r61dg1" />
<bpmn:startEvent id="StartEvent_17g4nu8">
<bpmn:outgoing>Flow_0jsdvpk</bpmn:outgoing>
<bpmn:messageEventDefinition id="MessageEventDefinition_0jn3ex4" />
</bpmn:startEvent>
<bpmn:task id="Activity_0puqzjv">
<bpmn:incoming>Flow_0jsdvpk</bpmn:incoming>
<bpmn:outgoing>Flow_17ljr6c</bpmn:outgoing>
</bpmn:task>
<bpmn:endEvent id="Event_0r61dg1">
<bpmn:incoming>Flow_17ljr6c</bpmn:incoming>
<bpmn:messageEventDefinition id="MessageEventDefinition_0exqd0a" />
</bpmn:endEvent>
</bpmn:process>
<bpmn:process id="Process_2">
<bpmn:startEvent id="Event_0aa0ktp">
<bpmn:outgoing>Flow_1vroj9a</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="Activity_14jx6w8">
<bpmn:incoming>Flow_1vroj9a</bpmn:incoming>
<bpmn:outgoing>Flow_0cx4m6y</bpmn:outgoing>
</bpmn:task>
<bpmn:intermediateThrowEvent id="Event_0z01vb5">
<bpmn:incoming>Flow_0cx4m6y</bpmn:incoming>
<bpmn:outgoing>Flow_1qzs7cq</bpmn:outgoing>
<bpmn:messageEventDefinition id="MessageEventDefinition_1ofhuys" />
</bpmn:intermediateThrowEvent>
<bpmn:endEvent id="Event_1d8mi1m">
<bpmn:incoming>Flow_1qzs7cq</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1vroj9a" sourceRef="Event_0aa0ktp" targetRef="Activity_14jx6w8" />
<bpmn:sequenceFlow id="Flow_0cx4m6y" sourceRef="Activity_14jx6w8" targetRef="Event_0z01vb5" />
<bpmn:sequenceFlow id="Flow_1qzs7cq" sourceRef="Event_0z01vb5" targetRef="Event_1d8mi1m" />
</bpmn:process>
<bpmn:process id="Process_3">
<bpmn:startEvent id="Event_0f92tj3">
<bpmn:outgoing>Flow_0ipugn9</bpmn:outgoing>
<bpmn:messageEventDefinition id="MessageEventDefinition_18c8g9f" />
</bpmn:startEvent>
<bpmn:task id="Activity_1ka7pcl">
<bpmn:incoming>Flow_0ipugn9</bpmn:incoming>
<bpmn:outgoing>Flow_1bw85cc</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_0ipugn9" sourceRef="Event_0f92tj3" targetRef="Activity_1ka7pcl" />
<bpmn:endEvent id="Event_09s4aci">
<bpmn:incoming>Flow_1bw85cc</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1bw85cc" sourceRef="Activity_1ka7pcl" targetRef="Event_09s4aci" />
</bpmn:process>
<bpmn:process id="Process_4">
<bpmn:startEvent id="Event_0v4aheg">
<bpmn:outgoing>Flow_0txp0nu</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="Activity_0ltcxpv">
<bpmn:incoming>Flow_0txp0nu</bpmn:incoming>
<bpmn:outgoing>Flow_16r4h6t</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_0txp0nu" sourceRef="Event_0v4aheg" targetRef="Activity_0ltcxpv" />
<bpmn:endEvent id="Event_0expexd">
<bpmn:incoming>Flow_16r4h6t</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_16r4h6t" sourceRef="Activity_0ltcxpv" targetRef="Event_0expexd" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_16qn7f7">
<bpmndi:BPMNShape id="Participant_1_di" bpmnElement="Participant_1" isHorizontal="true">
<dc:Bounds x="-30" y="-250" width="500" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_17ljr6c_di" bpmnElement="Flow_17ljr6c">
<di:waypoint x="260" y="-140" />
<di:waypoint x="322" y="-140" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0jsdvpk_di" bpmnElement="Flow_0jsdvpk">
<di:waypoint x="68" y="-140" />
<di:waypoint x="160" y="-140" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Event_0dr110a_di" bpmnElement="StartEvent_17g4nu8">
<dc:Bounds x="32" y="-158" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0puqzjv_di" bpmnElement="Activity_0puqzjv">
<dc:Bounds x="160" y="-180" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0ewtrd7_di" bpmnElement="Event_0r61dg1">
<dc:Bounds x="322" y="-158" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_2_di" bpmnElement="Participant_2" isHorizontal="true">
<dc:Bounds x="-30" y="100" width="500" height="220" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1qzs7cq_di" bpmnElement="Flow_1qzs7cq">
<di:waypoint x="344" y="210" />
<di:waypoint x="398" y="210" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0cx4m6y_di" bpmnElement="Flow_0cx4m6y">
<di:waypoint x="256" y="210" />
<di:waypoint x="308" y="210" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1vroj9a_di" bpmnElement="Flow_1vroj9a">
<di:waypoint x="58" y="210" />
<di:waypoint x="156" y="210" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Event_0aa0ktp_di" bpmnElement="Event_0aa0ktp">
<dc:Bounds x="22" y="192" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_14jx6w8_di" bpmnElement="Activity_14jx6w8">
<dc:Bounds x="156" y="170" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1osag5t_di" bpmnElement="Event_0z01vb5">
<dc:Bounds x="308" y="192" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1d8mi1m_di" bpmnElement="Event_1d8mi1m">
<dc:Bounds x="398" y="192" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_3_di" bpmnElement="Participant_3" isHorizontal="true">
<dc:Bounds x="530" y="100" width="410" height="220" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0ipugn9_di" bpmnElement="Flow_0ipugn9">
<di:waypoint x="638" y="210" />
<di:waypoint x="690" y="210" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1bw85cc_di" bpmnElement="Flow_1bw85cc">
<di:waypoint x="790" y="210" />
<di:waypoint x="842" y="210" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Event_04xwdv4_di" bpmnElement="Event_0f92tj3">
<dc:Bounds x="602" y="192" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1ka7pcl_di" bpmnElement="Activity_1ka7pcl">
<dc:Bounds x="690" y="170" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_09s4aci_di" bpmnElement="Event_09s4aci">
<dc:Bounds x="842" y="192" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_4_di" bpmnElement="Participant_4" isHorizontal="true">
<dc:Bounds x="530" y="-250" width="410" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0txp0nu_di" bpmnElement="Flow_0txp0nu">
<di:waypoint x="638" y="-140" />
<di:waypoint x="690" y="-140" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_16r4h6t_di" bpmnElement="Flow_16r4h6t">
<di:waypoint x="790" y="-140" />
<di:waypoint x="842" y="-140" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Event_0v4aheg_di" bpmnElement="Event_0v4aheg">
<dc:Bounds x="602" y="-158" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0ltcxpv_di" bpmnElement="Activity_0ltcxpv">
<dc:Bounds x="690" y="-180" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0expexd_di" bpmnElement="Event_0expexd">
<dc:Bounds x="842" y="-158" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1oodl1k_di" bpmnElement="Flow_1oodl1k">
<di:waypoint x="180" y="170" />
<di:waypoint x="180" y="140" />
<di:waypoint x="130" y="140" />
<di:waypoint x="130" y="-50" />
<di:waypoint x="160" y="-50" />
<di:waypoint x="160" y="-90" />
<di:waypoint x="50" y="-90" />
<di:waypoint x="50" y="-122" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1xspsn1_di" bpmnElement="Flow_1xspsn1">
<di:waypoint x="340" y="-122" />
<di:waypoint x="340" y="-60" />
<di:waypoint x="250" y="-60" />
<di:waypoint x="250" y="-30" />
<di:waypoint x="310" y="-30" />
<di:waypoint x="310" y="49" />
<di:waypoint x="230" y="49" />
<di:waypoint x="230" y="170" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_09jmgm4_di" bpmnElement="Flow_09jmgm4">
<di:waypoint x="326" y="228" />
<di:waypoint x="326" y="280" />
<di:waypoint x="620" y="280" />
<di:waypoint x="620" y="228" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_10w9tdb_di" bpmnElement="Flow_10w9tdb">
<di:waypoint x="740" y="170" />
<di:waypoint x="740" y="-100" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Loading