index.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.constants = void 0;
  6. Object.defineProperty(exports, 'defaults', {
  7. enumerable: true,
  8. get: function () {
  9. return _Defaults.default;
  10. }
  11. });
  12. Object.defineProperty(exports, 'deprecationEntries', {
  13. enumerable: true,
  14. get: function () {
  15. return _Deprecated.default;
  16. }
  17. });
  18. Object.defineProperty(exports, 'descriptions', {
  19. enumerable: true,
  20. get: function () {
  21. return _Descriptions.default;
  22. }
  23. });
  24. Object.defineProperty(exports, 'isJSONString', {
  25. enumerable: true,
  26. get: function () {
  27. return _utils.isJSONString;
  28. }
  29. });
  30. Object.defineProperty(exports, 'normalize', {
  31. enumerable: true,
  32. get: function () {
  33. return _normalize.default;
  34. }
  35. });
  36. exports.readConfig = readConfig;
  37. exports.readConfigs = readConfigs;
  38. exports.readInitialOptions = readInitialOptions;
  39. Object.defineProperty(exports, 'replaceRootDirInPath', {
  40. enumerable: true,
  41. get: function () {
  42. return _utils.replaceRootDirInPath;
  43. }
  44. });
  45. function path() {
  46. const data = _interopRequireWildcard(require('path'));
  47. path = function () {
  48. return data;
  49. };
  50. return data;
  51. }
  52. function _chalk() {
  53. const data = _interopRequireDefault(require('chalk'));
  54. _chalk = function () {
  55. return data;
  56. };
  57. return data;
  58. }
  59. function fs() {
  60. const data = _interopRequireWildcard(require('graceful-fs'));
  61. fs = function () {
  62. return data;
  63. };
  64. return data;
  65. }
  66. function _jestUtil() {
  67. const data = require('jest-util');
  68. _jestUtil = function () {
  69. return data;
  70. };
  71. return data;
  72. }
  73. var constants = _interopRequireWildcard(require('./constants'));
  74. exports.constants = constants;
  75. var _normalize = _interopRequireDefault(require('./normalize'));
  76. var _readConfigFileAndSetRootDir = _interopRequireDefault(
  77. require('./readConfigFileAndSetRootDir')
  78. );
  79. var _resolveConfigPath = _interopRequireDefault(require('./resolveConfigPath'));
  80. var _utils = require('./utils');
  81. var _Deprecated = _interopRequireDefault(require('./Deprecated'));
  82. var _Defaults = _interopRequireDefault(require('./Defaults'));
  83. var _Descriptions = _interopRequireDefault(require('./Descriptions'));
  84. function _interopRequireDefault(obj) {
  85. return obj && obj.__esModule ? obj : {default: obj};
  86. }
  87. function _getRequireWildcardCache(nodeInterop) {
  88. if (typeof WeakMap !== 'function') return null;
  89. var cacheBabelInterop = new WeakMap();
  90. var cacheNodeInterop = new WeakMap();
  91. return (_getRequireWildcardCache = function (nodeInterop) {
  92. return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
  93. })(nodeInterop);
  94. }
  95. function _interopRequireWildcard(obj, nodeInterop) {
  96. if (!nodeInterop && obj && obj.__esModule) {
  97. return obj;
  98. }
  99. if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
  100. return {default: obj};
  101. }
  102. var cache = _getRequireWildcardCache(nodeInterop);
  103. if (cache && cache.has(obj)) {
  104. return cache.get(obj);
  105. }
  106. var newObj = {};
  107. var hasPropertyDescriptor =
  108. Object.defineProperty && Object.getOwnPropertyDescriptor;
  109. for (var key in obj) {
  110. if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
  111. var desc = hasPropertyDescriptor
  112. ? Object.getOwnPropertyDescriptor(obj, key)
  113. : null;
  114. if (desc && (desc.get || desc.set)) {
  115. Object.defineProperty(newObj, key, desc);
  116. } else {
  117. newObj[key] = obj[key];
  118. }
  119. }
  120. }
  121. newObj.default = obj;
  122. if (cache) {
  123. cache.set(obj, newObj);
  124. }
  125. return newObj;
  126. }
  127. /**
  128. * Copyright (c) Meta Platforms, Inc. and affiliates.
  129. *
  130. * This source code is licensed under the MIT license found in the
  131. * LICENSE file in the root directory of this source tree.
  132. */
  133. async function readConfig(
  134. argv,
  135. packageRootOrConfig,
  136. // Whether it needs to look into `--config` arg passed to CLI.
  137. // It only used to read initial config. If the initial config contains
  138. // `project` property, we don't want to read `--config` value and rather
  139. // read individual configs for every project.
  140. skipArgvConfigOption,
  141. parentConfigDirname,
  142. projectIndex = Infinity,
  143. skipMultipleConfigError = false
  144. ) {
  145. const {config: initialOptions, configPath} = await readInitialOptions(
  146. argv.config,
  147. {
  148. packageRootOrConfig,
  149. parentConfigDirname,
  150. readFromCwd: skipArgvConfigOption,
  151. skipMultipleConfigError
  152. }
  153. );
  154. const packageRoot =
  155. typeof packageRootOrConfig === 'string'
  156. ? path().resolve(packageRootOrConfig)
  157. : undefined;
  158. const {options, hasDeprecationWarnings} = await (0, _normalize.default)(
  159. initialOptions,
  160. argv,
  161. configPath,
  162. projectIndex,
  163. skipArgvConfigOption && !(packageRoot === parentConfigDirname)
  164. );
  165. const {globalConfig, projectConfig} = groupOptions(options);
  166. return {
  167. configPath,
  168. globalConfig,
  169. hasDeprecationWarnings,
  170. projectConfig
  171. };
  172. }
  173. const groupOptions = options => ({
  174. globalConfig: Object.freeze({
  175. bail: options.bail,
  176. changedFilesWithAncestor: options.changedFilesWithAncestor,
  177. changedSince: options.changedSince,
  178. ci: options.ci,
  179. collectCoverage: options.collectCoverage,
  180. collectCoverageFrom: options.collectCoverageFrom,
  181. coverageDirectory: options.coverageDirectory,
  182. coverageProvider: options.coverageProvider,
  183. coverageReporters: options.coverageReporters,
  184. coverageThreshold: options.coverageThreshold,
  185. detectLeaks: options.detectLeaks,
  186. detectOpenHandles: options.detectOpenHandles,
  187. errorOnDeprecated: options.errorOnDeprecated,
  188. expand: options.expand,
  189. filter: options.filter,
  190. findRelatedTests: options.findRelatedTests,
  191. forceExit: options.forceExit,
  192. globalSetup: options.globalSetup,
  193. globalTeardown: options.globalTeardown,
  194. json: options.json,
  195. lastCommit: options.lastCommit,
  196. listTests: options.listTests,
  197. logHeapUsage: options.logHeapUsage,
  198. maxConcurrency: options.maxConcurrency,
  199. maxWorkers: options.maxWorkers,
  200. noSCM: undefined,
  201. noStackTrace: options.noStackTrace,
  202. nonFlagArgs: options.nonFlagArgs,
  203. notify: options.notify,
  204. notifyMode: options.notifyMode,
  205. onlyChanged: options.onlyChanged,
  206. onlyFailures: options.onlyFailures,
  207. openHandlesTimeout: options.openHandlesTimeout,
  208. outputFile: options.outputFile,
  209. passWithNoTests: options.passWithNoTests,
  210. projects: options.projects,
  211. randomize: options.randomize,
  212. replname: options.replname,
  213. reporters: options.reporters,
  214. rootDir: options.rootDir,
  215. runInBand: options.runInBand,
  216. runTestsByPath: options.runTestsByPath,
  217. seed: options.seed,
  218. shard: options.shard,
  219. showSeed: options.showSeed,
  220. silent: options.silent,
  221. skipFilter: options.skipFilter,
  222. snapshotFormat: options.snapshotFormat,
  223. testFailureExitCode: options.testFailureExitCode,
  224. testNamePattern: options.testNamePattern,
  225. testPathPattern: options.testPathPattern,
  226. testResultsProcessor: options.testResultsProcessor,
  227. testSequencer: options.testSequencer,
  228. testTimeout: options.testTimeout,
  229. updateSnapshot: options.updateSnapshot,
  230. useStderr: options.useStderr,
  231. verbose: options.verbose,
  232. watch: options.watch,
  233. watchAll: options.watchAll,
  234. watchPlugins: options.watchPlugins,
  235. watchman: options.watchman,
  236. workerIdleMemoryLimit: options.workerIdleMemoryLimit,
  237. workerThreads: options.workerThreads
  238. }),
  239. projectConfig: Object.freeze({
  240. automock: options.automock,
  241. cache: options.cache,
  242. cacheDirectory: options.cacheDirectory,
  243. clearMocks: options.clearMocks,
  244. collectCoverageFrom: options.collectCoverageFrom,
  245. coverageDirectory: options.coverageDirectory,
  246. coveragePathIgnorePatterns: options.coveragePathIgnorePatterns,
  247. cwd: options.cwd,
  248. dependencyExtractor: options.dependencyExtractor,
  249. detectLeaks: options.detectLeaks,
  250. detectOpenHandles: options.detectOpenHandles,
  251. displayName: options.displayName,
  252. errorOnDeprecated: options.errorOnDeprecated,
  253. extensionsToTreatAsEsm: options.extensionsToTreatAsEsm,
  254. fakeTimers: options.fakeTimers,
  255. filter: options.filter,
  256. forceCoverageMatch: options.forceCoverageMatch,
  257. globalSetup: options.globalSetup,
  258. globalTeardown: options.globalTeardown,
  259. globals: options.globals,
  260. haste: options.haste,
  261. id: options.id,
  262. injectGlobals: options.injectGlobals,
  263. moduleDirectories: options.moduleDirectories,
  264. moduleFileExtensions: options.moduleFileExtensions,
  265. moduleNameMapper: options.moduleNameMapper,
  266. modulePathIgnorePatterns: options.modulePathIgnorePatterns,
  267. modulePaths: options.modulePaths,
  268. openHandlesTimeout: options.openHandlesTimeout,
  269. prettierPath: options.prettierPath,
  270. resetMocks: options.resetMocks,
  271. resetModules: options.resetModules,
  272. resolver: options.resolver,
  273. restoreMocks: options.restoreMocks,
  274. rootDir: options.rootDir,
  275. roots: options.roots,
  276. runner: options.runner,
  277. runtime: options.runtime,
  278. sandboxInjectedGlobals: options.sandboxInjectedGlobals,
  279. setupFiles: options.setupFiles,
  280. setupFilesAfterEnv: options.setupFilesAfterEnv,
  281. skipFilter: options.skipFilter,
  282. skipNodeResolution: options.skipNodeResolution,
  283. slowTestThreshold: options.slowTestThreshold,
  284. snapshotFormat: options.snapshotFormat,
  285. snapshotResolver: options.snapshotResolver,
  286. snapshotSerializers: options.snapshotSerializers,
  287. testEnvironment: options.testEnvironment,
  288. testEnvironmentOptions: options.testEnvironmentOptions,
  289. testLocationInResults: options.testLocationInResults,
  290. testMatch: options.testMatch,
  291. testPathIgnorePatterns: options.testPathIgnorePatterns,
  292. testRegex: options.testRegex,
  293. testRunner: options.testRunner,
  294. transform: options.transform,
  295. transformIgnorePatterns: options.transformIgnorePatterns,
  296. unmockedModulePathPatterns: options.unmockedModulePathPatterns,
  297. watchPathIgnorePatterns: options.watchPathIgnorePatterns
  298. })
  299. });
  300. const ensureNoDuplicateConfigs = (parsedConfigs, projects) => {
  301. if (projects.length <= 1) {
  302. return;
  303. }
  304. const configPathMap = new Map();
  305. for (const config of parsedConfigs) {
  306. const {configPath} = config;
  307. if (configPathMap.has(configPath)) {
  308. const message = `Whoops! Two projects resolved to the same config path: ${_chalk().default.bold(
  309. String(configPath)
  310. )}:
  311. Project 1: ${_chalk().default.bold(
  312. projects[parsedConfigs.findIndex(x => x === config)]
  313. )}
  314. Project 2: ${_chalk().default.bold(
  315. projects[parsedConfigs.findIndex(x => x === configPathMap.get(configPath))]
  316. )}
  317. This usually means that your ${_chalk().default.bold(
  318. '"projects"'
  319. )} config includes a directory that doesn't have any configuration recognizable by Jest. Please fix it.
  320. `;
  321. throw new Error(message);
  322. }
  323. if (configPath !== null) {
  324. configPathMap.set(configPath, config);
  325. }
  326. }
  327. };
  328. /**
  329. * Reads the jest config, without validating them or filling it out with defaults.
  330. * @param config The path to the file or serialized config.
  331. * @param param1 Additional options
  332. * @returns The raw initial config (not validated)
  333. */
  334. async function readInitialOptions(
  335. config,
  336. {
  337. packageRootOrConfig = process.cwd(),
  338. parentConfigDirname = null,
  339. readFromCwd = false,
  340. skipMultipleConfigError = false
  341. } = {}
  342. ) {
  343. if (typeof packageRootOrConfig !== 'string') {
  344. if (parentConfigDirname) {
  345. const rawOptions = packageRootOrConfig;
  346. rawOptions.rootDir = rawOptions.rootDir
  347. ? (0, _utils.replaceRootDirInPath)(
  348. parentConfigDirname,
  349. rawOptions.rootDir
  350. )
  351. : parentConfigDirname;
  352. return {
  353. config: rawOptions,
  354. configPath: null
  355. };
  356. } else {
  357. throw new Error(
  358. 'Jest: Cannot use configuration as an object without a file path.'
  359. );
  360. }
  361. }
  362. if ((0, _utils.isJSONString)(config)) {
  363. try {
  364. // A JSON string was passed to `--config` argument and we can parse it
  365. // and use as is.
  366. const initialOptions = JSON.parse(config);
  367. // NOTE: we might need to resolve this dir to an absolute path in the future
  368. initialOptions.rootDir = initialOptions.rootDir || packageRootOrConfig;
  369. return {
  370. config: initialOptions,
  371. configPath: null
  372. };
  373. } catch {
  374. throw new Error(
  375. 'There was an error while parsing the `--config` argument as a JSON string.'
  376. );
  377. }
  378. }
  379. if (!readFromCwd && typeof config == 'string') {
  380. // A string passed to `--config`, which is either a direct path to the config
  381. // or a path to directory containing `package.json`, `jest.config.js` or `jest.config.ts`
  382. const configPath = (0, _resolveConfigPath.default)(
  383. config,
  384. process.cwd(),
  385. skipMultipleConfigError
  386. );
  387. return {
  388. config: await (0, _readConfigFileAndSetRootDir.default)(configPath),
  389. configPath
  390. };
  391. }
  392. // Otherwise just try to find config in the current rootDir.
  393. const configPath = (0, _resolveConfigPath.default)(
  394. packageRootOrConfig,
  395. process.cwd(),
  396. skipMultipleConfigError
  397. );
  398. return {
  399. config: await (0, _readConfigFileAndSetRootDir.default)(configPath),
  400. configPath
  401. };
  402. }
  403. // Possible scenarios:
  404. // 1. jest --config config.json
  405. // 2. jest --projects p1 p2
  406. // 3. jest --projects p1 p2 --config config.json
  407. // 4. jest --projects p1
  408. // 5. jest
  409. //
  410. // If no projects are specified, process.cwd() will be used as the default
  411. // (and only) project.
  412. async function readConfigs(argv, projectPaths) {
  413. let globalConfig;
  414. let hasDeprecationWarnings;
  415. let configs = [];
  416. let projects = projectPaths;
  417. let configPath;
  418. if (projectPaths.length === 1) {
  419. const parsedConfig = await readConfig(argv, projects[0]);
  420. configPath = parsedConfig.configPath;
  421. hasDeprecationWarnings = parsedConfig.hasDeprecationWarnings;
  422. globalConfig = parsedConfig.globalConfig;
  423. configs = [parsedConfig.projectConfig];
  424. if (globalConfig.projects && globalConfig.projects.length) {
  425. // Even though we had one project in CLI args, there might be more
  426. // projects defined in the config.
  427. // In other words, if this was a single project,
  428. // and its config has `projects` settings, use that value instead.
  429. projects = globalConfig.projects;
  430. }
  431. }
  432. if (projects.length > 0) {
  433. const cwd =
  434. process.platform === 'win32'
  435. ? (0, _jestUtil().tryRealpath)(process.cwd())
  436. : process.cwd();
  437. const projectIsCwd = projects[0] === cwd;
  438. const parsedConfigs = await Promise.all(
  439. projects
  440. .filter(root => {
  441. // Ignore globbed files that cannot be `require`d.
  442. if (
  443. typeof root === 'string' &&
  444. fs().existsSync(root) &&
  445. !fs().lstatSync(root).isDirectory() &&
  446. !constants.JEST_CONFIG_EXT_ORDER.some(ext => root.endsWith(ext))
  447. ) {
  448. return false;
  449. }
  450. return true;
  451. })
  452. .map((root, projectIndex) => {
  453. const projectIsTheOnlyProject =
  454. projectIndex === 0 && projects.length === 1;
  455. const skipArgvConfigOption = !(
  456. projectIsTheOnlyProject && projectIsCwd
  457. );
  458. return readConfig(
  459. argv,
  460. root,
  461. skipArgvConfigOption,
  462. configPath ? path().dirname(configPath) : cwd,
  463. projectIndex,
  464. // we wanna skip the warning if this is the "main" project
  465. projectIsCwd
  466. );
  467. })
  468. );
  469. ensureNoDuplicateConfigs(parsedConfigs, projects);
  470. configs = parsedConfigs.map(({projectConfig}) => projectConfig);
  471. if (!hasDeprecationWarnings) {
  472. hasDeprecationWarnings = parsedConfigs.some(
  473. ({hasDeprecationWarnings}) => !!hasDeprecationWarnings
  474. );
  475. }
  476. // If no config was passed initially, use the one from the first project
  477. if (!globalConfig) {
  478. globalConfig = parsedConfigs[0].globalConfig;
  479. }
  480. }
  481. if (!globalConfig || !configs.length) {
  482. throw new Error('jest: No configuration found for any project.');
  483. }
  484. return {
  485. configs,
  486. globalConfig,
  487. hasDeprecationWarnings: !!hasDeprecationWarnings
  488. };
  489. }