collect-files.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. 'use strict';
  2. const path = require('node:path');
  3. const pc = require('picocolors');
  4. const debug = require('debug')('mocha:cli:run:helpers');
  5. const { minimatch } = require('minimatch');
  6. const {NO_FILES_MATCH_PATTERN} = require('../error-constants').constants;
  7. const lookupFiles = require('./lookup-files');
  8. const {castArray} = require('../utils');
  9. /**
  10. * Exports a function that collects test files from CLI parameters.
  11. * @see module:lib/cli/run-helpers
  12. * @see module:lib/cli/watch-run
  13. * @module
  14. * @private
  15. */
  16. /**
  17. * @typedef {import('../types.d.ts').FileCollectionOptions} FileCollectionOptions
  18. * @typedef {import('../types.d.ts').FileCollectionResponse} FileCollectionResponse
  19. */
  20. /**
  21. * Smash together an array of test files in the correct order
  22. * @param {FileCollectionOptions} [opts] - Options
  23. * @returns {FileCollectionResponse} An object containing a list of files to test and unmatched files.
  24. * @private
  25. */
  26. module.exports = ({
  27. ignore,
  28. extension,
  29. file: fileArgs,
  30. recursive,
  31. sort,
  32. spec
  33. } = {}) => {
  34. const unmatchedSpecFiles = [];
  35. const specFiles = spec.reduce((specFiles, arg) => {
  36. try {
  37. const moreSpecFiles = castArray(lookupFiles(arg, extension, recursive))
  38. .filter(filename =>
  39. ignore.every(
  40. pattern =>
  41. !minimatch(filename, pattern, {windowsPathsNoEscape: true})
  42. )
  43. )
  44. .map(filename => path.resolve(filename));
  45. return [...specFiles, ...moreSpecFiles];
  46. } catch (err) {
  47. if (err.code === NO_FILES_MATCH_PATTERN) {
  48. unmatchedSpecFiles.push({message: err.message, pattern: err.pattern});
  49. return specFiles;
  50. }
  51. throw err;
  52. }
  53. }, []);
  54. // check that each file passed in to --file exists
  55. const unmatchedFiles = [];
  56. fileArgs.forEach(file => {
  57. const fileAbsolutePath = path.resolve(file);
  58. try {
  59. // Used instead of fs.existsSync to ensure that file-ending less files are still resolved correctly
  60. require.resolve(fileAbsolutePath);
  61. } catch (err) {
  62. if (err.code === 'MODULE_NOT_FOUND') {
  63. unmatchedFiles.push({
  64. pattern: file,
  65. absolutePath: fileAbsolutePath
  66. });
  67. return;
  68. }
  69. throw err;
  70. }
  71. });
  72. // ensure we don't sort the stuff from fileArgs; order is important!
  73. if (sort) {
  74. specFiles.sort();
  75. }
  76. // add files given through --file to be ran first
  77. const files = [
  78. ...fileArgs.map(filepath => path.resolve(filepath)),
  79. ...specFiles
  80. ];
  81. debug('test files (in order): ', files);
  82. if (!files.length) {
  83. // give full message details when only 1 file is missing
  84. const noneFoundMsg =
  85. unmatchedSpecFiles.length === 1
  86. ? `Error: No test files found: ${JSON.stringify(
  87. unmatchedSpecFiles[0].pattern
  88. )}` // stringify to print escaped characters raw
  89. : 'Error: No test files found';
  90. console.error(pc.red(noneFoundMsg));
  91. process.exit(1);
  92. } else {
  93. // print messages as a warning
  94. unmatchedSpecFiles.forEach(warning => {
  95. console.warn(pc.yellow(`Warning: ${warning.message}`));
  96. });
  97. }
  98. return {
  99. files,
  100. unmatchedFiles
  101. };
  102. };