vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

403 lines
11 KiB

  1. /**
  2. * TODO - add tests for:
  3. * ====
  4. *
  5. * - !!! good test case with the tags for max width
  6. * - pathological cases of spaces (and other whitespace!)
  7. * - html unclosed or unopened tags
  8. * - html tag combinations with no font defined (e.g. bold within mono)
  9. */
  10. var assert = require('assert')
  11. var Label = require('../lib/network/modules/components/shared/Label').default;
  12. var NodesHandler = require('../lib/network/modules/NodesHandler').default;
  13. /**************************************************************
  14. * Dummy class definitions for minimal required functionality.
  15. **************************************************************/
  16. class DummyContext {
  17. measureText(text) {
  18. return {
  19. width: 12*text.length,
  20. height: 14
  21. };
  22. }
  23. }
  24. class DummyLayoutEngine {
  25. positionInitially() {}
  26. }
  27. /**************************************************************
  28. * End Dummy class definitions
  29. **************************************************************/
  30. describe('Network Label', function() {
  31. /**
  32. * Retrieve options object from a NodesHandler instance
  33. *
  34. * NOTE: these are options at the node-level
  35. */
  36. function getOptions(options = {}) {
  37. var body = {
  38. functions: {},
  39. emitter: {
  40. on: function() {}
  41. }
  42. }
  43. var nodesHandler = new NodesHandler(body, {}, options, new DummyLayoutEngine() );
  44. //console.log(JSON.stringify(nodesHandler.options, null, 2));
  45. return nodesHandler.options;
  46. }
  47. /**
  48. * Check if the returned lines and blocks are as expected.
  49. *
  50. * All width/height fields and font info are ignored.
  51. * Within blocks, only the text is compared
  52. */
  53. function checkBlocks(returned, expected) {
  54. let showBlocks = () => {
  55. return '\nreturned: ' + JSON.stringify(returned, null, 2) + '\n' +
  56. 'expected: ' + JSON.stringify(expected, null, 2);
  57. }
  58. assert.equal(expected.lines.length, returned.lines.length, 'Number of lines does not match, ' + showBlocks());
  59. for (let i = 0; i < returned.lines.length; ++i) {
  60. let retLine = returned.lines[i];
  61. let expLine = expected.lines[i];
  62. assert(retLine.blocks.length === expLine.blocks.length, 'Number of blocks does not match, ' + showBlocks());
  63. for (let j = 0; j < retLine.blocks.length; ++j) {
  64. let retBlock = retLine.blocks[j];
  65. let expBlock = expLine.blocks[j];
  66. assert(retBlock.text === expBlock.text, 'Text does not match, ' + showBlocks());
  67. assert(retBlock.mod !== undefined);
  68. if (retBlock.mod === 'normal' || retBlock.mod === '') {
  69. assert(expBlock.mod === undefined || expBlock.mod === 'normal' || expBlock === '',
  70. 'No mod field expected in returned, ' + showBlocks());
  71. } else {
  72. assert(retBlock.mod === expBlock.mod, 'Mod fields do not match, line: ' + i + ', block: ' + j +
  73. '; ret: ' + retBlock.mod + ', exp: ' + expBlock.mod + '\n' + showBlocks());
  74. }
  75. }
  76. }
  77. }
  78. function checkProcessedLabels(label, text, expected) {
  79. var ctx = new DummyContext();
  80. for (var i in text) {
  81. var ret = label._processLabelText(ctx, false, false, text[i]);
  82. //console.log(JSON.stringify(ret, null, 2));
  83. checkBlocks(ret, expected[i]);
  84. }
  85. }
  86. /**************************************************************
  87. * Test data
  88. **************************************************************/
  89. var normal_text = [
  90. "label text",
  91. "label\nwith\nnewlines",
  92. "OnereallylongwordthatshouldgooverwidthConstraint.maximumifdefined",
  93. "One really long sentence that should go over widthConstraint.maximum if defined",
  94. "Reallyoneenormouslylargelabel withtwobigwordsgoingoverwayovermax"
  95. ]
  96. var html_text = [
  97. "label <b>with</b> <code>some</code> <i>multi <b>tags</b></i>",
  98. "label <b>with</b> <code>some</code> \n <i>multi <b>tags</b></i>\n and newlines" // NB spaces around \n's
  99. ];
  100. var markdown_text = [
  101. "label *with* `some` _multi *tags*_",
  102. "label *with* `some` \n _multi *tags*_\n and newlines" // NB spaces around \n's
  103. ];
  104. /**************************************************************
  105. * Expected Results
  106. **************************************************************/
  107. var normal_expected = [{
  108. // In first item, width/height kept in for reference
  109. width: 120,
  110. height: 14,
  111. lines: [{
  112. width: 120,
  113. height: 14,
  114. blocks: [{
  115. text: "label text",
  116. width: 120,
  117. height: 14,
  118. }]
  119. }]
  120. }, {
  121. lines: [{
  122. blocks: [{text: "label"}]
  123. }, {
  124. blocks: [{text: "with"}]
  125. }, {
  126. blocks: [{text: "newlines"}]
  127. }]
  128. }, {
  129. // From here onward, changes width max width set
  130. lines: [{
  131. blocks: [{text: "OnereallylongwordthatshouldgooverwidthConstraint.maximumifdefined"}]
  132. }]
  133. }, {
  134. lines: [{
  135. blocks: [{text: "One really long sentence that should go over widthConstraint.maximum if defined"}]
  136. }]
  137. }, {
  138. lines: [{
  139. blocks: [{text: "Reallyoneenormouslylargelabel withtwobigwordsgoingoverwayovermax"}]
  140. }]
  141. }];
  142. const indexWidthConstrained = 2; // index of first item that will be different with max width set
  143. var normal_widthConstraint_expected = normal_expected.slice(0, indexWidthConstrained);
  144. Array.prototype.push.apply(normal_widthConstraint_expected, [{
  145. lines: [{
  146. blocks: [{text: "Onereallylongwordthatshoul"}]
  147. }, {
  148. blocks: [{text: "dgooverwidthConstraint.max"}]
  149. }, {
  150. blocks: [{text: "imumifdefined"}]
  151. }]
  152. }, {
  153. lines: [{
  154. blocks: [{text: "One really long sentence"}]
  155. }, {
  156. blocks: [{text: "that should go over"}]
  157. }, {
  158. blocks: [{text: "widthConstraint.maximum"}]
  159. }, {
  160. blocks: [{text: "if defined"}]
  161. }]
  162. }, {
  163. lines: [{
  164. blocks: [{text: "Reallyoneenormouslylargela"}]
  165. }, {
  166. blocks: [{text: "bel"}]
  167. }, {
  168. blocks: [{text: "withtwobigwordsgoingoverwa"}]
  169. }, {
  170. blocks: [{text: "yovermax"}]
  171. }]
  172. }]);
  173. var html_unchanged_expected = [{
  174. lines: [{
  175. blocks: [{text: "label <b>with</b> <code>some</code> <i>multi <b>tags</b></i>"}]
  176. }]
  177. }, {
  178. lines: [{
  179. blocks: [{text: "label <b>with</b> <code>some</code> "}]
  180. }, {
  181. blocks: [{text: " <i>multi <b>tags</b></i>"}]
  182. }, {
  183. blocks: [{text: " and newlines"}]
  184. }]
  185. }];
  186. var html_widthConstraint_unchanged = [{
  187. lines: [{
  188. blocks: [{text: "label <b>with</b>"}]
  189. }, {
  190. blocks: [{text: "<code>some</code>"}]
  191. }, {
  192. blocks: [{text: "<i>multi <b>tags</b></i>"}]
  193. }]
  194. }, {
  195. lines: [{
  196. blocks: [{text: "label <b>with</b>"}]
  197. }, {
  198. blocks: [{text: "<code>some</code> "}]
  199. }, {
  200. blocks: [{text: " <i>multi <b>tags</b></i>"}]
  201. }, {
  202. blocks: [{text: " and newlines"}]
  203. }]
  204. }];
  205. var markdown_unchanged_expected = [{
  206. lines: [{
  207. blocks: [{text: "label *with* `some` _multi *tags*_"}]
  208. }]
  209. }, {
  210. lines: [{
  211. blocks: [{text: "label *with* `some` "}]
  212. }, {
  213. blocks: [{text: " _multi *tags*_"}]
  214. }, {
  215. blocks: [{text: " and newlines"}]
  216. }]
  217. }];
  218. var markdown_widthConstraint_expected = [{
  219. lines: [{
  220. blocks: [{text: "label *with* `some`"}]
  221. }, {
  222. blocks: [{text: "_multi *tags*_"}]
  223. }]
  224. }, {
  225. lines: [{
  226. blocks: [{text: "label *with* `some` "}]
  227. }, {
  228. blocks: [{text: " _multi *tags*_"}]
  229. }, {
  230. blocks: [{text: " and newlines"}]
  231. }]
  232. }];
  233. var multi_expected = [{
  234. lines: [{
  235. blocks: [
  236. {text: "label "},
  237. {text: "with" , mod: 'bold'},
  238. {text: " "},
  239. {text: "some" , mod: 'mono'},
  240. {text: " "},
  241. {text: "multi ", mod: 'ital'},
  242. {text: "tags" , mod: 'boldital'}
  243. ]
  244. }]
  245. }, {
  246. lines: [{
  247. blocks: [
  248. {text: "label "},
  249. {text: "with" , mod: 'bold'},
  250. {text: " "},
  251. {text: "some" , mod: 'mono'},
  252. {text: " "}
  253. ]
  254. }, {
  255. blocks: [
  256. {text: " "},
  257. {text: "multi ", mod: 'ital'},
  258. {text: "tags" , mod: 'boldital'}
  259. ]
  260. }, {
  261. blocks: [{text: " and newlines"}]
  262. }]
  263. }];
  264. /**************************************************************
  265. * End Expected Results
  266. **************************************************************/
  267. it('parses normal text labels', function (done) {
  268. var label = new Label({}, getOptions());
  269. checkProcessedLabels(label, normal_text , normal_expected);
  270. checkProcessedLabels(label, html_text , html_unchanged_expected); // html unchanged
  271. checkProcessedLabels(label, markdown_text, markdown_unchanged_expected); // markdown unchanged
  272. done();
  273. });
  274. it('parses html labels', function (done) {
  275. var options = getOptions(options);
  276. options.font.multi = true; // TODO: also test 'html', also test illegal value here
  277. var label = new Label({}, options);
  278. checkProcessedLabels(label, normal_text , normal_expected); // normal as usual
  279. checkProcessedLabels(label, html_text , multi_expected);
  280. checkProcessedLabels(label, markdown_text, markdown_unchanged_expected); // markdown unchanged
  281. done();
  282. });
  283. it('parses markdown labels', function (done) {
  284. var options = getOptions(options);
  285. options.font.multi = 'markdown'; // TODO: also test 'md', also test illegal value here
  286. var label = new Label({}, options);
  287. checkProcessedLabels(label, normal_text , normal_expected); // normal as usual
  288. checkProcessedLabels(label, html_text , html_unchanged_expected); // html unchanged
  289. checkProcessedLabels(label, markdown_text, multi_expected);
  290. done();
  291. });
  292. it('handles normal text with widthConstraint.maximum', function (done) {
  293. var options = getOptions(options);
  294. //
  295. // What the user would set:
  296. //
  297. // options.widthConstraint = { minimum: 100, maximum: 200};
  298. //
  299. // No sense in adding minWdt, not used when splitting labels into lines
  300. //
  301. // This comment also applies to the usage of maxWdt in the test cases below
  302. //
  303. options.font.maxWdt = 300;
  304. var label = new Label({}, options);
  305. checkProcessedLabels(label, normal_text , normal_widthConstraint_expected);
  306. checkProcessedLabels(label, html_text , html_widthConstraint_unchanged); // html unchanged
  307. checkProcessedLabels(label, markdown_text, markdown_widthConstraint_expected); // markdown unchanged
  308. done();
  309. });
  310. it('handles html tags with widthConstraint.maximum', function (done) {
  311. var options = getOptions(options);
  312. options.font.multi = true;
  313. options.font.maxWdt = 300;
  314. var label = new Label({}, options);
  315. checkProcessedLabels(label, normal_text , normal_widthConstraint_expected);
  316. checkProcessedLabels(label, html_text , multi_expected);
  317. checkProcessedLabels(label, markdown_text, markdown_widthConstraint_expected);
  318. done();
  319. });
  320. it('handles markdown tags with widthConstraint.maximum', function (done) {
  321. var options = getOptions(options);
  322. options.font.multi = 'markdown';
  323. options.font.maxWdt = 300;
  324. var label = new Label({}, options);
  325. checkProcessedLabels(label, normal_text , normal_widthConstraint_expected);
  326. checkProcessedLabels(label, html_text , html_widthConstraint_unchanged);
  327. checkProcessedLabels(label, markdown_text, multi_expected);
  328. done();
  329. });
  330. });