index.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. 'use strict';
  2. /*
  3. Copyright 2012-2015, Yahoo Inc.
  4. Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
  5. */
  6. const fs = require('fs');
  7. const path = require('path');
  8. const { ReportBase } = require('istanbul-lib-report');
  9. const HtmlReport = require('../html');
  10. const standardLinkMapper = {
  11. getPath(node) {
  12. if (typeof node === 'string') {
  13. return node;
  14. }
  15. let filePath = node.getQualifiedName();
  16. if (node.isSummary()) {
  17. if (filePath !== '') {
  18. filePath += '/index.html';
  19. } else {
  20. filePath = 'index.html';
  21. }
  22. } else {
  23. filePath += '.html';
  24. }
  25. return filePath;
  26. },
  27. relativePath(source, target) {
  28. const targetPath = this.getPath(target);
  29. const sourcePath = path.dirname(this.getPath(source));
  30. return path.relative(sourcePath, targetPath);
  31. },
  32. assetPath(node, name) {
  33. return this.relativePath(this.getPath(node), name);
  34. }
  35. };
  36. class HtmlSpaReport extends ReportBase {
  37. constructor(opts = {}) {
  38. super({
  39. // force the summarizer to nested for html-spa
  40. summarizer: 'nested'
  41. });
  42. this.verbose = opts.verbose || false;
  43. this.linkMapper = opts.linkMapper || standardLinkMapper;
  44. this.subdir = opts.subdir || '';
  45. this.date = Date();
  46. this.skipEmpty = opts.skipEmpty;
  47. this.htmlReport = new HtmlReport(opts);
  48. this.htmlReport.getBreadcrumbHtml = function() {
  49. return '<a href="javascript:history.back()">Back</a>';
  50. };
  51. this.metricsToShow = opts.metricsToShow || [
  52. 'lines',
  53. 'branches',
  54. 'functions'
  55. ];
  56. }
  57. getWriter(context) {
  58. if (!this.subdir) {
  59. return context.writer;
  60. }
  61. return context.writer.writerForDir(this.subdir);
  62. }
  63. onStart(root, context) {
  64. this.htmlReport.onStart(root, context);
  65. const writer = this.getWriter(context);
  66. const srcDir = path.resolve(__dirname, './assets');
  67. fs.readdirSync(srcDir).forEach(f => {
  68. const resolvedSource = path.resolve(srcDir, f);
  69. const resolvedDestination = '.';
  70. const stat = fs.statSync(resolvedSource);
  71. let dest;
  72. if (stat.isFile()) {
  73. dest = resolvedDestination + '/' + f;
  74. if (this.verbose) {
  75. console.log('Write asset: ' + dest);
  76. }
  77. writer.copyFile(resolvedSource, dest);
  78. }
  79. });
  80. }
  81. onDetail(node, context) {
  82. this.htmlReport.onDetail(node, context);
  83. }
  84. getMetric(metric, type, context) {
  85. const isEmpty = metric.total === 0;
  86. return {
  87. total: metric.total,
  88. covered: metric.covered,
  89. skipped: metric.skipped,
  90. pct: isEmpty ? 0 : metric.pct,
  91. classForPercent: isEmpty
  92. ? 'empty'
  93. : context.classForPercent(type, metric.pct)
  94. };
  95. }
  96. toDataStructure(node, context) {
  97. const coverageSummary = node.getCoverageSummary();
  98. const metrics = {
  99. statements: this.getMetric(
  100. coverageSummary.statements,
  101. 'statements',
  102. context
  103. ),
  104. branches: this.getMetric(
  105. coverageSummary.branches,
  106. 'branches',
  107. context
  108. ),
  109. functions: this.getMetric(
  110. coverageSummary.functions,
  111. 'functions',
  112. context
  113. ),
  114. lines: this.getMetric(coverageSummary.lines, 'lines', context)
  115. };
  116. return {
  117. file: node.getRelativeName(),
  118. isEmpty: coverageSummary.isEmpty(),
  119. metrics,
  120. children:
  121. node.isSummary() &&
  122. node
  123. .getChildren()
  124. .map(child => this.toDataStructure(child, context))
  125. };
  126. }
  127. onEnd(rootNode, context) {
  128. const data = this.toDataStructure(rootNode, context);
  129. const cw = this.getWriter(context).writeFile(
  130. this.linkMapper.getPath(rootNode)
  131. );
  132. cw.write(
  133. `<!doctype html>
  134. <html lang="en">
  135. <head>
  136. <link rel="stylesheet" href="spa.css" />
  137. <meta name="viewport" content="width=device-width, initial-scale=1">
  138. </head>
  139. <body>
  140. <div id="app" class="app"></div>
  141. <script>
  142. window.data = ${JSON.stringify(data)};
  143. window.generatedDatetime = ${JSON.stringify(
  144. String(Date())
  145. )};
  146. window.metricsToShow = ${JSON.stringify(
  147. this.metricsToShow
  148. )};
  149. </script>
  150. <script src="bundle.js"></script>
  151. </body>
  152. </html>`
  153. );
  154. cw.close();
  155. }
  156. }
  157. module.exports = HtmlSpaReport;