diff --git a/package-lock.json b/package-lock.json index bf9d0aa5b0..58d8379806 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1514,6 +1514,12 @@ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, + "@types/debug": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", + "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", + "dev": true + }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", diff --git a/package.json b/package.json index 24517e9993..a93dba76df 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "devDependencies": { "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^8.4.0", + "@types/debug": "^4.1.5", "@types/jest": "^26.0.9", "@types/jest-environment-puppeteer": "^4.3.2", "@types/puppeteer": "^3.0.1", diff --git a/src/demo/index.ts b/src/demo/index.ts index be0a828f71..f0647860a0 100644 --- a/src/demo/index.ts +++ b/src/demo/index.ts @@ -50,8 +50,45 @@ export function handleFileSelect(evt: any): void { readAndLoadFile(f); } -export function startBpmnVisualization(container: string): void { +function fetchBpmnContent(url: string): Promise { + log(`Fetching BPMN content from url ${url}`); + return fetch(url).then(response => { + if (!response.ok) { + throw Error(String(response.status)); + } + return response.text(); + }); +} + +function loadBpmnFromUrl(url: string, statusFetchKoNotifier: (errorMsg: string) => void): void { + fetchBpmnContent(url) + .catch(error => { + const errorMessage = `Unable to fetch ${url}. ${error}`; + statusFetchKoNotifier(errorMessage); + throw new Error(errorMessage); + }) + .then(responseBody => { + log('BPMN content fetched'); + return responseBody; + }) + .then(bpmn => { + loadBpmn(bpmn); + log(`Bpmn loaded from url ${url}`); + }); +} + +export interface BpmnVisualizationDemoConfiguration { + container: string; + statusFetchKoNotifier?: (errorMsg: string) => void; +} + +function defaultStatusFetchKoNotifier(errorMsg: string): void { + console.error(errorMsg); +} + +export function startBpmnVisualization(config: BpmnVisualizationDemoConfiguration): void { const log = logStartup; + const container = config.container; log(`Initializing BpmnVisualization with container '${container}'...`); bpmnVisualization = new BpmnVisualization(window.document.getElementById(container)); @@ -62,7 +99,7 @@ export function startBpmnVisualization(container: string): void { fitOnLoad = parameters.get('fitOnLoad') == 'true'; log(`Configure 'fit on load' to ${fitOnLoad}`); - log("Checking if 'BPMN auto loading from url parameter' is requested"); + log("Checking if 'BPMN content' is provided as query parameter"); const bpmnParameterValue = parameters.get('bpmn'); if (bpmnParameterValue) { const bpmn = decodeURIComponent(bpmnParameterValue); @@ -70,8 +107,18 @@ export function startBpmnVisualization(container: string): void { log(`Received bpmn content: ${bpmn}`); log('BPMN auto loading'); loadBpmn(bpmn); - log('BPMN auto loading completed'); - } else { - log('No BPMN auto loading'); + log('BPMN content loading completed'); + return; + } + log("No 'BPMN content' provided"); + + log("Checking if an 'url to fetch BPMN content' is provided as query parameter"); + const urlParameterValue = parameters.get('url'); + if (urlParameterValue) { + const url = decodeURIComponent(urlParameterValue); + const statusFetchKoNotifier = config.statusFetchKoNotifier || defaultStatusFetchKoNotifier; + loadBpmnFromUrl(url, statusFetchKoNotifier); + return; } + log("No 'url to fetch BPMN content' provided"); } diff --git a/src/index-non-regression.html b/src/index-non-regression.html index 4474b2f8e7..b54272a786 100644 --- a/src/index-non-regression.html +++ b/src/index-non-regression.html @@ -13,9 +13,14 @@ position: absolute; overflow: hidden; } + .status-ko { + color: red; + font-weight: bold; + } +
diff --git a/src/static/js/demo.js b/src/static/js/demo.js index dae259ba9f..dcf7cd2d5b 100644 --- a/src/static/js/demo.js +++ b/src/static/js/demo.js @@ -22,4 +22,4 @@ new DropFileUserInterface(window, 'drop-container', visualizationContainer, read document.getElementById('bpmn-file').addEventListener('change', handleFileSelect, false); document.getElementById('file-selector').classList.remove('hidden'); -documentReady(startBpmnVisualization(visualizationContainer)); +documentReady(startBpmnVisualization({ container: visualizationContainer })); diff --git a/src/static/js/non-regression.js b/src/static/js/non-regression.js index 412d4382fd..55afc3b861 100644 --- a/src/static/js/non-regression.js +++ b/src/static/js/non-regression.js @@ -19,4 +19,11 @@ const visualizationContainer = 'viewport'; // TODO: move to UI initializer new DropFileUserInterface(window, 'drop-container', visualizationContainer, readAndLoadFile); -documentReady(startBpmnVisualization(visualizationContainer)); +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +function statusFetchKO(errorMsg) { + const statusElt = document.getElementById('fetch-status'); + statusElt.innerText = errorMsg; + statusElt.className = 'status-ko'; +} + +documentReady(startBpmnVisualization({ container: visualizationContainer, statusFetchKoNotifier: statusFetchKO })); diff --git a/test/e2e/__image_snapshots__/bpmn-rendering-test-ts-no-visual-regression-events-1-snap.png b/test/e2e/__image_snapshots__/bpmn-rendering-test-ts-no-visual-regression-events-1-snap.png index 719381e256..e6e78ab030 100644 Binary files a/test/e2e/__image_snapshots__/bpmn-rendering-test-ts-no-visual-regression-events-1-snap.png and b/test/e2e/__image_snapshots__/bpmn-rendering-test-ts-no-visual-regression-events-1-snap.png differ diff --git a/test/e2e/bpmn-rendering.test.ts b/test/e2e/bpmn-rendering.test.ts index 1336fd070a..5406feaaa6 100644 --- a/test/e2e/bpmn-rendering.test.ts +++ b/test/e2e/bpmn-rendering.test.ts @@ -30,11 +30,10 @@ declare global { } } -import { encodeUriXml, findFiles, linearizeXml, readFileSync } from '../helpers/file-helper'; -// import debug from 'debug'; -// eslint-disable-next-line @typescript-eslint/no-var-requires -const debug = require('debug')('test'); +import { copyFileSync, findFiles, loadBpmnContentForUrlQueryParam } from '../helpers/file-helper'; +import debugLogger from 'debug'; +const log = debugLogger('test'); const graphContainerId = 'viewport'; describe('no visual regression', () => { @@ -46,13 +45,9 @@ describe('no visual regression', () => { comparisonMethod: 'ssim', }; - function log(msg: string): void { - debug(msg); - } - function getSimplePlatformName(): string { const platform = process.platform; - debug(`This platform is ${platform}`); + log(`This platform is ${platform}`); if (platform.startsWith('win')) { return 'windows'; @@ -139,17 +134,43 @@ describe('no visual regression', () => { return defaultImageSnapshotConfig; } - function bpmnContentForTestPage(fileName: string): string { - log(`Preparing bpmn content for test '${fileName}'`); - let rawBpmn = readFileSync(`../fixtures/bpmn/non-regression/${fileName}.bpmn`); - log(`Original bpmn length: ${rawBpmn.length}`); + enum BpmnLoadMethod { + QueryParam = 'query param', + Url = 'url', + } - rawBpmn = linearizeXml(rawBpmn); - log(`bpmn length after linearize: ${rawBpmn.length}`); + /** + * Configure how the BPMN file is loaded by the test page. + * + * When introducing a new test, there is generally no need to add configuration here as the default is OK. You only need configuration when the file content becomes larger (in + * that case, the test server returns an HTTP 400 error). + * + * Prior adding a config here, review your file to check if it is not too large because it contains too much elements, in particular, some elements not related to what you want to + * test. + */ + const bpmnLoadMethodConfig = new Map([['events', BpmnLoadMethod.Url]]); - const uriEncodedBpmn = encodeUriXml(rawBpmn); - log(`bpmn length in URI encoded form: ${uriEncodedBpmn.length}`); - return uriEncodedBpmn; + function getBpmnLoadMethod(fileName: string): BpmnLoadMethod { + return bpmnLoadMethodConfig.get(fileName) || BpmnLoadMethod.QueryParam; + } + + function prepareTestResourcesAndGetPageUrl(fileName: string): string { + let url = 'http://localhost:10001/index-non-regression.html?fitOnLoad=true'; + + const bpmnLoadMethod = getBpmnLoadMethod(fileName); + log(`Use '${bpmnLoadMethod}' as BPMN Load Method for '${fileName}'`); + const relPathToBpmnFile = `../fixtures/bpmn/non-regression/${fileName}.bpmn`; + switch (bpmnLoadMethod) { + case BpmnLoadMethod.QueryParam: + const bpmnContent = loadBpmnContentForUrlQueryParam(relPathToBpmnFile); + url += `&bpmn=${bpmnContent}`; + break; + case BpmnLoadMethod.Url: + copyFileSync(relPathToBpmnFile, `../../dist/static/diagrams/`, `${fileName}.bpmn`); + url += `&url=./static/diagrams/${fileName}.bpmn`; + break; + } + return url; } const bpmnFiles = findFiles('../fixtures/bpmn/non-regression/'); @@ -166,9 +187,10 @@ describe('no visual regression', () => { return filename.split('.').slice(0, -1).join('.'); }); it.each(bpmnFileNames)(`%s`, async (fileName: string) => { - const url = `http://localhost:10001/index-non-regression.html?fitOnLoad=true&bpmn=${bpmnContentForTestPage(fileName)}`; + const url = prepareTestResourcesAndGetPageUrl(fileName); + const response = await page.goto(url); - // Uncomment the following in case of http error 400 + // Uncomment the following in case of http error 400 (probably because of a too large bpmn file) // eslint-disable-next-line no-console // await page.evaluate(() => console.log(`url is ${location.href}`)); expect(response.status()).toBe(200); diff --git a/test/e2e/mxGraph.view.test.ts b/test/e2e/mxGraph.view.test.ts index 4b69bf42d4..0e484fa1d7 100644 --- a/test/e2e/mxGraph.view.test.ts +++ b/test/e2e/mxGraph.view.test.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { readFileSync } from '../helpers/file-helper'; +import { loadBpmnContentForUrlQueryParam } from '../helpers/file-helper'; let graphContainerId = 'graph'; @@ -59,7 +59,7 @@ describe('BpmnVisu view - index page', () => { }); it('should display graph in page', async () => { - await page.goto(`http://localhost:10001?bpmn=${readFileSync('../fixtures/bpmn/simple-start-task-end.bpmn')}`); + await page.goto(`http://localhost:10001?bpmn=${loadBpmnContentForUrlQueryParam('../fixtures/bpmn/simple-start-task-end.bpmn')}`); await expectEvent('StartEvent_1', 'Start Event 1'); await expectSequenceFlow('Flow_1', 'Sequence Flow 1'); @@ -72,7 +72,7 @@ describe('BpmnVisu view - index page', () => { describe('BpmnVisu view - lib-integration page', () => { it('should display graph in page', async () => { graphContainerId = 'bpmn-visualization-viewport'; - await page.goto(`http://localhost:10001/lib-integration.html?bpmn=${readFileSync('../fixtures/bpmn/simple-start-only.bpmn')}`); + await page.goto(`http://localhost:10001/lib-integration.html?bpmn=${loadBpmnContentForUrlQueryParam('../fixtures/bpmn/simple-start-only.bpmn')}`); await expect(page.title()).resolves.toMatch('BPMN Visualization Lib Integration'); await page.waitForSelector(`#${graphContainerId}`); diff --git a/test/fixtures/bpmn/non-regression/events.bpmn b/test/fixtures/bpmn/non-regression/events.bpmn index 7517a842d8..128d1f3f00 100644 --- a/test/fixtures/bpmn/non-regression/events.bpmn +++ b/test/fixtures/bpmn/non-regression/events.bpmn @@ -1,38 +1,580 @@ - - - - - + + + + + - - + + - - + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + - - + + + + + - - + + + + + - - + + + + + diff --git a/test/helpers/file-helper.ts b/test/helpers/file-helper.ts index 2aed1ae99c..3bb55d5dc8 100644 --- a/test/helpers/file-helper.ts +++ b/test/helpers/file-helper.ts @@ -15,11 +15,21 @@ */ import * as fs from 'fs'; import * as path from 'path'; +import debugLogger from 'debug'; + +const debug = debugLogger('test'); export function readFileSync(relPathToSourceFile: string, encoding = 'utf8'): string { return fs.readFileSync(path.join(__dirname, relPathToSourceFile), encoding); } +export function copyFileSync(relPathToSourceFile: string, relPathToDestinationDirectory: string, destinationFileName: string): void { + const directoryPath = path.join(__dirname, relPathToDestinationDirectory); + + fs.mkdirSync(directoryPath, { recursive: true }); + fs.copyFileSync(path.join(__dirname, relPathToSourceFile), path.join(directoryPath, destinationFileName)); +} + /** Returns the files in the given directory. The function doesn't do any recursion in sub directories. */ export function findFiles(relPathToSourceDirectory: string): string[] { return fs.readdirSync(path.join(__dirname, relPathToSourceDirectory)); @@ -50,3 +60,16 @@ export function linearizeXml(xml: string): string { export function encodeUriXml(xml: string): string { return encodeURIComponent(xml); } + +export function loadBpmnContentForUrlQueryParam(relPathToSourceFile: string): string { + debug(`Preparing bpmn content for url query param, source: '${relPathToSourceFile}'`); + let rawBpmn = readFileSync(relPathToSourceFile); + debug(`Original bpmn length: ${rawBpmn.length}`); + + rawBpmn = linearizeXml(rawBpmn); + debug(`Bpmn length after linearize: ${rawBpmn.length}`); + + const uriEncodedBpmn = encodeUriXml(rawBpmn); + debug(`Bpmn length in URI encoded form: ${uriEncodedBpmn.length}`); + return uriEncodedBpmn; +}