uiHelper.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. (function (context) {
  2. var helper = context.uiHelper = {};
  3. // canvas comparing strategy, 'stack' or 'content'
  4. var STRATEGY = 'content';
  5. // always display images even if no error
  6. var ALWAYS_SHOW_IMAGE = true;
  7. // dom for failed cases
  8. var failedDom = document.createElement('div');
  9. failedDom.setAttribute('id', 'failed-panel');
  10. var hasFailedDom = false;
  11. /**
  12. * expect canvas.toDataURL to be the same by old and new echarts
  13. * @param {string} title title of suite and case
  14. * @param {function} doTest test body
  15. * @param {function} done done callback provided by jasmine
  16. */
  17. helper.expectEqualCanvasContent = function(title, doTest, done) {
  18. var that = this;
  19. window.require(['oldEcharts', 'newEcharts'], function (oldE, newE) {
  20. var oldImg = doTest(oldE).toDataURL();
  21. var newImg = doTest(newE).toDataURL();
  22. if (ALWAYS_SHOW_IMAGE || oldImg !== newImg) {
  23. // show difference rate of canvas content as string
  24. var diff = 0;
  25. for (var i = 0; i < oldImg.length; ++i) {
  26. if (oldImg[i] !== newImg[i]) {
  27. ++diff;
  28. }
  29. }
  30. if (newImg.length > oldImg.length) {
  31. diff += newImg.length - oldImg.length;
  32. }
  33. var log = 'Different rate: ' + diff + '/' + oldImg.length
  34. + '. ';
  35. that.addFailedCases(title, oldImg, newImg, log);
  36. }
  37. expect(oldImg).toEqual(newImg);
  38. done();
  39. });
  40. };
  41. /**
  42. * expect canvas operation stack provided by canteen
  43. * to be the same by old and new echarts
  44. * @param {string} title title of suite and case
  45. * @param {function} doTest test body
  46. * @param {function} done done callback provided by jasmine
  47. */
  48. helper.expectEqualCanvasStack = function(title, doTest, done) {
  49. window.require(['oldEcharts', 'newEcharts'], function (oldE, newE) {
  50. var oldCanvas = doTest(oldE);
  51. var newCanvas = doTest(newE);
  52. var oldImg = oldCanvas.toDataURL();
  53. var newImg = newCanvas.toDataURL();
  54. if (ALWAYS_SHOW_IMAGE || oldImg !== newImg) {
  55. helper.addFailedCases(title, oldImg, newImg);
  56. }
  57. var oldCtx = oldCanvas.getContext('2d');
  58. var newCtx = newCanvas.getContext('2d');
  59. // hash of canvas operation stack, provided by canteen
  60. // https://github.com/platfora/Canteen
  61. // console.log(oldCtx.hash());
  62. expect(oldCtx.hash()).toEqual(newCtx.hash());
  63. done();
  64. });
  65. };
  66. /**
  67. * expect canvas with strategy
  68. * @param {string} title title of suite and case
  69. * @param {function} doTest test body
  70. * @param {function} done done callback provided by jasmine
  71. */
  72. helper.expectEqualCanvas = function(title, doTest, done) {
  73. if (STRATEGY === 'content') {
  74. helper.expectEqualCanvasContent(title, doTest, done);
  75. } else if (STRATEGY === 'stack') {
  76. helper.expectEqualCanvasStack(title, doTest, done);
  77. } else {
  78. console.error('Invalid equal canvas strategy!');
  79. }
  80. };
  81. var optionCompareHelper = function(isExpectEqual,
  82. title,
  83. option1,
  84. option2) {
  85. it(title, function(done) {
  86. window.require(['newEcharts'], function (ec) {
  87. var canvas1 = helper.getRenderedCanvas(ec, function(myChart) {
  88. myChart.setOption(helper.preprocessOption(option1));
  89. });
  90. var canvas2 = helper.getRenderedCanvas(ec, function(myChart) {
  91. myChart.setOption(helper.preprocessOption(option2));
  92. });
  93. var ctx1 = canvas1.getContext('2d');
  94. var ctx2 = canvas2.getContext('2d');
  95. var img1 = canvas1.toDataURL();
  96. var img2 = canvas2.toDataURL();
  97. var compare1 = compare2 = null;
  98. if (STRATEGY === 'content') {
  99. compare1 = img1;
  100. compare2 = img2;
  101. } else if (STRATEGY === 'stack') {
  102. compare1 = ctx1.hash()
  103. compare2 = ctx2.hash();
  104. } else {
  105. console.error('Invalid equal canvas strategy!');
  106. }
  107. if (isExpectEqual) {
  108. expect(compare1).toEqual(compare2);
  109. } else {
  110. expect(compare1).not.toEqual(compare2);
  111. }
  112. if (ALWAYS_SHOW_IMAGE || (compare1 === compare2) ^ isExpectEqual) {
  113. helper.addFailedCases(title, img1, img2);
  114. // console.log(title);
  115. // console.log(JSON.stringify(ctx1.stack()));
  116. // console.log(JSON.stringify(ctx2.stack()));
  117. }
  118. done();
  119. });
  120. });
  121. };
  122. /**
  123. * expect two options have the same canvas for new echarts
  124. * @param {string} title title of test case
  125. * @param {object} option1 one echarts option
  126. * @param {object} option2 the other echarts option
  127. * @param {function} done callback for jasmine
  128. */
  129. helper.expectEqualOption = function(title, option1, option2) {
  130. optionCompareHelper(true, title, option1, option2);
  131. };
  132. /**
  133. * expect two options have different canvas for new echarts
  134. * @param {string} title title of test case
  135. * @param {object} option1 one echarts option
  136. * @param {object} option2 the other echarts option
  137. * @param {function} done callback for jasmine
  138. */
  139. helper.expectNotEqualOption = function(title, option1, option2) {
  140. optionCompareHelper(false, title, option1, option2);
  141. };
  142. /**
  143. * get rendered canvas with echarts and operations
  144. * @param {object} echarts echarts
  145. * @param {function} operations operations with echarts
  146. * @return {Canvas} canvas rendered by echarts
  147. */
  148. helper.getRenderedCanvas = function(echarts, operations) {
  149. // init canvas with echarts
  150. var canvas = document.createElement('canvas');
  151. canvas.width = 400;
  152. canvas.height = 300;
  153. var myChart = echarts.init(canvas);
  154. // user defined operations
  155. operations(myChart);
  156. return canvas;
  157. };
  158. /**
  159. * run test with only setOption
  160. * @param {string} name name of the test
  161. * @param {object} option echarts option
  162. */
  163. helper.testOption = function(name, option) {
  164. var doTest = function(ec) {
  165. var canvas = helper.getRenderedCanvas(ec, function(myChart) {
  166. myChart.setOption(helper.preprocessOption(option));
  167. });
  168. return canvas;
  169. };
  170. it(name, function(done) {
  171. if (STRATEGY === 'content') {
  172. helper.expectEqualCanvasContent(name, doTest, done);
  173. } else if (STRATEGY === 'stack') {
  174. helper.expectEqualCanvasStack(name, doTest, done);
  175. } else {
  176. console.error('Invalid equal canvas strategy!');
  177. }
  178. });
  179. }
  180. /**
  181. * preprocess option and set default values
  182. * @param {object} option echarts option
  183. * @return {object} processed option
  184. */
  185. helper.preprocessOption = function(option) {
  186. if (typeof option.animation === 'undefined') {
  187. option.animation = false;
  188. }
  189. return option;
  190. }
  191. /**
  192. * run test with setOption for whole spec
  193. * @param {string} specName spec name
  194. * @param {object[]} suites arrary of suites
  195. * @param {boolean} isTestAll true to test all cases,
  196. * or false or undefined to the last one only
  197. */
  198. helper.testOptionSpec = function(specName, suites, isTestAll) {
  199. if (isTestAll === undefined) {
  200. // default value of test all to be true
  201. isTestAll = true;
  202. }
  203. var testCases = function(suiteName, cases) {
  204. describe(suiteName, function() {
  205. var start = isTestAll ? 0 : cases.length - 1;
  206. for (var cid = start; cid < cases.length; ++cid) {
  207. var name = specName + ' - ' + suiteName + ': '
  208. + cases[cid].name;
  209. if (cases[cid].cases) {
  210. // another level of cases
  211. testCases(name, cases[cid].cases);
  212. return;
  213. }
  214. if (cases[cid].test === 'equalOption') {
  215. helper.expectEqualOption(name, cases[cid].option1,
  216. cases[cid].option2);
  217. helper.testOption(name + ', same as last version',
  218. cases[cid].option1);
  219. } else if (cases[cid].test === 'notEqualOption') {
  220. helper.expectNotEqualOption(name, cases[cid].option1,
  221. cases[cid].option2);
  222. helper.testOption(name + ', same as last version',
  223. cases[cid].option1);
  224. } else {
  225. helper.testOption(name, cases[cid].option);
  226. }
  227. }
  228. });
  229. };
  230. var start = isTestAll ? 0 : suites.length - 1;
  231. for (var sid = start, slen = suites.length; sid < slen; ++sid) {
  232. testCases(suites[sid].name, suites[sid].cases);
  233. }
  234. }
  235. /**
  236. * @param {string} name name of the test
  237. * @param {string} oldImgSrc old canvas.toDataURL value
  238. * @param {string} newImgSrc new canvas.toDataURL value
  239. * @param {string} extraLog extra log information
  240. * add a failed case in dom
  241. */
  242. helper.addFailedCases = function(name, oldImgSrc, newImgSrc, extraLog) {
  243. // group of this case
  244. var group = document.createElement('div');
  245. var title = document.createElement('h6');
  246. var log = name + ': ';
  247. if (extraLog !== undefined) {
  248. log += extraLog;
  249. }
  250. log += 'Here are old, new, and diff images.';
  251. title.innerHTML = log;
  252. group.appendChild(title);
  253. // old image and new image
  254. var oldImg = document.createElement('img');
  255. oldImg.src = oldImgSrc;
  256. oldImg.setAttribute('title', 'Old Image');
  257. var newImg = document.createElement('img');
  258. newImg.src = newImgSrc;
  259. newImg.setAttribute('title', 'New Image');
  260. group.appendChild(oldImg);
  261. group.appendChild(newImg);
  262. // diff image
  263. var diff = imagediff.diff(oldImg, newImg);
  264. var canvas = document.createElement('canvas');
  265. canvas.width = oldImg.width;
  266. canvas.height = oldImg.height;
  267. var ctx = canvas.getContext('2d');
  268. ctx.putImageData(diff, 0, 0);
  269. var diffImg = document.createElement('img');
  270. diffImg.src = canvas.toDataURL();
  271. diffImg.setAttribute('title', 'Diff Image');
  272. group.appendChild(diffImg);
  273. failedDom.appendChild(group);
  274. // append to dom
  275. if (!hasFailedDom) {
  276. var body = document.getElementsByTagName('body')[0];
  277. body.appendChild(failedDom);
  278. hasFailedDom = true;
  279. }
  280. };
  281. })(window);