API Docs for: 3.18.1
Show:

File: test-console/js/test-console.js

  1. /**
  2. Provides a specialized log console widget that's pre-configured to display YUI
  3. Test output with no extra configuration.
  4.  
  5. @example
  6.  
  7. <div id="log" class="yui3-skin-sam"></div>
  8.  
  9. <script>
  10. YUI().use('test-console', function (Y) {
  11. // ... set up your test cases here ...
  12.  
  13. // Render the console inside the #log div, then run the tests.
  14. new Y.Test.Console().render('#log');
  15. Y.Test.Runner.run();
  16. });
  17. </script>
  18.  
  19. @module test-console
  20. @namespace Test
  21. @class Console
  22. @extends Console
  23. @constructor
  24.  
  25. @param {Object} [config] Config attributes.
  26. @param {Object} [config.filters] Category filter configuration.
  27.  
  28. @since 3.5.0
  29. **/
  30.  
  31. function TestConsole() {
  32. TestConsole.superclass.constructor.apply(this, arguments);
  33. }
  34.  
  35. Y.namespace('Test').Console = Y.extend(TestConsole, Y.Console, {
  36. initializer: function (config) {
  37. this.on('entry', this._onEntry);
  38.  
  39. this.plug(Y.Plugin.ConsoleFilters, {
  40. category: Y.merge({
  41. info : true,
  42. pass : false,
  43. fail : true,
  44. status: false
  45. }, (config && config.filters) || {}),
  46.  
  47. defaultVisibility: false,
  48.  
  49. source: {
  50. TestRunner: true
  51. }
  52. });
  53.  
  54. Y.Test.Runner.on('complete', Y.bind(this._parseCoverage, this));
  55. },
  56.  
  57. // -- Protected Coverage Parser ---------------------------------------------
  58. /**
  59. * Scans the coverage data to determine if it's an Istanbul coverage object.
  60. * @method _isIstanbul
  61. * @param {Object} json The coverage data to scan
  62. * @return {Boolean} True if this is Istanbul Coverage
  63. */
  64. _isIstanbul: function(json) {
  65. var first = Y.Object.keys(json)[0],
  66. ret = false;
  67.  
  68. if (json[first].s !== undefined && json[first].fnMap !== undefined) {
  69. ret = true;
  70. }
  71.  
  72. if (json.s !== undefined && json.fnMap !== undefined) {
  73. ret = true;
  74. }
  75. return ret;
  76. },
  77. /**
  78. * Parses and logs a summary of YUITest coverage data.
  79. * @method parseYUITest
  80. * @param {Object} coverage The YUITest Coverage JSON data
  81. */
  82. parseYUITestCoverage: function (coverage) {
  83. var cov = {
  84. lines: {
  85. hit: 0,
  86. miss: 0,
  87. total: 0,
  88. percent: 0
  89. },
  90. functions: {
  91. hit: 0,
  92. miss: 0,
  93. total: 0,
  94. percent: 0
  95. }
  96. }, coverageLog;
  97.  
  98. Y.Object.each(coverage, function(info) {
  99. cov.lines.total += info.coveredLines;
  100. cov.lines.hit += info.calledLines;
  101. cov.lines.miss += (info.coveredLines - info.calledLines);
  102. cov.lines.percent = Math.floor((cov.lines.hit / cov.lines.total) * 100);
  103.  
  104. cov.functions.total += info.coveredFunctions;
  105. cov.functions.hit += info.calledFunctions;
  106. cov.functions.miss += (info.coveredFunctions - info.calledFunctions);
  107. cov.functions.percent = Math.floor((cov.functions.hit / cov.functions.total) * 100);
  108. });
  109.  
  110.  
  111. coverageLog = 'Lines: Hit:' + cov.lines.hit + ' Missed:' + cov.lines.miss + ' Total:' + cov.lines.total + ' Percent:' + cov.lines.percent + '%\n';
  112. coverageLog += 'Functions: Hit:' + cov.functions.hit + ' Missed:' + cov.functions.miss + ' Total:' + cov.functions.total + ' Percent:' + cov.functions.percent + '%';
  113.  
  114. this.log('Coverage: ' + coverageLog, 'info', 'TestRunner');
  115. },
  116. /**
  117. * Generates a generic summary object used for Istanbul conversions.
  118. * @method _blankSummary
  119. * @return {Object} Generic summary object
  120. */
  121. _blankSummary: function () {
  122. return {
  123. lines: {
  124. total: 0,
  125. covered: 0,
  126. pct: 'Unknown'
  127. },
  128. statements: {
  129. total: 0,
  130. covered: 0,
  131. pct: 'Unknown'
  132. },
  133. functions: {
  134. total: 0,
  135. covered: 0,
  136. pct: 'Unknown'
  137. },
  138. branches: {
  139. total: 0,
  140. covered: 0,
  141. pct: 'Unknown'
  142. }
  143. };
  144. },
  145. /**
  146. * Calculates line numbers from statement coverage
  147. * @method _addDerivedInfoForFile
  148. * @private
  149. * @param {Object} fileCoverage JSON coverage data
  150. */
  151. _addDerivedInfoForFile: function (fileCoverage) {
  152. var statementMap = fileCoverage.statementMap,
  153. statements = fileCoverage.s,
  154. lineMap;
  155.  
  156. if (!fileCoverage.l) {
  157. fileCoverage.l = lineMap = {};
  158. Y.Object.each(statements, function (value, st) {
  159. var line = statementMap[st].start.line,
  160. count = statements[st],
  161. prevVal = lineMap[line];
  162. if (typeof prevVal === 'undefined' || prevVal < count) {
  163. lineMap[line] = count;
  164. }
  165. });
  166. }
  167. },
  168. /**
  169. * Generic percent calculator
  170. * @method _percent
  171. * @param {Number} covered The covered amount
  172. * @param {Number} total The total
  173. * @private
  174. */
  175. _percent: function (covered, total) {
  176. var tmp, pct = 100.00;
  177. if (total > 0) {
  178. tmp = 1000 * 100 * covered / total + 5;
  179. pct = Math.floor(tmp / 10) / 100;
  180. }
  181. return pct;
  182. },
  183. /**
  184. * Summarize simple properties in the coverage data
  185. * @method _computSimpleTotals
  186. * @private
  187. * @param {Object} fileCoverage JSON coverage data
  188. * @param {String} property The property to summarize
  189. */
  190. _computeSimpleTotals: function (fileCoverage, property) {
  191. var stats = fileCoverage[property],
  192. ret = { total: 0, covered: 0 };
  193.  
  194. Y.Object.each(stats, function(val) {
  195. ret.total += 1;
  196. if (val) {
  197. ret.covered += 1;
  198. }
  199. });
  200. ret.pct = this._percent(ret.covered, ret.total);
  201. return ret;
  202. },
  203. /**
  204. * Noramlizes branch data from Istanbul
  205. * @method _computeBranchTotals
  206. * @private
  207. * @param {Object} fileCoverage JSON coverage data
  208. */
  209. _computeBranchTotals: function (fileCoverage) {
  210. var stats = fileCoverage.b,
  211. ret = { total: 0, covered: 0 };
  212.  
  213. Y.Object.each(stats, function (branches) {
  214. var covered = Y.Array.filter(branches, function (num) { return num > 0; });
  215. ret.total += branches.length;
  216. ret.covered += covered.length;
  217. });
  218. ret.pct = this._percent(ret.covered, ret.total);
  219. return ret;
  220. },
  221. /**
  222. * Takes an Istanbul coverage object, normalizes it and prints a log with a summary
  223. * @method parseInstanbul
  224. * @param {Object} coverage The coverage object to normalize and log
  225. */
  226. parseIstanbul: function (coverage) {
  227. var self = this,
  228. str = 'Coverage Report:\n';
  229.  
  230. Y.Object.each(coverage, function(fileCoverage, file) {
  231. var ret = self._blankSummary();
  232.  
  233. self._addDerivedInfoForFile(fileCoverage);
  234. ret.lines = self._computeSimpleTotals(fileCoverage, 'l');
  235. ret.functions = self._computeSimpleTotals(fileCoverage, 'f');
  236. ret.statements = self._computeSimpleTotals(fileCoverage, 's');
  237. ret.branches = self._computeBranchTotals(fileCoverage);
  238. str += file + ':\n';
  239. Y.Array.each(['lines','functions','statements','branches'], function(key) {
  240. str += ' ' + key +': ' + ret[key].covered + '/' + ret[key].total + ' : ' + ret[key].pct + '%\n';
  241. });
  242.  
  243. });
  244. this.log(str, 'info', 'TestRunner');
  245.  
  246. },
  247. /**
  248. * Parses YUITest or Istanbul coverage results if they are available and logs them.
  249. * @method _parseCoverage
  250. * @private
  251. */
  252. _parseCoverage: function() {
  253. var coverage = Y.Test.Runner.getCoverage();
  254. if (!coverage) {
  255. return;
  256. }
  257. if (this._isIstanbul(coverage)) {
  258. this.parseIstanbul(coverage);
  259. } else {
  260. this.parseYUITestCoverage(coverage);
  261. }
  262. },
  263.  
  264. // -- Protected Event Handlers ---------------------------------------------
  265. _onEntry: function (e) {
  266. var msg = e.message;
  267.  
  268. if (msg.category === 'info'
  269. && /\s(?:case|suite)\s|yuitests\d+|began/.test(msg.message)) {
  270. msg.category = 'status';
  271. } else if (msg.category === 'fail') {
  272. this.printBuffer();
  273. }
  274. }
  275. }, {
  276. NAME: 'testConsole',
  277.  
  278. ATTRS: {
  279. entryTemplate: {
  280. value:
  281. '<div class="{entry_class} {cat_class} {src_class}">' +
  282. '<div class="{entry_content_class}">{message}</div>' +
  283. '</div>'
  284. },
  285.  
  286. height: {
  287. value: '350px'
  288. },
  289.  
  290. newestOnTop: {
  291. value: false
  292. },
  293.  
  294. style: {
  295. value: 'block'
  296. },
  297.  
  298. width: {
  299. value: Y.UA.ie && Y.UA.ie < 9 ? '100%' : 'inherit'
  300. }
  301. }
  302. });
  303.