index.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /**
  2. * A helper file that may be used in test cases for bpmn-js and extensions.
  3. *
  4. * Provides the globals
  5. *
  6. * * bootstrapModeler(): bootstrap a modeler instance
  7. * * bootstrapViewer(): bootstrap a viewer instance
  8. * * inject(function(a, b) {}): inject the bpmn-js services in the given function
  9. *
  10. *
  11. * In addition it provides the utilities
  12. *
  13. * * insertCSS(name, css): add a CSS file to be used in test cases
  14. *
  15. *
  16. * It is recommended to expose the helper through a per-project utility and
  17. * and perform custom bootstrapping (CSS, ...) in that utility.
  18. *
  19. * ```
  20. * export * from 'bpmn-js/test/helper';
  21. *
  22. * import {
  23. * insertCSS
  24. * } from 'bpmn-js/test/helper';
  25. *
  26. * // insert diagram.css
  27. * insertCSS('diagram.css', require('./some-css.css'));
  28. * ```
  29. */
  30. import {
  31. isFunction,
  32. forEach,
  33. merge
  34. } from 'min-dash';
  35. import TestContainer from 'mocha-test-container-support';
  36. import Modeler from '../../lib/Modeler';
  37. import NavigatedViewer from '../../lib/NavigatedViewer';
  38. import Viewer from '../../lib/Viewer';
  39. var OPTIONS, BPMN_JS;
  40. import translationModule from './TranslationCollector';
  41. export var collectTranslations = window.__env__ && window.__env__.COLLECT_TRANSLATIONS;
  42. // inject logging translation module into default modules
  43. if (collectTranslations) {
  44. [ Modeler, Viewer, NavigatedViewer ].forEach(function(constructor) {
  45. constructor.prototype._modules.push(translationModule);
  46. });
  47. }
  48. export function bootstrapBpmnJS(BpmnJS, diagram, options, locals) {
  49. return function() {
  50. var testContainer;
  51. // Make sure the test container is an optional dependency and we fall back
  52. // to an empty <div> if it does not exist.
  53. //
  54. // This is needed if other libraries rely on this helper for testing
  55. // while not adding the mocha-test-container-support as a dependency.
  56. try {
  57. // 'this' is the current test context
  58. testContainer = TestContainer.get(this);
  59. } catch (e) {
  60. testContainer = document.createElement('div');
  61. testContainer.classList.add('test-content-container');
  62. document.body.appendChild(testContainer);
  63. }
  64. var _options = options,
  65. _locals = locals;
  66. if (_locals === undefined && isFunction(_options)) {
  67. _locals = _options;
  68. _options = null;
  69. }
  70. if (isFunction(_options)) {
  71. _options = _options();
  72. }
  73. if (isFunction(_locals)) {
  74. _locals = _locals();
  75. }
  76. _options = merge({
  77. container: testContainer,
  78. canvas: {
  79. deferUpdate: false
  80. }
  81. }, OPTIONS, _options);
  82. if (_locals) {
  83. var mockModule = {};
  84. forEach(_locals, function(v, k) {
  85. mockModule[k] = [ 'value', v ];
  86. });
  87. _options.modules = [].concat(_options.modules || [], [ mockModule ]);
  88. }
  89. if (_options.modules && !_options.modules.length) {
  90. _options.modules = undefined;
  91. }
  92. // used to extract translations used during tests
  93. if (collectTranslations) {
  94. _options.additionalModules = [].concat(
  95. _options.additionalModules || [],
  96. [ translationModule ]
  97. );
  98. }
  99. clearBpmnJS();
  100. var instance = new BpmnJS(_options);
  101. setBpmnJS(instance);
  102. return instance.importXML(diagram).then(function(result) {
  103. return { error: null, warnings: result.warnings };
  104. }).catch(function(err) {
  105. return { error: err, warnings: err.warnings };
  106. });
  107. };
  108. }
  109. /**
  110. * Bootstrap the Modeler given the specified options and a number of locals (i.e. services)
  111. *
  112. * @example
  113. *
  114. * describe(function() {
  115. *
  116. * var mockEvents;
  117. *
  118. * beforeEach(bootstrapModeler('some-xml', function() {
  119. * mockEvents = new Events();
  120. *
  121. * return {
  122. * events: mockEvents
  123. * };
  124. * }));
  125. *
  126. * });
  127. *
  128. * @param {string} xml document to display
  129. * @param {Object} (options) optional options to be passed to the diagram upon instantiation
  130. * @param {Object|Function} locals the local overrides to be used by the diagram or a function that produces them
  131. * @return {Function} a function to be passed to beforeEach
  132. */
  133. export function bootstrapModeler(diagram, options, locals) {
  134. return bootstrapBpmnJS(Modeler, diagram, options, locals);
  135. }
  136. /**
  137. * Bootstrap the Viewer given the specified options and a number of locals (i.e. services)
  138. *
  139. * @example
  140. *
  141. * describe(function() {
  142. *
  143. * var mockEvents;
  144. *
  145. * beforeEach(bootstrapViewer('some-xml', function() {
  146. * mockEvents = new Events();
  147. *
  148. * return {
  149. * events: mockEvents
  150. * };
  151. * }));
  152. *
  153. * });
  154. *
  155. * @param {string} xml document to display
  156. * @param {Object} (options) optional options to be passed to the diagram upon instantiation
  157. * @param {Object|Function} locals the local overrides to be used by the diagram or a function that produces them
  158. * @return {Function} a function to be passed to beforeEach
  159. */
  160. export function bootstrapViewer(diagram, options, locals) {
  161. return bootstrapBpmnJS(Viewer, diagram, options, locals);
  162. }
  163. /**
  164. * Injects services of an instantiated diagram into the argument.
  165. *
  166. * Use it in conjunction with {@link #bootstrapModeler} or {@link #bootstrapViewer}.
  167. *
  168. * @example
  169. *
  170. * describe(function() {
  171. *
  172. * var mockEvents;
  173. *
  174. * beforeEach(bootstrapViewer(...));
  175. *
  176. * it('should provide mocked events', inject(function(events) {
  177. * expect(events).to.eql(mockEvents);
  178. * }));
  179. *
  180. * });
  181. *
  182. * @param {Function} fn the function to inject to
  183. * @return {Function} a function that can be passed to it to carry out the injection
  184. */
  185. export function inject(fn) {
  186. return function() {
  187. if (!BPMN_JS) {
  188. throw new Error(
  189. 'no bootstraped bpmn-js instance, ' +
  190. 'ensure you created it via #boostrap(Modeler|Viewer)'
  191. );
  192. }
  193. return BPMN_JS.invoke(fn);
  194. };
  195. }
  196. /**
  197. * Returns the current active BpmnJS instance.
  198. *
  199. * @return {BpmnJS}
  200. */
  201. export function getBpmnJS() {
  202. return BPMN_JS;
  203. }
  204. export function clearBpmnJS() {
  205. // clean up old bpmn-js instance
  206. if (BPMN_JS) {
  207. BPMN_JS.destroy();
  208. BPMN_JS = null;
  209. }
  210. }
  211. // This method always resolves.
  212. // It helps us to do done(err) within the same block.
  213. export function createViewer(container, viewerInstance, xml, diagramId) {
  214. clearBpmnJS();
  215. var viewer = new viewerInstance({ container: container });
  216. setBpmnJS(viewer);
  217. return viewer.importXML(xml, diagramId).then(function(result) {
  218. return { warnings: result.warnings, viewer: viewer };
  219. }).catch(function(err) {
  220. return { error: err, viewer: viewer, warnings: err.warnings };
  221. });
  222. }
  223. function logConfigured(type, force) {
  224. var url = new URL(window.location.href);
  225. var log = ('searchParams' in url) && url.searchParams.get('log') || '';
  226. return force || log.includes('save-xml');
  227. }
  228. /**
  229. * Enable logging on a modeler instance.
  230. *
  231. * @param {import('bpmn-js')} modeler
  232. * @param {boolean} [force=false]
  233. */
  234. export function enableLogging(modeler, force) {
  235. var saveXML = logConfigured('save-xml', force);
  236. saveXML && modeler.on('commandStack.changed', function() {
  237. modeler.saveXML({ format: true }).then(function(result) {
  238. console.log(result.xml);
  239. });
  240. });
  241. }
  242. export function setBpmnJS(instance) {
  243. BPMN_JS = instance;
  244. }
  245. export function insertCSS(name, css) {
  246. if (document.querySelector('[data-css-file="' + name + '"]')) {
  247. return;
  248. }
  249. var head = document.head || document.getElementsByTagName('head')[0],
  250. style = document.createElement('style');
  251. style.setAttribute('data-css-file', name);
  252. style.type = 'text/css';
  253. if (style.styleSheet) {
  254. style.styleSheet.cssText = css;
  255. } else {
  256. style.appendChild(document.createTextNode(css));
  257. }
  258. head.appendChild(style);
  259. }