cov.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /* istanbul ignore next */
  2. 'use strict';
  3. const debug = require('debug')('egg-bin');
  4. const path = require('path');
  5. const rimraf = require('mz-modules/rimraf');
  6. const testExclude = require('test-exclude');
  7. const Command = require('./test');
  8. const EXCLUDES = Symbol('cov#excludes');
  9. /* istanbul ignore next */
  10. class CovCommand extends Command {
  11. constructor(argv) {
  12. super(argv);
  13. this.usage = 'Usage: egg-bin cov';
  14. this.options = {
  15. x: {
  16. description: 'istanbul coverage ignore, one or more fileset patterns',
  17. type: 'string',
  18. },
  19. prerequire: {
  20. description: 'prerequire files for coverage instrument',
  21. type: 'boolean',
  22. },
  23. nyc: {
  24. description: 'nyc instruments passthrough',
  25. type: 'string',
  26. default: '--temp-directory ./node_modules/.nyc_output -r text-summary -r json-summary -r json -r lcov',
  27. },
  28. c8: {
  29. description: 'c8 instruments passthrough',
  30. type: 'string',
  31. default: '--temp-directory ./node_modules/.c8_output -r text-summary -r json-summary -r json -r lcov',
  32. },
  33. 'c8-report': {
  34. description: 'use c8 to report coverage, default to false',
  35. type: 'boolean',
  36. default: false,
  37. },
  38. };
  39. // you can add ignore dirs here
  40. this[EXCLUDES] = new Set([
  41. 'example/',
  42. 'examples/',
  43. 'mocks**/',
  44. 'docs/',
  45. ].concat(testExclude.defaultExclude));
  46. }
  47. get description() {
  48. return 'Run test with coverage';
  49. }
  50. * run(context) {
  51. const { cwd, argv, execArgv, env } = context;
  52. if (argv.prerequire) {
  53. env.EGG_BIN_PREREQUIRE = 'true';
  54. }
  55. delete argv.prerequire;
  56. // ignore coverage
  57. if (argv.x) {
  58. if (Array.isArray(argv.x)) {
  59. for (const exclude of argv.x) {
  60. this.addExclude(exclude);
  61. }
  62. } else {
  63. this.addExclude(argv.x);
  64. }
  65. argv.x = undefined;
  66. }
  67. const excludes = (process.env.COV_EXCLUDES && process.env.COV_EXCLUDES.split(',')) || [];
  68. for (const exclude of excludes) {
  69. this.addExclude(exclude);
  70. }
  71. const opt = {
  72. cwd,
  73. execArgv,
  74. env: Object.assign({
  75. NODE_ENV: 'test',
  76. EGG_TYPESCRIPT: context.argv.typescript,
  77. }, env),
  78. };
  79. // https://github.com/eggjs/egg/issues/3930
  80. if (context.argv.typescript) {
  81. opt.env.SPAWN_WRAP_SHIM_ROOT = path.join(cwd, 'node_modules');
  82. }
  83. let cli = require.resolve('nyc/bin/nyc.js');
  84. let outputDir = path.join(cwd, 'node_modules/.nyc_output');
  85. if (argv['c8-report']) {
  86. cli = require.resolve('c8/bin/c8.js');
  87. outputDir = path.join(cwd, 'node_modules/.c8_output');
  88. }
  89. yield rimraf(outputDir);
  90. const coverageDir = path.join(cwd, 'coverage');
  91. yield rimraf(coverageDir);
  92. const covArgs = yield this.getCovArgs(context);
  93. if (!covArgs) return;
  94. debug('covArgs: %j', covArgs);
  95. yield this.helper.forkNode(cli, covArgs, opt);
  96. }
  97. /**
  98. * add istanbul coverage ignore
  99. * @param {String} exclude - glob pattern
  100. */
  101. addExclude(exclude) {
  102. this[EXCLUDES].add(exclude);
  103. }
  104. /**
  105. * get coverage args
  106. * @param {Object} context - { cwd, argv, ...}
  107. * @return {Array} args for nyc
  108. * @protected
  109. */
  110. * getCovArgs(context) {
  111. let covArgs = [
  112. // '--show-process-tree',
  113. ];
  114. // typescript support
  115. if (context.argv.typescript) {
  116. covArgs.push('--extension', '.ts');
  117. this.addExclude('typings/');
  118. this.addExclude('**/*.d.ts');
  119. }
  120. // nyc or c8 args passthrough
  121. let passthroughArgs = context.argv.nyc;
  122. if (context.argv['c8-report']) {
  123. passthroughArgs = context.argv.c8;
  124. context.argv['c8-report'] = undefined;
  125. }
  126. context.argv.nyc = undefined;
  127. context.argv.c8 = undefined;
  128. if (passthroughArgs) {
  129. covArgs = covArgs.concat(passthroughArgs.split(' '));
  130. }
  131. for (const exclude of this[EXCLUDES]) {
  132. covArgs.push('-x');
  133. covArgs.push(exclude);
  134. }
  135. const testArgs = yield this.formatTestArgs(context);
  136. if (!testArgs) return;
  137. covArgs.push(require.resolve('mocha/bin/_mocha'));
  138. covArgs = covArgs.concat(testArgs);
  139. return covArgs;
  140. }
  141. }
  142. module.exports = CovCommand;