You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1372 lines
37 KiB

'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = normalize;
function _crypto() {
const data = require('crypto');
_crypto = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require('path'));
path = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require('chalk'));
_chalk = function () {
return data;
};
return data;
}
function _deepmerge() {
const data = _interopRequireDefault(require('deepmerge'));
_deepmerge = function () {
return data;
};
return data;
}
function _glob() {
const data = require('glob');
_glob = function () {
return data;
};
return data;
}
function _gracefulFs() {
const data = require('graceful-fs');
_gracefulFs = function () {
return data;
};
return data;
}
function _micromatch() {
const data = _interopRequireDefault(require('micromatch'));
_micromatch = function () {
return data;
};
return data;
}
function _jestRegexUtil() {
const data = require('jest-regex-util');
_jestRegexUtil = function () {
return data;
};
return data;
}
function _jestResolve() {
const data = _interopRequireWildcard(require('jest-resolve'));
_jestResolve = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require('jest-util');
_jestUtil = function () {
return data;
};
return data;
}
function _jestValidate() {
const data = require('jest-validate');
_jestValidate = function () {
return data;
};
return data;
}
var _Defaults = _interopRequireDefault(require('./Defaults'));
var _Deprecated = _interopRequireDefault(require('./Deprecated'));
var _ReporterValidationErrors = require('./ReporterValidationErrors');
var _ValidConfig = _interopRequireDefault(require('./ValidConfig'));
var _color = require('./color');
var _constants = require('./constants');
var _getMaxWorkers = _interopRequireDefault(require('./getMaxWorkers'));
var _setFromArgv = _interopRequireDefault(require('./setFromArgv'));
var _utils = require('./utils');
var _validatePattern = _interopRequireDefault(require('./validatePattern'));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== 'function') return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function (nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interopRequireWildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
return {default: obj};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor =
Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var key in obj) {
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor
? Object.getOwnPropertyDescriptor(obj, key)
: null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const ERROR = `${_utils.BULLET}Validation Error`;
const PRESET_EXTENSIONS = ['.json', '.js', '.cjs', '.mjs'];
const PRESET_NAME = 'jest-preset';
const createConfigError = message =>
new (_jestValidate().ValidationError)(
ERROR,
message,
_utils.DOCUMENTATION_NOTE
);
function verifyDirectoryExists(path, key) {
try {
const rootStat = (0, _gracefulFs().statSync)(path);
if (!rootStat.isDirectory()) {
throw createConfigError(
` ${_chalk().default.bold(path)} in the ${_chalk().default.bold(
key
)} option is not a directory.`
);
}
} catch (err) {
if (err instanceof _jestValidate().ValidationError) {
throw err;
}
if (err.code === 'ENOENT') {
throw createConfigError(
` Directory ${_chalk().default.bold(
path
)} in the ${_chalk().default.bold(key)} option was not found.`
);
} // Not sure in which cases `statSync` can throw, so let's just show the underlying error to the user
throw createConfigError(
` Got an error trying to find ${_chalk().default.bold(
path
)} in the ${_chalk().default.bold(key)} option.\n\n Error was: ${
err.message
}`
);
}
} // TS 3.5 forces us to split these into 2
const mergeModuleNameMapperWithPreset = (options, preset) => {
if (options['moduleNameMapper'] && preset['moduleNameMapper']) {
options['moduleNameMapper'] = {
...options['moduleNameMapper'],
...preset['moduleNameMapper'],
...options['moduleNameMapper']
};
}
};
const mergeTransformWithPreset = (options, preset) => {
if (options['transform'] && preset['transform']) {
options['transform'] = {
...options['transform'],
...preset['transform'],
...options['transform']
};
}
};
const mergeGlobalsWithPreset = (options, preset) => {
if (options['globals'] && preset['globals']) {
options['globals'] = (0, _deepmerge().default)(
preset['globals'],
options['globals']
);
}
};
const setupPreset = async (options, optionsPreset) => {
let preset;
const presetPath = (0, _utils.replaceRootDirInPath)(
options.rootDir,
optionsPreset
);
const presetModule = _jestResolve().default.findNodeModule(
presetPath.startsWith('.')
? presetPath
: path().join(presetPath, PRESET_NAME),
{
basedir: options.rootDir,
extensions: PRESET_EXTENSIONS
}
);
try {
if (!presetModule) {
throw new Error(`Cannot find module '${presetPath}'`);
} // Force re-evaluation to support multiple projects
try {
delete require.cache[require.resolve(presetModule)];
} catch {}
preset = await (0, _jestUtil().requireOrImportModule)(presetModule);
} catch (error) {
if (error instanceof SyntaxError || error instanceof TypeError) {
throw createConfigError(
` Preset ${_chalk().default.bold(presetPath)} is invalid:\n\n ${
error.message
}\n ${error.stack}`
);
}
if (error.message.includes('Cannot find module')) {
if (error.message.includes(presetPath)) {
const preset = _jestResolve().default.findNodeModule(presetPath, {
basedir: options.rootDir
});
if (preset) {
throw createConfigError(
` Module ${_chalk().default.bold(
presetPath
)} should have "jest-preset.js" or "jest-preset.json" file at the root.`
);
}
throw createConfigError(
` Preset ${_chalk().default.bold(presetPath)} not found.`
);
}
throw createConfigError(
` Missing dependency in ${_chalk().default.bold(presetPath)}:\n\n ${
error.message
}\n ${error.stack}`
);
}
throw createConfigError(
` An unknown error occurred in ${_chalk().default.bold(
presetPath
)}:\n\n ${error.message}\n ${error.stack}`
);
}
if (options.setupFiles) {
options.setupFiles = (preset.setupFiles || []).concat(options.setupFiles);
}
if (options.setupFilesAfterEnv) {
options.setupFilesAfterEnv = (preset.setupFilesAfterEnv || []).concat(
options.setupFilesAfterEnv
);
}
if (options.modulePathIgnorePatterns && preset.modulePathIgnorePatterns) {
options.modulePathIgnorePatterns = preset.modulePathIgnorePatterns.concat(
options.modulePathIgnorePatterns
);
}
mergeModuleNameMapperWithPreset(options, preset);
mergeTransformWithPreset(options, preset);
mergeGlobalsWithPreset(options, preset);
return {...preset, ...options};
};
const setupBabelJest = options => {
const transform = options.transform;
let babelJest;
if (transform) {
const customJSPattern = Object.keys(transform).find(pattern => {
const regex = new RegExp(pattern);
return regex.test('a.js') || regex.test('a.jsx');
});
const customTSPattern = Object.keys(transform).find(pattern => {
const regex = new RegExp(pattern);
return regex.test('a.ts') || regex.test('a.tsx');
});
[customJSPattern, customTSPattern].forEach(pattern => {
if (pattern) {
const customTransformer = transform[pattern];
if (Array.isArray(customTransformer)) {
if (customTransformer[0] === 'babel-jest') {
babelJest = require.resolve('babel-jest');
customTransformer[0] = babelJest;
} else if (customTransformer[0].includes('babel-jest')) {
babelJest = customTransformer[0];
}
} else {
if (customTransformer === 'babel-jest') {
babelJest = require.resolve('babel-jest');
transform[pattern] = babelJest;
} else if (customTransformer.includes('babel-jest')) {
babelJest = customTransformer;
}
}
}
});
} else {
babelJest = require.resolve('babel-jest');
options.transform = {
[_constants.DEFAULT_JS_PATTERN]: babelJest
};
}
};
const normalizeCollectCoverageOnlyFrom = (options, key) => {
const initialCollectCoverageFrom = options[key];
const collectCoverageOnlyFrom = Array.isArray(initialCollectCoverageFrom)
? initialCollectCoverageFrom // passed from argv
: Object.keys(initialCollectCoverageFrom); // passed from options
return collectCoverageOnlyFrom.reduce((map, filePath) => {
filePath = path().resolve(
options.rootDir,
(0, _utils.replaceRootDirInPath)(options.rootDir, filePath)
);
map[filePath] = true;
return map;
}, Object.create(null));
};
const normalizeCollectCoverageFrom = (options, key) => {
const initialCollectCoverageFrom = options[key];
let value;
if (!initialCollectCoverageFrom) {
value = [];
}
if (!Array.isArray(initialCollectCoverageFrom)) {
try {
value = JSON.parse(initialCollectCoverageFrom);
} catch {}
if (options[key] && !Array.isArray(value)) {
value = [initialCollectCoverageFrom];
}
} else {
value = initialCollectCoverageFrom;
}
if (value) {
value = value.map(filePath =>
filePath.replace(/^(!?)(<rootDir>\/)(.*)/, '$1$3')
);
}
return value;
};
const normalizeUnmockedModulePathPatterns = (
options,
key // _replaceRootDirTags is specifically well-suited for substituting
) =>
// <rootDir> in paths (it deals with properly interpreting relative path
// separators, etc).
//
// For patterns, direct global substitution is far more ideal, so we
// special case substitutions for patterns here.
options[key].map(pattern =>
(0, _jestRegexUtil().replacePathSepForRegex)(
pattern.replace(/<rootDir>/g, options.rootDir)
)
);
const normalizePreprocessor = options => {
if (options.scriptPreprocessor && options.transform) {
throw createConfigError(` Options: ${_chalk().default.bold(
'scriptPreprocessor'
)} and ${_chalk().default.bold('transform')} cannot be used together.
Please change your configuration to only use ${_chalk().default.bold(
'transform'
)}.`);
}
if (options.preprocessorIgnorePatterns && options.transformIgnorePatterns) {
throw createConfigError(` Options ${_chalk().default.bold(
'preprocessorIgnorePatterns'
)} and ${_chalk().default.bold(
'transformIgnorePatterns'
)} cannot be used together.
Please change your configuration to only use ${_chalk().default.bold(
'transformIgnorePatterns'
)}.`);
}
if (options.scriptPreprocessor) {
options.transform = {
'.*': options.scriptPreprocessor
};
}
if (options.preprocessorIgnorePatterns) {
options.transformIgnorePatterns = options.preprocessorIgnorePatterns;
}
delete options.scriptPreprocessor;
delete options.preprocessorIgnorePatterns;
return options;
};
const normalizeMissingOptions = (options, configPath, projectIndex) => {
if (!options.name) {
options.name = (0, _crypto().createHash)('md5')
.update(options.rootDir) // In case we load config from some path that has the same root dir
.update(configPath || '')
.update(String(projectIndex))
.digest('hex');
}
if (!options.setupFiles) {
options.setupFiles = [];
}
return options;
};
const normalizeRootDir = options => {
// Assert that there *is* a rootDir
if (!options.rootDir) {
throw createConfigError(
` Configuration option ${_chalk().default.bold(
'rootDir'
)} must be specified.`
);
}
options.rootDir = path().normalize(options.rootDir);
try {
// try to resolve windows short paths, ignoring errors (permission errors, mostly)
options.rootDir = (0, _jestUtil().tryRealpath)(options.rootDir);
} catch {
// ignored
}
verifyDirectoryExists(options.rootDir, 'rootDir');
return {...options, rootDir: options.rootDir};
};
const normalizeReporters = options => {
const reporters = options.reporters;
if (!reporters || !Array.isArray(reporters)) {
return options;
}
(0, _ReporterValidationErrors.validateReporters)(reporters);
options.reporters = reporters.map(reporterConfig => {
const normalizedReporterConfig =
typeof reporterConfig === 'string' // if reporter config is a string, we wrap it in an array
? // and pass an empty object for options argument, to normalize
// the shape.
[reporterConfig, {}]
: reporterConfig;
const reporterPath = (0, _utils.replaceRootDirInPath)(
options.rootDir,
normalizedReporterConfig[0]
);
if (reporterPath !== _constants.DEFAULT_REPORTER_LABEL) {
const reporter = _jestResolve().default.findNodeModule(reporterPath, {
basedir: options.rootDir
});
if (!reporter) {
throw new (_jestResolve().default.ModuleNotFoundError)(
'Could not resolve a module for a custom reporter.\n' +
` Module name: ${reporterPath}`
);
}
normalizedReporterConfig[0] = reporter;
}
return normalizedReporterConfig;
});
return options;
};
const buildTestPathPattern = argv => {
const patterns = [];
if (argv._) {
patterns.push(...argv._);
}
if (argv.testPathPattern) {
patterns.push(...argv.testPathPattern);
}
const replacePosixSep = pattern => {
// yargs coerces positional args into numbers
const patternAsString = pattern.toString();
if (path().sep === '/') {
return patternAsString;
}
return patternAsString.replace(/\//g, '\\\\');
};
const testPathPattern = patterns.map(replacePosixSep).join('|');
if ((0, _validatePattern.default)(testPathPattern)) {
return testPathPattern;
} else {
showTestPathPatternError(testPathPattern);
return '';
}
};
const showTestPathPatternError = testPathPattern => {
(0, _jestUtil().clearLine)(process.stdout); // eslint-disable-next-line no-console
console.log(
_chalk().default.red(
` Invalid testPattern ${testPathPattern} supplied. ` +
'Running all tests instead.'
)
);
};
function validateExtensionsToTreatAsEsm(extensionsToTreatAsEsm) {
if (!extensionsToTreatAsEsm || extensionsToTreatAsEsm.length === 0) {
return;
}
function printConfig(opts) {
const string = opts.map(ext => `'${ext}'`).join(', ');
return _chalk().default.bold(`extensionsToTreatAsEsm: [${string}]`);
}
const extensionWithoutDot = extensionsToTreatAsEsm.some(
ext => !ext.startsWith('.')
);
if (extensionWithoutDot) {
throw createConfigError(` Option: ${printConfig(
extensionsToTreatAsEsm
)} includes a string that does not start with a period (${_chalk().default.bold(
'.'
)}).
Please change your configuration to ${printConfig(
extensionsToTreatAsEsm.map(ext => (ext.startsWith('.') ? ext : `.${ext}`))
)}.`);
}
if (extensionsToTreatAsEsm.includes('.js')) {
throw createConfigError(
` Option: ${printConfig(
extensionsToTreatAsEsm
)} includes ${_chalk().default.bold(
"'.js'"
)} which is always inferred based on ${_chalk().default.bold(
'type'
)} in its nearest ${_chalk().default.bold('package.json')}.`
);
}
if (extensionsToTreatAsEsm.includes('.cjs')) {
throw createConfigError(
` Option: ${printConfig(
extensionsToTreatAsEsm
)} includes ${_chalk().default.bold(
"'.cjs'"
)} which is always treated as CommonJS.`
);
}
if (extensionsToTreatAsEsm.includes('.mjs')) {
throw createConfigError(
` Option: ${printConfig(
extensionsToTreatAsEsm
)} includes ${_chalk().default.bold(
"'.mjs'"
)} which is always treated as an ECMAScript Module.`
);
}
}
async function normalize(
initialOptions,
argv,
configPath,
projectIndex = Infinity
) {
var _options$haste, _argv$_;
const {hasDeprecationWarnings} = (0, _jestValidate().validate)(
initialOptions,
{
comment: _utils.DOCUMENTATION_NOTE,
deprecatedConfig: _Deprecated.default,
exampleConfig: _ValidConfig.default,
recursiveDenylist: [
'collectCoverageOnlyFrom', // 'coverageThreshold' allows to use 'global' and glob strings on the same
// level, there's currently no way we can deal with such config
'coverageThreshold',
'globals',
'moduleNameMapper',
'testEnvironmentOptions',
'transform'
]
}
);
let options = normalizePreprocessor(
normalizeReporters(
normalizeMissingOptions(
normalizeRootDir((0, _setFromArgv.default)(initialOptions, argv)),
configPath,
projectIndex
)
)
);
if (options.preset) {
options = await setupPreset(options, options.preset);
}
if (!options.setupFilesAfterEnv) {
options.setupFilesAfterEnv = [];
}
if (
options.setupTestFrameworkScriptFile &&
options.setupFilesAfterEnv.length > 0
) {
throw createConfigError(` Options: ${_chalk().default.bold(
'setupTestFrameworkScriptFile'
)} and ${_chalk().default.bold(
'setupFilesAfterEnv'
)} cannot be used together.
Please change your configuration to only use ${_chalk().default.bold(
'setupFilesAfterEnv'
)}.`);
}
if (options.setupTestFrameworkScriptFile) {
options.setupFilesAfterEnv.push(options.setupTestFrameworkScriptFile);
}
options.testEnvironment = (0, _jestResolve().resolveTestEnvironment)({
requireResolveFunction: require.resolve,
rootDir: options.rootDir,
testEnvironment:
options.testEnvironment ||
require.resolve(_Defaults.default.testEnvironment)
});
if (!options.roots && options.testPathDirs) {
options.roots = options.testPathDirs;
delete options.testPathDirs;
}
if (!options.roots) {
options.roots = [options.rootDir];
}
if (
!options.testRunner ||
options.testRunner === 'circus' ||
options.testRunner === 'jest-circus'
) {
options.testRunner = require.resolve('jest-circus/runner');
} else if (options.testRunner === 'jasmine2') {
options.testRunner = require.resolve('jest-jasmine2');
}
if (!options.coverageDirectory) {
options.coverageDirectory = path().resolve(options.rootDir, 'coverage');
}
setupBabelJest(options); // TODO: Type this properly
const newOptions = {..._Defaults.default};
if (options.resolver) {
newOptions.resolver = (0, _utils.resolve)(null, {
filePath: options.resolver,
key: 'resolver',
rootDir: options.rootDir
});
}
validateExtensionsToTreatAsEsm(options.extensionsToTreatAsEsm);
if (options.watchman == null) {
options.watchman = _Defaults.default.watchman;
}
const optionKeys = Object.keys(options);
optionKeys.reduce((newOptions, key) => {
// The resolver has been resolved separately; skip it
if (key === 'resolver') {
return newOptions;
} // This is cheating, because it claims that all keys of InitialOptions are Required.
// We only really know it's Required for oldOptions[key], not for oldOptions.someOtherKey,
// so oldOptions[key] is the only way it should be used.
const oldOptions = options;
let value;
switch (key) {
case 'collectCoverageOnlyFrom':
value = normalizeCollectCoverageOnlyFrom(oldOptions, key);
break;
case 'setupFiles':
case 'setupFilesAfterEnv':
case 'snapshotSerializers':
{
const option = oldOptions[key];
value =
option &&
option.map(filePath =>
(0, _utils.resolve)(newOptions.resolver, {
filePath,
key,
rootDir: options.rootDir
})
);
}
break;
case 'modulePaths':
case 'roots':
{
const option = oldOptions[key];
value =
option &&
option.map(filePath =>
path().resolve(
options.rootDir,
(0, _utils.replaceRootDirInPath)(options.rootDir, filePath)
)
);
}
break;
case 'collectCoverageFrom':
value = normalizeCollectCoverageFrom(oldOptions, key);
break;
case 'cacheDirectory':
case 'coverageDirectory':
{
const option = oldOptions[key];
value =
option &&
path().resolve(
options.rootDir,
(0, _utils.replaceRootDirInPath)(options.rootDir, option)
);
}
break;
case 'dependencyExtractor':
case 'globalSetup':
case 'globalTeardown':
case 'moduleLoader':
case 'snapshotResolver':
case 'testResultsProcessor':
case 'testRunner':
case 'filter':
{
const option = oldOptions[key];
value =
option &&
(0, _utils.resolve)(newOptions.resolver, {
filePath: option,
key,
rootDir: options.rootDir
});
}
break;
case 'runner':
{
const option = oldOptions[key];
value =
option &&
(0, _jestResolve().resolveRunner)(newOptions.resolver, {
filePath: option,
requireResolveFunction: require.resolve,
rootDir: options.rootDir
});
}
break;
case 'prettierPath':
{
// We only want this to throw if "prettierPath" is explicitly passed
// from config or CLI, and the requested path isn't found. Otherwise we
// set it to null and throw an error lazily when it is used.
const option = oldOptions[key];
value =
option &&
(0, _utils.resolve)(newOptions.resolver, {
filePath: option,
key,
optional: option === _Defaults.default[key],
rootDir: options.rootDir
});
}
break;
case 'moduleNameMapper':
const moduleNameMapper = oldOptions[key];
value =
moduleNameMapper &&
Object.keys(moduleNameMapper).map(regex => {
const item = moduleNameMapper && moduleNameMapper[regex];
return (
item && [
regex,
(0, _utils._replaceRootDirTags)(options.rootDir, item)
]
);
});
break;
case 'transform':
const transform = oldOptions[key];
value =
transform &&
Object.keys(transform).map(regex => {
const transformElement = transform[regex];
return [
regex,
(0, _utils.resolve)(newOptions.resolver, {
filePath: Array.isArray(transformElement)
? transformElement[0]
: transformElement,
key,
rootDir: options.rootDir
}),
Array.isArray(transformElement) ? transformElement[1] : {}
];
});
break;
case 'coveragePathIgnorePatterns':
case 'modulePathIgnorePatterns':
case 'testPathIgnorePatterns':
case 'transformIgnorePatterns':
case 'watchPathIgnorePatterns':
case 'unmockedModulePathPatterns':
value = normalizeUnmockedModulePathPatterns(oldOptions, key);
break;
case 'haste':
value = {...oldOptions[key]};
if (value.hasteImplModulePath != null) {
const resolvedHasteImpl = (0, _utils.resolve)(newOptions.resolver, {
filePath: (0, _utils.replaceRootDirInPath)(
options.rootDir,
value.hasteImplModulePath
),
key: 'haste.hasteImplModulePath',
rootDir: options.rootDir
});
value.hasteImplModulePath = resolvedHasteImpl || undefined;
}
break;
case 'projects':
value = (oldOptions[key] || [])
.map(project =>
typeof project === 'string'
? (0, _utils._replaceRootDirTags)(options.rootDir, project)
: project
)
.reduce((projects, project) => {
// Project can be specified as globs. If a glob matches any files,
// We expand it to these paths. If not, we keep the original path
// for the future resolution.
const globMatches =
typeof project === 'string' ? (0, _glob().sync)(project) : [];
return projects.concat(globMatches.length ? globMatches : project);
}, []);
break;
case 'moduleDirectories':
case 'testMatch':
{
const replacedRootDirTags = (0, _utils._replaceRootDirTags)(
(0, _utils.escapeGlobCharacters)(options.rootDir),
oldOptions[key]
);
if (replacedRootDirTags) {
value = Array.isArray(replacedRootDirTags)
? replacedRootDirTags.map(_jestUtil().replacePathSepForGlob)
: (0, _jestUtil().replacePathSepForGlob)(replacedRootDirTags);
} else {
value = replacedRootDirTags;
}
}
break;
case 'testRegex':
{
const option = oldOptions[key];
value = option
? (Array.isArray(option) ? option : [option]).map(
_jestRegexUtil().replacePathSepForRegex
)
: [];
}
break;
case 'moduleFileExtensions': {
value = oldOptions[key];
if (
Array.isArray(value) && // If it's the wrong type, it can throw at a later time
(options.runner === undefined ||
options.runner === _Defaults.default.runner) && // Only require 'js' for the default jest-runner
!value.includes('js')
) {
const errorMessage =
" moduleFileExtensions must include 'js':\n" +
' but instead received:\n' +
` ${_chalk().default.bold.red(JSON.stringify(value))}`; // If `js` is not included, any dependency Jest itself injects into
// the environment, like jasmine or sourcemap-support, will need to
// `require` its modules with a file extension. This is not plausible
// in the long run, so it's way easier to just fail hard early.
// We might consider throwing if `json` is missing as well, as it's a
// fair assumption from modules that they can do
// `require('some-package/package') without the trailing `.json` as it
// works in Node normally.
throw createConfigError(
errorMessage +
"\n Please change your configuration to include 'js'."
);
}
break;
}
case 'bail': {
const bail = oldOptions[key];
if (typeof bail === 'boolean') {
value = bail ? 1 : 0;
} else if (typeof bail === 'string') {
value = 1; // If Jest is invoked as `jest --bail someTestPattern` then need to
// move the pattern from the `bail` configuration and into `argv._`
// to be processed as an extra parameter
argv._.push(bail);
} else {
value = oldOptions[key];
}
break;
}
case 'displayName': {
const displayName = oldOptions[key];
/**
* Ensuring that displayName shape is correct here so that the
* reporters can trust the shape of the data
*/
if (typeof displayName === 'object') {
const {name, color} = displayName;
if (
!name ||
!color ||
typeof name !== 'string' ||
typeof color !== 'string'
) {
const errorMessage =
` Option "${_chalk().default.bold(
'displayName'
)}" must be of type:\n\n` +
' {\n' +
' name: string;\n' +
' color: string;\n' +
' }\n';
throw createConfigError(errorMessage);
}
value = oldOptions[key];
} else {
value = {
color: (0, _color.getDisplayNameColor)(options.runner),
name: displayName
};
}
break;
}
case 'testTimeout': {
if (oldOptions[key] < 0) {
throw createConfigError(
` Option "${_chalk().default.bold(
'testTimeout'
)}" must be a natural number.`
);
}
value = oldOptions[key];
break;
}
case 'automock':
case 'cache':
case 'changedSince':
case 'changedFilesWithAncestor':
case 'clearMocks':
case 'collectCoverage':
case 'coverageProvider':
case 'coverageReporters':
case 'coverageThreshold':
case 'detectLeaks':
case 'detectOpenHandles':
case 'errorOnDeprecated':
case 'expand':
case 'extensionsToTreatAsEsm':
case 'extraGlobals':
case 'globals':
case 'findRelatedTests':
case 'forceCoverageMatch':
case 'forceExit':
case 'injectGlobals':
case 'lastCommit':
case 'listTests':
case 'logHeapUsage':
case 'maxConcurrency':
case 'name':
case 'noStackTrace':
case 'notify':
case 'notifyMode':
case 'onlyChanged':
case 'onlyFailures':
case 'outputFile':
case 'passWithNoTests':
case 'replname':
case 'reporters':
case 'resetMocks':
case 'resetModules':
case 'restoreMocks':
case 'rootDir':
case 'runTestsByPath':
case 'silent':
case 'skipFilter':
case 'skipNodeResolution':
case 'slowTestThreshold':
case 'snapshotFormat':
case 'testEnvironment':
case 'testEnvironmentOptions':
case 'testFailureExitCode':
case 'testLocationInResults':
case 'testNamePattern':
case 'testURL':
case 'timers':
case 'useStderr':
case 'verbose':
case 'watch':
case 'watchAll':
case 'watchman':
value = oldOptions[key];
break;
case 'watchPlugins':
value = (oldOptions[key] || []).map(watchPlugin => {
if (typeof watchPlugin === 'string') {
return {
config: {},
path: (0, _jestResolve().resolveWatchPlugin)(
newOptions.resolver,
{
filePath: watchPlugin,
requireResolveFunction: require.resolve,
rootDir: options.rootDir
}
)
};
} else {
return {
config: watchPlugin[1] || {},
path: (0, _jestResolve().resolveWatchPlugin)(
newOptions.resolver,
{
filePath: watchPlugin[0],
requireResolveFunction: require.resolve,
rootDir: options.rootDir
}
)
};
}
});
break;
} // @ts-expect-error: automock is missing in GlobalConfig, so what
newOptions[key] = value;
return newOptions;
}, newOptions);
if (
options.watchman &&
(_options$haste = options.haste) !== null &&
_options$haste !== void 0 &&
_options$haste.enableSymlinks
) {
throw new (_jestValidate().ValidationError)(
'Validation Error',
'haste.enableSymlinks is incompatible with watchman',
'Either set haste.enableSymlinks to false or do not use watchman'
);
}
newOptions.roots.forEach((root, i) => {
verifyDirectoryExists(root, `roots[${i}]`);
});
try {
// try to resolve windows short paths, ignoring errors (permission errors, mostly)
newOptions.cwd = (0, _jestUtil().tryRealpath)(process.cwd());
} catch {
// ignored
}
newOptions.testSequencer = (0, _jestResolve().resolveSequencer)(
newOptions.resolver,
{
filePath:
options.testSequencer ||
require.resolve(_Defaults.default.testSequencer),
requireResolveFunction: require.resolve,
rootDir: options.rootDir
}
);
if (newOptions.runner === _Defaults.default.runner) {
newOptions.runner = require.resolve(newOptions.runner);
}
newOptions.nonFlagArgs =
(_argv$_ = argv._) === null || _argv$_ === void 0
? void 0
: _argv$_.map(arg => `${arg}`);
newOptions.testPathPattern = buildTestPathPattern(argv);
newOptions.json = !!argv.json;
newOptions.testFailureExitCode = parseInt(newOptions.testFailureExitCode, 10);
if (
newOptions.lastCommit ||
newOptions.changedFilesWithAncestor ||
newOptions.changedSince
) {
newOptions.onlyChanged = true;
}
if (argv.all) {
newOptions.onlyChanged = false;
newOptions.onlyFailures = false;
} else if (newOptions.testPathPattern) {
// When passing a test path pattern we don't want to only monitor changed
// files unless `--watch` is also passed.
newOptions.onlyChanged = newOptions.watch;
}
if (!newOptions.onlyChanged) {
newOptions.onlyChanged = false;
}
if (!newOptions.lastCommit) {
newOptions.lastCommit = false;
}
if (!newOptions.onlyFailures) {
newOptions.onlyFailures = false;
}
if (!newOptions.watchAll) {
newOptions.watchAll = false;
} // as unknown since it can happen. We really need to fix the types here
if (newOptions.moduleNameMapper === _Defaults.default.moduleNameMapper) {
newOptions.moduleNameMapper = [];
}
newOptions.updateSnapshot =
argv.ci && !argv.updateSnapshot
? 'none'
: argv.updateSnapshot
? 'all'
: 'new';
newOptions.maxConcurrency = parseInt(newOptions.maxConcurrency, 10);
newOptions.maxWorkers = (0, _getMaxWorkers.default)(argv, options);
if (newOptions.testRegex.length && options.testMatch) {
throw createConfigError(
` Configuration options ${_chalk().default.bold('testMatch')} and` +
` ${_chalk().default.bold('testRegex')} cannot be used together.`
);
}
if (newOptions.testRegex.length && !options.testMatch) {
// Prevent the default testMatch conflicting with any explicitly
// configured `testRegex` value
newOptions.testMatch = [];
} // If argv.json is set, coverageReporters shouldn't print a text report.
if (argv.json) {
newOptions.coverageReporters = (newOptions.coverageReporters || []).filter(
reporter => reporter !== 'text'
);
} // If collectCoverage is enabled while using --findRelatedTests we need to
// avoid having false negatives in the generated coverage report.
// The following: `--findRelatedTests '/rootDir/file1.js' --coverage`
// Is transformed to: `--findRelatedTests '/rootDir/file1.js' --coverage --collectCoverageFrom 'file1.js'`
// where arguments to `--collectCoverageFrom` should be globs (or relative
// paths to the rootDir)
if (newOptions.collectCoverage && argv.findRelatedTests) {
let collectCoverageFrom = newOptions.nonFlagArgs.map(filename => {
filename = (0, _utils.replaceRootDirInPath)(options.rootDir, filename);
return path().isAbsolute(filename)
? path().relative(options.rootDir, filename)
: filename;
}); // Don't override existing collectCoverageFrom options
if (newOptions.collectCoverageFrom) {
collectCoverageFrom = collectCoverageFrom.reduce((patterns, filename) => {
if (
(0, _micromatch().default)(
[
(0, _jestUtil().replacePathSepForGlob)(
path().relative(options.rootDir, filename)
)
],
newOptions.collectCoverageFrom
).length === 0
) {
return patterns;
}
return [...patterns, filename];
}, newOptions.collectCoverageFrom);
}
newOptions.collectCoverageFrom = collectCoverageFrom;
} else if (!newOptions.collectCoverageFrom) {
newOptions.collectCoverageFrom = [];
}
if (!newOptions.findRelatedTests) {
newOptions.findRelatedTests = false;
}
if (!newOptions.projects) {
newOptions.projects = [];
}
if (!newOptions.extraGlobals) {
newOptions.extraGlobals = [];
}
if (!newOptions.forceExit) {
newOptions.forceExit = false;
}
if (!newOptions.logHeapUsage) {
newOptions.logHeapUsage = false;
}
return {
hasDeprecationWarnings,
options: newOptions
};
}