Created
November 29, 2020 01:28
-
-
Save milesj/5fa74043d405c56826750bbe3721b932 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
function nativeModule() { | |
const data = _interopRequireWildcard(require('module')); | |
nativeModule = function () { | |
return data; | |
}; | |
return data; | |
} | |
function path() { | |
const data = _interopRequireWildcard(require('path')); | |
path = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _url() { | |
const data = require('url'); | |
_url = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _vm() { | |
const data = require('vm'); | |
_vm = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _cjsModuleLexer() { | |
const data = require('cjs-module-lexer'); | |
_cjsModuleLexer = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _collectV8Coverage() { | |
const data = require('collect-v8-coverage'); | |
_collectV8Coverage = function () { | |
return data; | |
}; | |
return data; | |
} | |
function fs() { | |
const data = _interopRequireWildcard(require('graceful-fs')); | |
fs = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _stripBom() { | |
const data = _interopRequireDefault(require('strip-bom')); | |
_stripBom = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _fakeTimers() { | |
const data = require('@jest/fake-timers'); | |
_fakeTimers = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _transform() { | |
const data = require('@jest/transform'); | |
_transform = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _jestHasteMap() { | |
const data = _interopRequireDefault(require('jest-haste-map')); | |
_jestHasteMap = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _jestMessageUtil() { | |
const data = require('jest-message-util'); | |
_jestMessageUtil = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _jestMock() { | |
const data = _interopRequireDefault(require('jest-mock')); | |
_jestMock = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _jestRegexUtil() { | |
const data = require('jest-regex-util'); | |
_jestRegexUtil = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _jestResolve() { | |
const data = _interopRequireDefault(require('jest-resolve')); | |
_jestResolve = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _jestSnapshot() { | |
const data = _interopRequireDefault(require('jest-snapshot')); | |
_jestSnapshot = function () { | |
return data; | |
}; | |
return data; | |
} | |
function _jestUtil() { | |
const data = require('jest-util'); | |
_jestUtil = function () { | |
return data; | |
}; | |
return data; | |
} | |
var _cli = require('./cli'); | |
var _args = require('./cli/args'); | |
var _helpers = require('./helpers'); | |
var _Object$fromEntries; | |
function _interopRequireDefault(obj) { | |
return obj && obj.__esModule ? obj : {default: obj}; | |
} | |
function _getRequireWildcardCache() { | |
if (typeof WeakMap !== 'function') return null; | |
var cache = new WeakMap(); | |
_getRequireWildcardCache = function () { | |
return cache; | |
}; | |
return cache; | |
} | |
function _interopRequireWildcard(obj) { | |
if (obj && obj.__esModule) { | |
return obj; | |
} | |
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) { | |
return {default: obj}; | |
} | |
var cache = _getRequireWildcardCache(); | |
if (cache && cache.has(obj)) { | |
return cache.get(obj); | |
} | |
var newObj = {}; | |
var hasPropertyDescriptor = | |
Object.defineProperty && Object.getOwnPropertyDescriptor; | |
for (var key in obj) { | |
if (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; | |
} | |
function _defineProperty(obj, key, value) { | |
if (key in obj) { | |
Object.defineProperty(obj, key, { | |
value: value, | |
enumerable: true, | |
configurable: true, | |
writable: true | |
}); | |
} else { | |
obj[key] = value; | |
} | |
return obj; | |
} | |
const esmIsAvailable = typeof _vm().SourceTextModule === 'function'; | |
const defaultTransformOptions = { | |
isInternalModule: false, | |
supportsDynamicImport: esmIsAvailable, | |
supportsExportNamespaceFrom: false, | |
supportsStaticESM: false, | |
supportsTopLevelAwait: false | |
}; | |
const OUTSIDE_JEST_VM_RESOLVE_OPTION = Symbol.for( | |
'OUTSIDE_JEST_VM_RESOLVE_OPTION' | |
); | |
const fromEntries = | |
(_Object$fromEntries = Object.fromEntries) !== null && | |
_Object$fromEntries !== void 0 | |
? _Object$fromEntries | |
: function fromEntries(iterable) { | |
return [...iterable].reduce((obj, [key, val]) => { | |
obj[key] = val; | |
return obj; | |
}, {}); | |
}; | |
const testTimeoutSymbol = Symbol.for('TEST_TIMEOUT_SYMBOL'); | |
const retryTimesSymbol = Symbol.for('RETRY_TIMES'); | |
const NODE_MODULES = path().sep + 'node_modules' + path().sep; | |
const getModuleNameMapper = config => { | |
if ( | |
Array.isArray(config.moduleNameMapper) && | |
config.moduleNameMapper.length | |
) { | |
return config.moduleNameMapper.map(([regex, moduleName]) => ({ | |
moduleName, | |
regex: new RegExp(regex) | |
})); | |
} | |
return null; | |
}; | |
const unmockRegExpCache = new WeakMap(); | |
const EVAL_RESULT_VARIABLE = 'Object.<anonymous>'; | |
const runtimeSupportsVmModules = typeof _vm().SyntheticModule === 'function'; | |
const supportsTopLevelAwait = | |
runtimeSupportsVmModules && | |
(() => { | |
try { | |
// eslint-disable-next-line no-new | |
new (_vm().SourceTextModule)('await Promise.resolve()'); | |
return true; | |
} catch { | |
return false; | |
} | |
})(); | |
class Runtime { | |
constructor( | |
config, | |
environment, | |
resolver, | |
cacheFS = {}, | |
coverageOptions, // TODO: Make mandatory in Jest 27 | |
testPath | |
) { | |
_defineProperty(this, '_cacheFS', void 0); | |
_defineProperty(this, '_config', void 0); | |
_defineProperty(this, '_coverageOptions', void 0); | |
_defineProperty(this, '_currentlyExecutingModulePath', void 0); | |
_defineProperty(this, '_environment', void 0); | |
_defineProperty(this, '_explicitShouldMock', void 0); | |
_defineProperty(this, '_fakeTimersImplementation', void 0); | |
_defineProperty(this, '_internalModuleRegistry', void 0); | |
_defineProperty(this, '_isCurrentlyExecutingManualMock', void 0); | |
_defineProperty(this, '_mainModule', void 0); | |
_defineProperty(this, '_mockFactories', void 0); | |
_defineProperty(this, '_mockMetaDataCache', void 0); | |
_defineProperty(this, '_mockRegistry', void 0); | |
_defineProperty(this, '_isolatedMockRegistry', void 0); | |
_defineProperty(this, '_moduleMocker', void 0); | |
_defineProperty(this, '_isolatedModuleRegistry', void 0); | |
_defineProperty(this, '_moduleRegistry', void 0); | |
_defineProperty(this, '_esmoduleRegistry', void 0); | |
_defineProperty(this, '_testPath', void 0); | |
_defineProperty(this, '_resolver', void 0); | |
_defineProperty(this, '_shouldAutoMock', void 0); | |
_defineProperty(this, '_shouldMockModuleCache', void 0); | |
_defineProperty(this, '_shouldUnmockTransitiveDependenciesCache', void 0); | |
_defineProperty(this, '_sourceMapRegistry', void 0); | |
_defineProperty(this, '_scriptTransformer', void 0); | |
_defineProperty(this, '_fileTransforms', void 0); | |
_defineProperty(this, '_v8CoverageInstrumenter', void 0); | |
_defineProperty(this, '_v8CoverageResult', void 0); | |
_defineProperty(this, '_transitiveShouldMock', void 0); | |
_defineProperty(this, '_unmockList', void 0); | |
_defineProperty(this, '_virtualMocks', void 0); | |
_defineProperty(this, '_moduleImplementation', void 0); | |
_defineProperty(this, 'jestObjectCaches', void 0); | |
_defineProperty(this, 'jestGlobals', void 0); | |
_defineProperty( | |
this, | |
'unstable_shouldLoadAsEsm', | |
_jestResolve().default.unstable_shouldLoadAsEsm | |
); | |
this._cacheFS = new Map(Object.entries(cacheFS)); | |
this._config = config; | |
this._coverageOptions = coverageOptions || { | |
changedFiles: undefined, | |
collectCoverage: false, | |
collectCoverageFrom: [], | |
collectCoverageOnlyFrom: undefined, | |
coverageProvider: 'babel', | |
sourcesRelatedToTestsInChangedFiles: undefined | |
}; | |
this._currentlyExecutingModulePath = ''; | |
this._environment = environment; | |
this._explicitShouldMock = new Map(); | |
this._internalModuleRegistry = new Map(); | |
this._isCurrentlyExecutingManualMock = null; | |
this._mainModule = null; | |
this._mockFactories = new Map(); | |
this._mockRegistry = new Map(); // during setup, this cannot be null (and it's fine to explode if it is) | |
this._moduleMocker = this._environment.moduleMocker; | |
this._isolatedModuleRegistry = null; | |
this._isolatedMockRegistry = null; | |
this._moduleRegistry = new Map(); | |
this._esmoduleRegistry = new Map(); | |
this._testPath = testPath; | |
this._resolver = resolver; | |
this._scriptTransformer = new (_transform().ScriptTransformer)(config); | |
this._shouldAutoMock = config.automock; | |
this._sourceMapRegistry = new Map(); | |
this._fileTransforms = new Map(); | |
this._virtualMocks = new Map(); | |
this.jestObjectCaches = new Map(); | |
this._mockMetaDataCache = new Map(); | |
this._shouldMockModuleCache = new Map(); | |
this._shouldUnmockTransitiveDependenciesCache = new Map(); | |
this._transitiveShouldMock = new Map(); | |
this._fakeTimersImplementation = | |
config.timers === 'modern' | |
? this._environment.fakeTimersModern | |
: this._environment.fakeTimers; | |
this._unmockList = unmockRegExpCache.get(config); | |
if (!this._unmockList && config.unmockedModulePathPatterns) { | |
this._unmockList = new RegExp( | |
config.unmockedModulePathPatterns.join('|') | |
); | |
unmockRegExpCache.set(config, this._unmockList); | |
} | |
if (config.automock) { | |
const virtualMocks = fromEntries(this._virtualMocks); | |
config.setupFiles.forEach(filePath => { | |
if (filePath && filePath.includes(NODE_MODULES)) { | |
const moduleID = this._resolver.getModuleID(virtualMocks, filePath); | |
this._transitiveShouldMock.set(moduleID, false); | |
} | |
}); | |
} | |
this.resetModules(); | |
} | |
static createContext(config, options) { | |
(0, _jestUtil().createDirectory)(config.cacheDirectory); | |
const instance = Runtime.createHasteMap(config, { | |
console: options.console, | |
maxWorkers: options.maxWorkers, | |
resetCache: !config.cache, | |
watch: options.watch, | |
watchman: options.watchman | |
}); | |
return instance.build().then( | |
hasteMap => ({ | |
config, | |
hasteFS: hasteMap.hasteFS, | |
moduleMap: hasteMap.moduleMap, | |
resolver: Runtime.createResolver(config, hasteMap.moduleMap) | |
}), | |
error => { | |
throw error; | |
} | |
); | |
} | |
static createHasteMap(config, options) { | |
const ignorePatternParts = [ | |
...config.modulePathIgnorePatterns, | |
...(options && options.watch ? config.watchPathIgnorePatterns : []), | |
config.cacheDirectory.startsWith(config.rootDir + path().sep) && | |
config.cacheDirectory | |
].filter(Boolean); | |
const ignorePattern = | |
ignorePatternParts.length > 0 | |
? new RegExp(ignorePatternParts.join('|')) | |
: undefined; | |
return new (_jestHasteMap().default)({ | |
cacheDirectory: config.cacheDirectory, | |
computeSha1: config.haste.computeSha1, | |
console: options && options.console, | |
dependencyExtractor: config.dependencyExtractor, | |
extensions: [_jestSnapshot().default.EXTENSION].concat( | |
config.moduleFileExtensions | |
), | |
hasteImplModulePath: config.haste.hasteImplModulePath, | |
ignorePattern, | |
maxWorkers: (options && options.maxWorkers) || 1, | |
mocksPattern: (0, _jestRegexUtil().escapePathForRegex)( | |
path().sep + '__mocks__' + path().sep | |
), | |
name: config.name, | |
platforms: config.haste.platforms || ['ios', 'android'], | |
resetCache: options && options.resetCache, | |
retainAllFiles: false, | |
rootDir: config.rootDir, | |
roots: config.roots, | |
throwOnModuleCollision: config.haste.throwOnModuleCollision, | |
useWatchman: options && options.watchman, | |
watch: options && options.watch | |
}); | |
} | |
static createResolver(config, moduleMap) { | |
return new (_jestResolve().default)(moduleMap, { | |
defaultPlatform: config.haste.defaultPlatform, | |
extensions: config.moduleFileExtensions.map(extension => '.' + extension), | |
hasCoreModules: true, | |
moduleDirectories: config.moduleDirectories, | |
moduleNameMapper: getModuleNameMapper(config), | |
modulePaths: config.modulePaths, | |
platforms: config.haste.platforms, | |
resolver: config.resolver, | |
rootDir: config.rootDir | |
}); | |
} | |
static runCLI(args, info) { | |
return (0, _cli.run)(args, info); | |
} | |
static getCLIOptions() { | |
return _args.options; | |
} // unstable as it should be replaced by https://github.com/nodejs/modules/issues/393, and we don't want people to use it | |
async loadEsmModule(modulePath, query = '') { | |
const cacheKey = modulePath + query; | |
if (!this._esmoduleRegistry.has(cacheKey)) { | |
invariant( | |
typeof this._environment.getVmContext === 'function', | |
'ES Modules are only supported if your test environment has the `getVmContext` function' | |
); | |
const context = this._environment.getVmContext(); | |
invariant(context); | |
if (this._resolver.isCoreModule(modulePath)) { | |
const core = await this._importCoreModule(modulePath, context); | |
this._esmoduleRegistry.set(cacheKey, core); | |
return core; | |
} | |
const transformedCode = this.transformFile(modulePath, { | |
isInternalModule: false, | |
supportsDynamicImport: true, | |
supportsExportNamespaceFrom: true, | |
supportsStaticESM: true, | |
supportsTopLevelAwait | |
}); | |
const module = new (_vm().SourceTextModule)(transformedCode, { | |
context, | |
identifier: modulePath, | |
importModuleDynamically: (specifier, referencingModule) => | |
this.linkModules( | |
specifier, | |
referencingModule.identifier, | |
referencingModule.context | |
), | |
initializeImportMeta(meta) { | |
meta.url = (0, _url().pathToFileURL)(modulePath).href; | |
} | |
}); | |
this._esmoduleRegistry.set( | |
cacheKey, // we wanna put the linking promise in the cache so modules loaded in | |
// parallel can all await it. We then await it synchronously below, so | |
// we shouldn't get any unhandled rejections | |
module | |
.link((specifier, referencingModule) => | |
this.linkModules( | |
specifier, | |
referencingModule.identifier, | |
referencingModule.context | |
) | |
) | |
.then(() => module.evaluate()) | |
.then(() => module) | |
); | |
} | |
const module = this._esmoduleRegistry.get(cacheKey); | |
invariant(module); | |
return module; | |
} | |
linkModules(specifier, referencingIdentifier, context) { | |
if (specifier === '@jest/globals') { | |
const fromCache = this._esmoduleRegistry.get('@jest/globals'); | |
if (fromCache) { | |
return fromCache; | |
} | |
const globals = this.getGlobalsForEsm(referencingIdentifier, context); | |
this._esmoduleRegistry.set('@jest/globals', globals); | |
return globals; | |
} | |
if (specifier.startsWith('file://')) { | |
specifier = (0, _url().fileURLToPath)(specifier); | |
} | |
const [path, query] = specifier.split('?'); | |
const resolved = this._resolveModule(referencingIdentifier, path); | |
if ( | |
this._resolver.isCoreModule(resolved) || | |
this.unstable_shouldLoadAsEsm(resolved) | |
) { | |
return this.loadEsmModule(resolved, query); | |
} | |
return this.loadCjsAsEsm(referencingIdentifier, resolved, context); | |
} | |
async unstable_importModule(from, moduleName) { | |
invariant( | |
runtimeSupportsVmModules, | |
'You need to run with a version of node that supports ES Modules in the VM API.' | |
); | |
const [path, query] = (moduleName !== null && moduleName !== void 0 | |
? moduleName | |
: '' | |
).split('?'); | |
const modulePath = this._resolveModule(from, path); | |
return this.loadEsmModule(modulePath, query); | |
} | |
loadCjsAsEsm(from, modulePath, context) { | |
// CJS loaded via `import` should share cache with other CJS: https://github.com/nodejs/modules/issues/503 | |
const cjs = this.requireModuleOrMock(from, modulePath); | |
const transformedCode = this._fileTransforms.get(modulePath); | |
let cjsExports = []; | |
if (transformedCode) { | |
const {exports} = (0, _cjsModuleLexer().parse)(transformedCode.code); | |
cjsExports = exports.filter(exportName => { | |
// we don't wanna respect any exports _names_ default as a named export | |
if (exportName === 'default') { | |
return false; | |
} | |
return Object.hasOwnProperty.call(cjs, exportName); | |
}); | |
} | |
const module = new (_vm().SyntheticModule)( | |
[...cjsExports, 'default'], | |
function () { | |
cjsExports.forEach(exportName => { | |
// @ts-expect-error | |
this.setExport(exportName, cjs[exportName]); | |
}); // @ts-expect-error: TS doesn't know what `this` is | |
this.setExport('default', cjs); | |
}, | |
{ | |
context, | |
identifier: modulePath | |
} | |
); | |
return evaluateSyntheticModule(module); | |
} | |
requireModule(from, moduleName, options, isRequireActual) { | |
const moduleID = this._resolver.getModuleID( | |
fromEntries(this._virtualMocks), | |
from, | |
moduleName | |
); | |
let modulePath; // Some old tests rely on this mocking behavior. Ideally we'll change this | |
// to be more explicit. | |
const moduleResource = moduleName && this._resolver.getModule(moduleName); | |
const manualMock = | |
moduleName && this._resolver.getMockModule(from, moduleName); | |
if ( | |
!(options === null || options === void 0 | |
? void 0 | |
: options.isInternalModule) && | |
!isRequireActual && | |
!moduleResource && | |
manualMock && | |
manualMock !== this._isCurrentlyExecutingManualMock && | |
this._explicitShouldMock.get(moduleID) !== false | |
) { | |
modulePath = manualMock; | |
} | |
if (moduleName && this._resolver.isCoreModule(moduleName)) { | |
return this._requireCoreModule(moduleName); | |
} | |
if (!modulePath) { | |
modulePath = this._resolveModule(from, moduleName); | |
} | |
let moduleRegistry; | |
if ( | |
options === null || options === void 0 ? void 0 : options.isInternalModule | |
) { | |
moduleRegistry = this._internalModuleRegistry; | |
} else { | |
if ( | |
this._moduleRegistry.get(modulePath) || | |
!this._isolatedModuleRegistry | |
) { | |
moduleRegistry = this._moduleRegistry; | |
} else { | |
moduleRegistry = this._isolatedModuleRegistry; | |
} | |
} | |
const module = moduleRegistry.get(modulePath); | |
if (module) { | |
return module.exports; | |
} // We must register the pre-allocated module object first so that any | |
// circular dependencies that may arise while evaluating the module can | |
// be satisfied. | |
const localModule = { | |
children: [], | |
exports: {}, | |
filename: modulePath, | |
id: modulePath, | |
loaded: false, | |
path: path().dirname(modulePath) | |
}; | |
moduleRegistry.set(modulePath, localModule); | |
this._loadModule( | |
localModule, | |
from, | |
moduleName, | |
modulePath, | |
options, | |
moduleRegistry | |
); | |
return localModule.exports; | |
} | |
requireInternalModule(from, to) { | |
if (to) { | |
const outsideJestVmPath = (0, _helpers.decodePossibleOutsideJestVmPath)( | |
to | |
); | |
if (outsideJestVmPath) { | |
return require(outsideJestVmPath); | |
} | |
} | |
return this.requireModule(from, to, { | |
isInternalModule: true, | |
supportsDynamicImport: esmIsAvailable, | |
supportsExportNamespaceFrom: false, | |
supportsStaticESM: false, | |
supportsTopLevelAwait: false | |
}); | |
} | |
requireActual(from, moduleName) { | |
return this.requireModule(from, moduleName, undefined, true); | |
} | |
requireMock(from, moduleName) { | |
const moduleID = this._resolver.getModuleID( | |
fromEntries(this._virtualMocks), | |
from, | |
moduleName | |
); | |
if ( | |
this._isolatedMockRegistry && | |
this._isolatedMockRegistry.get(moduleID) | |
) { | |
return this._isolatedMockRegistry.get(moduleID); | |
} else if (this._mockRegistry.get(moduleID)) { | |
return this._mockRegistry.get(moduleID); | |
} | |
const mockRegistry = this._isolatedMockRegistry || this._mockRegistry; | |
if (this._mockFactories.has(moduleID)) { | |
// has check above makes this ok | |
const module = this._mockFactories.get(moduleID)(); | |
mockRegistry.set(moduleID, module); | |
return module; | |
} | |
const manualMockOrStub = this._resolver.getMockModule(from, moduleName); | |
let modulePath = | |
this._resolver.getMockModule(from, moduleName) || | |
this._resolveModule(from, moduleName); | |
let isManualMock = | |
manualMockOrStub && | |
!this._resolver.resolveStubModuleName(from, moduleName); | |
if (!isManualMock) { | |
// If the actual module file has a __mocks__ dir sitting immediately next | |
// to it, look to see if there is a manual mock for this file. | |
// | |
// subDir1/my_module.js | |
// subDir1/__mocks__/my_module.js | |
// subDir2/my_module.js | |
// subDir2/__mocks__/my_module.js | |
// | |
// Where some other module does a relative require into each of the | |
// respective subDir{1,2} directories and expects a manual mock | |
// corresponding to that particular my_module.js file. | |
const moduleDir = path().dirname(modulePath); | |
const moduleFileName = path().basename(modulePath); | |
const potentialManualMock = path().join( | |
moduleDir, | |
'__mocks__', | |
moduleFileName | |
); | |
if (fs().existsSync(potentialManualMock)) { | |
isManualMock = true; | |
modulePath = potentialManualMock; | |
} | |
} | |
if (isManualMock) { | |
const localModule = { | |
children: [], | |
exports: {}, | |
filename: modulePath, | |
id: modulePath, | |
loaded: false, | |
path: path().dirname(modulePath) | |
}; | |
this._loadModule( | |
localModule, | |
from, | |
moduleName, | |
modulePath, | |
undefined, | |
mockRegistry | |
); | |
mockRegistry.set(moduleID, localModule.exports); | |
} else { | |
// Look for a real module to generate an automock from | |
mockRegistry.set(moduleID, this._generateMock(from, moduleName)); | |
} | |
return mockRegistry.get(moduleID); | |
} | |
_loadModule( | |
localModule, | |
from, | |
moduleName, | |
modulePath, | |
options, | |
moduleRegistry | |
) { | |
if (path().extname(modulePath) === '.json') { | |
const text = (0, _stripBom().default)(this.readFile(modulePath)); | |
const transformedFile = this._scriptTransformer.transformJson( | |
modulePath, | |
this._getFullTransformationOptions(options), | |
text | |
); | |
localModule.exports = this._environment.global.JSON.parse( | |
transformedFile | |
); | |
} else if (path().extname(modulePath) === '.node') { | |
localModule.exports = require(modulePath); | |
} else { | |
// Only include the fromPath if a moduleName is given. Else treat as root. | |
const fromPath = moduleName ? from : null; | |
this._execModule(localModule, options, moduleRegistry, fromPath); | |
} | |
localModule.loaded = true; | |
} | |
_getFullTransformationOptions(options = defaultTransformOptions) { | |
return {...options, ...this._coverageOptions}; | |
} | |
requireModuleOrMock(from, moduleName) { | |
// this module is unmockable | |
if (moduleName === '@jest/globals') { | |
// @ts-expect-error: we don't care that it's not assignable to T | |
return this.getGlobalsForCjs(from); | |
} | |
try { | |
if (this._shouldMock(from, moduleName)) { | |
return this.requireMock(from, moduleName); | |
} else { | |
return this.requireModule(from, moduleName); | |
} | |
} catch (e) { | |
const moduleNotFound = _jestResolve().default.tryCastModuleNotFoundError( | |
e | |
); | |
if (moduleNotFound) { | |
if ( | |
moduleNotFound.siblingWithSimilarExtensionFound === null || | |
moduleNotFound.siblingWithSimilarExtensionFound === undefined | |
) { | |
moduleNotFound.hint = (0, _helpers.findSiblingsWithFileExtension)( | |
this._config.moduleFileExtensions, | |
from, | |
moduleNotFound.moduleName || moduleName | |
); | |
moduleNotFound.siblingWithSimilarExtensionFound = Boolean( | |
moduleNotFound.hint | |
); | |
} | |
moduleNotFound.buildMessage(this._config.rootDir); | |
throw moduleNotFound; | |
} | |
throw e; | |
} | |
} | |
isolateModules(fn) { | |
if (this._isolatedModuleRegistry || this._isolatedMockRegistry) { | |
throw new Error( | |
'isolateModules cannot be nested inside another isolateModules.' | |
); | |
} | |
this._isolatedModuleRegistry = new Map(); | |
this._isolatedMockRegistry = new Map(); | |
try { | |
fn(); | |
} finally { | |
var _this$_isolatedModule, _this$_isolatedMockRe; | |
// might be cleared within the callback | |
(_this$_isolatedModule = this._isolatedModuleRegistry) === null || | |
_this$_isolatedModule === void 0 | |
? void 0 | |
: _this$_isolatedModule.clear(); | |
(_this$_isolatedMockRe = this._isolatedMockRegistry) === null || | |
_this$_isolatedMockRe === void 0 | |
? void 0 | |
: _this$_isolatedMockRe.clear(); | |
this._isolatedModuleRegistry = null; | |
this._isolatedMockRegistry = null; | |
} | |
} | |
resetModules() { | |
var _this$_isolatedModule2, _this$_isolatedMockRe2; | |
(_this$_isolatedModule2 = this._isolatedModuleRegistry) === null || | |
_this$_isolatedModule2 === void 0 | |
? void 0 | |
: _this$_isolatedModule2.clear(); | |
(_this$_isolatedMockRe2 = this._isolatedMockRegistry) === null || | |
_this$_isolatedMockRe2 === void 0 | |
? void 0 | |
: _this$_isolatedMockRe2.clear(); | |
this._isolatedModuleRegistry = null; | |
this._isolatedMockRegistry = null; | |
this._mockRegistry.clear(); | |
this._moduleRegistry.clear(); | |
this._esmoduleRegistry.clear(); | |
if (this._environment) { | |
if (this._environment.global) { | |
const envGlobal = this._environment.global; | |
Object.keys(envGlobal).forEach(key => { | |
const globalMock = envGlobal[key]; | |
if ( | |
((typeof globalMock === 'object' && globalMock !== null) || | |
typeof globalMock === 'function') && | |
globalMock._isMockFunction === true | |
) { | |
globalMock.mockClear(); | |
} | |
}); | |
} | |
if (this._environment.fakeTimers) { | |
this._environment.fakeTimers.clearAllTimers(); | |
} | |
} | |
} | |
async collectV8Coverage() { | |
this._v8CoverageInstrumenter = new (_collectV8Coverage().CoverageInstrumenter)(); | |
await this._v8CoverageInstrumenter.startInstrumenting(); | |
} | |
async stopCollectingV8Coverage() { | |
if (!this._v8CoverageInstrumenter) { | |
throw new Error('You need to call `collectV8Coverage` first.'); | |
} | |
this._v8CoverageResult = await this._v8CoverageInstrumenter.stopInstrumenting(); | |
} | |
getAllCoverageInfoCopy() { | |
return (0, _jestUtil().deepCyclicCopy)( | |
this._environment.global.__coverage__ | |
); | |
} | |
getAllV8CoverageInfoCopy() { | |
if (!this._v8CoverageResult) { | |
throw new Error('You need to `stopCollectingV8Coverage` first'); | |
} | |
return this._v8CoverageResult | |
.filter(res => res.url.startsWith('file://')) | |
.map(res => ({...res, url: (0, _url().fileURLToPath)(res.url)})) | |
.filter( | |
( | |
res // TODO: will this work on windows? It might be better if `shouldInstrument` deals with it anyways | |
) => | |
res.url.startsWith(this._config.rootDir) && | |
this._fileTransforms.has(res.url) && | |
(0, _transform().shouldInstrument)( | |
res.url, | |
this._coverageOptions, | |
this._config | |
) | |
) | |
.map(result => { | |
const transformedFile = this._fileTransforms.get(result.url); | |
return { | |
codeTransformResult: transformedFile, | |
result | |
}; | |
}); | |
} // TODO - remove in Jest 27 | |
getSourceMapInfo(_coveredFiles) { | |
return {}; | |
} | |
getSourceMaps() { | |
return fromEntries(this._sourceMapRegistry); | |
} | |
setMock(from, moduleName, mockFactory, options) { | |
if (options === null || options === void 0 ? void 0 : options.virtual) { | |
const mockPath = this._resolver.getModulePath(from, moduleName); | |
this._virtualMocks.set(mockPath, true); | |
} | |
const moduleID = this._resolver.getModuleID( | |
fromEntries(this._virtualMocks), | |
from, | |
moduleName | |
); | |
this._explicitShouldMock.set(moduleID, true); | |
this._mockFactories.set(moduleID, mockFactory); | |
} | |
restoreAllMocks() { | |
this._moduleMocker.restoreAllMocks(); | |
} | |
resetAllMocks() { | |
this._moduleMocker.resetAllMocks(); | |
} | |
clearAllMocks() { | |
this._moduleMocker.clearAllMocks(); | |
} | |
teardown() { | |
this.restoreAllMocks(); | |
this.resetAllMocks(); | |
this.resetModules(); | |
this._internalModuleRegistry.clear(); | |
this._mainModule = null; | |
this._mockFactories.clear(); | |
this._mockMetaDataCache.clear(); | |
this._shouldMockModuleCache.clear(); | |
this._shouldUnmockTransitiveDependenciesCache.clear(); | |
this._explicitShouldMock.clear(); | |
this._transitiveShouldMock.clear(); | |
this._virtualMocks.clear(); | |
this._cacheFS.clear(); | |
this._unmockList = undefined; | |
this._sourceMapRegistry.clear(); | |
this._fileTransforms.clear(); | |
this.jestObjectCaches.clear(); | |
this._v8CoverageResult = []; | |
this._v8CoverageInstrumenter = undefined; | |
this._moduleImplementation = undefined; | |
} | |
_resolveModule(from, to) { | |
return to ? this._resolver.resolveModule(from, to) : from; | |
} | |
_requireResolve(from, moduleName, options = {}) { | |
if (moduleName == null) { | |
throw new Error( | |
'The first argument to require.resolve must be a string. Received null or undefined.' | |
); | |
} | |
const {paths} = options; | |
if (paths) { | |
for (const p of paths) { | |
const absolutePath = path().resolve(from, '..', p); | |
const module = this._resolver.resolveModuleFromDirIfExists( | |
absolutePath, | |
moduleName, // required to also resolve files without leading './' directly in the path | |
{ | |
paths: [absolutePath] | |
} | |
); | |
if (module) { | |
return module; | |
} | |
} | |
throw new (_jestResolve().default.ModuleNotFoundError)( | |
`Cannot resolve module '${moduleName}' from paths ['${paths.join( | |
"', '" | |
)}'] from ${from}` | |
); | |
} | |
try { | |
return this._resolveModule(from, moduleName); | |
} catch (err) { | |
const module = this._resolver.getMockModule(from, moduleName); | |
if (module) { | |
return module; | |
} else { | |
throw err; | |
} | |
} | |
} | |
_requireResolvePaths(from, moduleName) { | |
if (moduleName == null) { | |
throw new Error( | |
'The first argument to require.resolve.paths must be a string. Received null or undefined.' | |
); | |
} | |
if (!moduleName.length) { | |
throw new Error( | |
'The first argument to require.resolve.paths must not be the empty string.' | |
); | |
} | |
if (moduleName[0] === '.') { | |
return [path().resolve(from, '..')]; | |
} | |
if (this._resolver.isCoreModule(moduleName)) { | |
return null; | |
} | |
return this._resolver.getModulePaths(path().resolve(from, '..')); | |
} | |
_execModule(localModule, options, moduleRegistry, from) { | |
// If the environment was disposed, prevent this module from being executed. | |
if (!this._environment.global) { | |
return; | |
} | |
const module = localModule; | |
const filename = module.filename; | |
const lastExecutingModulePath = this._currentlyExecutingModulePath; | |
this._currentlyExecutingModulePath = filename; | |
const origCurrExecutingManualMock = this._isCurrentlyExecutingManualMock; | |
this._isCurrentlyExecutingManualMock = filename; | |
module.children = []; | |
Object.defineProperty(module, 'parent', { | |
enumerable: true, | |
get() { | |
const key = from || ''; | |
return moduleRegistry.get(key) || null; | |
} | |
}); | |
module.paths = this._resolver.getModulePaths(module.path); | |
Object.defineProperty(module, 'require', { | |
value: this._createRequireImplementation(module, options) | |
}); | |
const transformedCode = this.transformFile(filename, options); | |
let compiledFunction = null; | |
const script = this.createScriptFromCode(transformedCode, filename); | |
let runScript = null; // Use this if available instead of deprecated `JestEnvironment.runScript` | |
if (typeof this._environment.getVmContext === 'function') { | |
const vmContext = this._environment.getVmContext(); | |
if (vmContext) { | |
runScript = script.runInContext(vmContext, { | |
filename | |
}); | |
} | |
} else { | |
runScript = this._environment.runScript(script); | |
} | |
if (runScript !== null) { | |
compiledFunction = runScript[EVAL_RESULT_VARIABLE]; | |
} | |
if (compiledFunction === null) { | |
this._logFormattedReferenceError( | |
'You are trying to `import` a file after the Jest environment has been torn down.' | |
); | |
process.exitCode = 1; | |
return; | |
} | |
const jestObject = this._createJestObjectFor(filename); | |
this.jestObjectCaches.set(filename, jestObject); | |
const lastArgs = [ | |
this._config.injectGlobals ? jestObject : undefined, // jest object | |
...this._config.extraGlobals.map(globalVariable => { | |
if (this._environment.global[globalVariable]) { | |
return this._environment.global[globalVariable]; | |
} | |
throw new Error( | |
`You have requested '${globalVariable}' as a global variable, but it was not present. Please check your config or your global environment.` | |
); | |
}) | |
]; | |
if (!this._mainModule && filename === this._testPath) { | |
this._mainModule = module; | |
} | |
Object.defineProperty(module, 'main', { | |
enumerable: true, | |
value: this._mainModule | |
}); | |
try { | |
compiledFunction.call( | |
module.exports, | |
module, // module object | |
module.exports, // module exports | |
module.require, // require implementation | |
module.path, // __dirname | |
module.filename, // __filename | |
this._environment.global, // global object | |
// @ts-expect-error | |
...lastArgs.filter(notEmpty) | |
); | |
} catch (error) { | |
this.handleExecutionError(error, module); | |
} | |
this._isCurrentlyExecutingManualMock = origCurrExecutingManualMock; | |
this._currentlyExecutingModulePath = lastExecutingModulePath; | |
} | |
transformFile(filename, options) { | |
const source = this.readFile(filename); | |
if ( | |
options === null || options === void 0 ? void 0 : options.isInternalModule | |
) { | |
return source; | |
} | |
const transformedFile = this._scriptTransformer.transform( | |
filename, | |
this._getFullTransformationOptions(options), | |
source | |
); | |
this._fileTransforms.set(filename, { | |
...transformedFile, | |
wrapperLength: this.constructModuleWrapperStart().length | |
}); | |
if (transformedFile.sourceMapPath) { | |
this._sourceMapRegistry.set(filename, transformedFile.sourceMapPath); | |
} | |
return transformedFile.code; | |
} | |
createScriptFromCode(scriptSource, filename) { | |
try { | |
const scriptFilename = this._resolver.isCoreModule(filename) | |
? `jest-nodejs-core-${filename}` | |
: filename; | |
return new (_vm().Script)(this.wrapCodeInModuleWrapper(scriptSource), { | |
displayErrors: true, | |
filename: scriptFilename, | |
// @ts-expect-error: Experimental ESM API | |
importModuleDynamically: specifier => { | |
var _this$_environment$ge, _this$_environment; | |
const context = | |
(_this$_environment$ge = (_this$_environment = this._environment) | |
.getVmContext) === null || _this$_environment$ge === void 0 | |
? void 0 | |
: _this$_environment$ge.call(_this$_environment); | |
invariant(context); | |
return this.linkModules(specifier, scriptFilename, context); | |
} | |
}); | |
} catch (e) { | |
throw (0, _transform().handlePotentialSyntaxError)(e); | |
} | |
} | |
_requireCoreModule(moduleName) { | |
if (moduleName === 'process') { | |
return this._environment.global.process; | |
} | |
if (moduleName === 'module') { | |
return this._getMockedNativeModule(); | |
} | |
return require(moduleName); | |
} | |
_importCoreModule(moduleName, context) { | |
const required = this._requireCoreModule(moduleName); | |
const module = new (_vm().SyntheticModule)( | |
['default', ...Object.keys(required)], | |
function () { | |
// @ts-expect-error: TS doesn't know what `this` is | |
this.setExport('default', required); | |
Object.entries(required).forEach(([key, value]) => { | |
// @ts-expect-error: TS doesn't know what `this` is | |
this.setExport(key, value); | |
}); | |
}, // should identifier be `node://${moduleName}`? | |
{ | |
context, | |
identifier: moduleName | |
} | |
); | |
return evaluateSyntheticModule(module); | |
} | |
_getMockedNativeModule() { | |
if (this._moduleImplementation) { | |
return this._moduleImplementation; | |
} | |
const createRequire = modulePath => { | |
const filename = | |
typeof modulePath === 'string' | |
? modulePath.startsWith('file:///') | |
? (0, _url().fileURLToPath)(new (_url().URL)(modulePath)) | |
: modulePath | |
: (0, _url().fileURLToPath)(modulePath); | |
if (!path().isAbsolute(filename)) { | |
const error = new TypeError( | |
`The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received '${filename}'` | |
); // @ts-expect-error | |
error.code = 'ERR_INVALID_ARG_TYPE'; | |
throw error; | |
} | |
return this._createRequireImplementation({ | |
children: [], | |
exports: {}, | |
filename, | |
id: filename, | |
loaded: false, | |
path: path().dirname(filename) | |
}); | |
}; // should we implement the class ourselves? | |
class Module extends nativeModule().Module {} | |
Object.entries(nativeModule().Module).forEach(([key, value]) => { | |
// @ts-expect-error | |
Module[key] = value; | |
}); | |
Module.Module = Module; | |
if ('createRequire' in nativeModule()) { | |
Module.createRequire = createRequire; | |
} | |
if ('createRequireFromPath' in nativeModule()) { | |
Module.createRequireFromPath = function createRequireFromPath(filename) { | |
if (typeof filename !== 'string') { | |
const error = new TypeError( | |
`The argument 'filename' must be string. Received '${filename}'.${ | |
filename instanceof _url().URL | |
? ' Use createRequire for URL filename.' | |
: '' | |
}` | |
); // @ts-expect-error | |
error.code = 'ERR_INVALID_ARG_TYPE'; | |
throw error; | |
} | |
return createRequire(filename); | |
}; | |
} | |
if ('syncBuiltinESMExports' in nativeModule()) { | |
Module.syncBuiltinESMExports = function syncBuiltinESMExports() {}; | |
} | |
this._moduleImplementation = Module; | |
return Module; | |
} | |
_generateMock(from, moduleName) { | |
const modulePath = | |
this._resolver.resolveStubModuleName(from, moduleName) || | |
this._resolveModule(from, moduleName); | |
if (!this._mockMetaDataCache.has(modulePath)) { | |
// This allows us to handle circular dependencies while generating an | |
// automock | |
this._mockMetaDataCache.set( | |
modulePath, | |
this._moduleMocker.getMetadata({}) || {} | |
); // In order to avoid it being possible for automocking to potentially | |
// cause side-effects within the module environment, we need to execute | |
// the module in isolation. This could cause issues if the module being | |
// mocked has calls into side-effectful APIs on another module. | |
const origMockRegistry = this._mockRegistry; | |
const origModuleRegistry = this._moduleRegistry; | |
this._mockRegistry = new Map(); | |
this._moduleRegistry = new Map(); | |
const moduleExports = this.requireModule(from, moduleName); // Restore the "real" module/mock registries | |
this._mockRegistry = origMockRegistry; | |
this._moduleRegistry = origModuleRegistry; | |
const mockMetadata = this._moduleMocker.getMetadata(moduleExports); | |
if (mockMetadata == null) { | |
throw new Error( | |
`Failed to get mock metadata: ${modulePath}\n\n` + | |
`See: https://jestjs.io/docs/manual-mocks.html#content` | |
); | |
} | |
this._mockMetaDataCache.set(modulePath, mockMetadata); | |
} | |
return this._moduleMocker.generateFromMetadata( | |
// added above if missing | |
this._mockMetaDataCache.get(modulePath) | |
); | |
} | |
_shouldMock(from, moduleName) { | |
const explicitShouldMock = this._explicitShouldMock; | |
const moduleID = this._resolver.getModuleID( | |
fromEntries(this._virtualMocks), | |
from, | |
moduleName | |
); | |
const key = from + path().delimiter + moduleID; | |
if (explicitShouldMock.has(moduleID)) { | |
// guaranteed by `has` above | |
return explicitShouldMock.get(moduleID); | |
} | |
if ( | |
!this._shouldAutoMock || | |
this._resolver.isCoreModule(moduleName) || | |
this._shouldUnmockTransitiveDependenciesCache.get(key) | |
) { | |
return false; | |
} | |
if (this._shouldMockModuleCache.has(moduleID)) { | |
// guaranteed by `has` above | |
return this._shouldMockModuleCache.get(moduleID); | |
} | |
let modulePath; | |
try { | |
modulePath = this._resolveModule(from, moduleName); | |
} catch (e) { | |
const manualMock = this._resolver.getMockModule(from, moduleName); | |
if (manualMock) { | |
this._shouldMockModuleCache.set(moduleID, true); | |
return true; | |
} | |
throw e; | |
} | |
if (this._unmockList && this._unmockList.test(modulePath)) { | |
this._shouldMockModuleCache.set(moduleID, false); | |
return false; | |
} // transitive unmocking for package managers that store flat packages (npm3) | |
const currentModuleID = this._resolver.getModuleID( | |
fromEntries(this._virtualMocks), | |
from | |
); | |
if ( | |
this._transitiveShouldMock.get(currentModuleID) === false || | |
(from.includes(NODE_MODULES) && | |
modulePath.includes(NODE_MODULES) && | |
((this._unmockList && this._unmockList.test(from)) || | |
explicitShouldMock.get(currentModuleID) === false)) | |
) { | |
this._transitiveShouldMock.set(moduleID, false); | |
this._shouldUnmockTransitiveDependenciesCache.set(key, true); | |
return false; | |
} | |
this._shouldMockModuleCache.set(moduleID, true); | |
return true; | |
} | |
_createRequireImplementation(from, options) { | |
const resolve = (moduleName, resolveOptions) => { | |
const resolved = this._requireResolve( | |
from.filename, | |
moduleName, | |
resolveOptions | |
); | |
if ( | |
(resolveOptions === null || resolveOptions === void 0 | |
? void 0 | |
: resolveOptions[OUTSIDE_JEST_VM_RESOLVE_OPTION]) && | |
(options === null || options === void 0 | |
? void 0 | |
: options.isInternalModule) | |
) { | |
return (0, _helpers.createOutsideJestVmPath)(resolved); | |
} | |
return resolved; | |
}; | |
resolve.paths = moduleName => | |
this._requireResolvePaths(from.filename, moduleName); | |
const moduleRequire = ( | |
options === null || options === void 0 ? void 0 : options.isInternalModule | |
) | |
? moduleName => this.requireInternalModule(from.filename, moduleName) | |
: this.requireModuleOrMock.bind(this, from.filename); | |
moduleRequire.extensions = Object.create(null); | |
moduleRequire.resolve = resolve; | |
moduleRequire.cache = (() => { | |
// TODO: consider warning somehow that this does nothing. We should support deletions, anyways | |
const notPermittedMethod = () => true; | |
return new Proxy(Object.create(null), { | |
defineProperty: notPermittedMethod, | |
deleteProperty: notPermittedMethod, | |
get: (_target, key) => | |
typeof key === 'string' ? this._moduleRegistry.get(key) : undefined, | |
getOwnPropertyDescriptor() { | |
return { | |
configurable: true, | |
enumerable: true | |
}; | |
}, | |
has: (_target, key) => | |
typeof key === 'string' && this._moduleRegistry.has(key), | |
ownKeys: () => Array.from(this._moduleRegistry.keys()), | |
set: notPermittedMethod | |
}); | |
})(); | |
Object.defineProperty(moduleRequire, 'main', { | |
enumerable: true, | |
value: this._mainModule | |
}); | |
return moduleRequire; | |
} | |
_createJestObjectFor(from) { | |
const disableAutomock = () => { | |
this._shouldAutoMock = false; | |
return jestObject; | |
}; | |
const enableAutomock = () => { | |
this._shouldAutoMock = true; | |
return jestObject; | |
}; | |
const unmock = moduleName => { | |
const moduleID = this._resolver.getModuleID( | |
fromEntries(this._virtualMocks), | |
from, | |
moduleName | |
); | |
this._explicitShouldMock.set(moduleID, false); | |
return jestObject; | |
}; | |
const deepUnmock = moduleName => { | |
const moduleID = this._resolver.getModuleID( | |
fromEntries(this._virtualMocks), | |
from, | |
moduleName | |
); | |
this._explicitShouldMock.set(moduleID, false); | |
this._transitiveShouldMock.set(moduleID, false); | |
return jestObject; | |
}; | |
const mock = (moduleName, mockFactory, options) => { | |
if (mockFactory !== undefined) { | |
return setMockFactory(moduleName, mockFactory, options); | |
} | |
const moduleID = this._resolver.getModuleID( | |
fromEntries(this._virtualMocks), | |
from, | |
moduleName | |
); | |
this._explicitShouldMock.set(moduleID, true); | |
return jestObject; | |
}; | |
const setMockFactory = (moduleName, mockFactory, options) => { | |
this.setMock(from, moduleName, mockFactory, options); | |
return jestObject; | |
}; | |
const clearAllMocks = () => { | |
this.clearAllMocks(); | |
return jestObject; | |
}; | |
const resetAllMocks = () => { | |
this.resetAllMocks(); | |
return jestObject; | |
}; | |
const restoreAllMocks = () => { | |
this.restoreAllMocks(); | |
return jestObject; | |
}; | |
const _getFakeTimers = () => { | |
if ( | |
!(this._environment.fakeTimers || this._environment.fakeTimersModern) | |
) { | |
this._logFormattedReferenceError( | |
'You are trying to access a property or method of the Jest environment after it has been torn down.' | |
); | |
process.exitCode = 1; | |
} | |
return this._fakeTimersImplementation; | |
}; | |
const useFakeTimers = (type = 'legacy') => { | |
if (type === 'modern') { | |
this._fakeTimersImplementation = this._environment.fakeTimersModern; | |
} else { | |
this._fakeTimersImplementation = this._environment.fakeTimers; | |
} | |
this._fakeTimersImplementation.useFakeTimers(); | |
return jestObject; | |
}; | |
const useRealTimers = () => { | |
_getFakeTimers().useRealTimers(); | |
return jestObject; | |
}; | |
const resetModules = () => { | |
this.resetModules(); | |
return jestObject; | |
}; | |
const isolateModules = fn => { | |
this.isolateModules(fn); | |
return jestObject; | |
}; | |
const fn = this._moduleMocker.fn.bind(this._moduleMocker); | |
const spyOn = this._moduleMocker.spyOn.bind(this._moduleMocker); | |
const setTimeout = timeout => { | |
if (this._environment.global.jasmine) { | |
this._environment.global.jasmine._DEFAULT_TIMEOUT_INTERVAL = timeout; | |
} else { | |
// @ts-expect-error: https://github.com/Microsoft/TypeScript/issues/24587 | |
this._environment.global[testTimeoutSymbol] = timeout; | |
} | |
return jestObject; | |
}; | |
const retryTimes = numTestRetries => { | |
// @ts-expect-error: https://github.com/Microsoft/TypeScript/issues/24587 | |
this._environment.global[retryTimesSymbol] = numTestRetries; | |
return jestObject; | |
}; | |
const jestObject = { | |
addMatchers: matchers => | |
this._environment.global.jasmine.addMatchers(matchers), | |
advanceTimersByTime: msToRun => | |
_getFakeTimers().advanceTimersByTime(msToRun), | |
advanceTimersToNextTimer: steps => | |
_getFakeTimers().advanceTimersToNextTimer(steps), | |
autoMockOff: disableAutomock, | |
autoMockOn: enableAutomock, | |
clearAllMocks, | |
clearAllTimers: () => _getFakeTimers().clearAllTimers(), | |
createMockFromModule: moduleName => this._generateMock(from, moduleName), | |
deepUnmock, | |
disableAutomock, | |
doMock: mock, | |
dontMock: unmock, | |
enableAutomock, | |
fn, | |
genMockFromModule: moduleName => this._generateMock(from, moduleName), | |
getRealSystemTime: () => { | |
const fakeTimers = _getFakeTimers(); | |
if (fakeTimers instanceof _fakeTimers().ModernFakeTimers) { | |
return fakeTimers.getRealSystemTime(); | |
} else { | |
throw new TypeError( | |
'getRealSystemTime is not available when not using modern timers' | |
); | |
} | |
}, | |
getTimerCount: () => _getFakeTimers().getTimerCount(), | |
isMockFunction: this._moduleMocker.isMockFunction, | |
isolateModules, | |
mock, | |
requireActual: this.requireActual.bind(this, from), | |
requireMock: this.requireMock.bind(this, from), | |
resetAllMocks, | |
resetModuleRegistry: resetModules, | |
resetModules, | |
restoreAllMocks, | |
retryTimes, | |
runAllImmediates: () => { | |
const fakeTimers = _getFakeTimers(); | |
if (fakeTimers instanceof _fakeTimers().LegacyFakeTimers) { | |
fakeTimers.runAllImmediates(); | |
} else { | |
throw new TypeError( | |
'runAllImmediates is not available when using modern timers' | |
); | |
} | |
}, | |
runAllTicks: () => _getFakeTimers().runAllTicks(), | |
runAllTimers: () => _getFakeTimers().runAllTimers(), | |
runOnlyPendingTimers: () => _getFakeTimers().runOnlyPendingTimers(), | |
runTimersToTime: msToRun => _getFakeTimers().advanceTimersByTime(msToRun), | |
setMock: (moduleName, mock) => setMockFactory(moduleName, () => mock), | |
setSystemTime: now => { | |
const fakeTimers = _getFakeTimers(); | |
if (fakeTimers instanceof _fakeTimers().ModernFakeTimers) { | |
fakeTimers.setSystemTime(now); | |
} else { | |
throw new TypeError( | |
'setSystemTime is not available when not using modern timers' | |
); | |
} | |
}, | |
setTimeout, | |
spyOn, | |
unmock, | |
useFakeTimers, | |
useRealTimers | |
}; | |
return jestObject; | |
} | |
_logFormattedReferenceError(errorMessage) { | |
const originalStack = new ReferenceError(errorMessage).stack | |
.split('\n') // Remove this file from the stack (jest-message-utils will keep one line) | |
.filter(line => line.indexOf(__filename) === -1) | |
.join('\n'); | |
const {message, stack} = (0, _jestMessageUtil().separateMessageFromStack)( | |
originalStack | |
); | |
console.error( | |
`\n${message}\n` + | |
(0, _jestMessageUtil().formatStackTrace)(stack, this._config, { | |
noStackTrace: false | |
}) | |
); | |
} | |
wrapCodeInModuleWrapper(content) { | |
return this.constructModuleWrapperStart() + content + '\n}});'; | |
} | |
constructModuleWrapperStart() { | |
const args = this.constructInjectedModuleParameters(); | |
return '({"' + EVAL_RESULT_VARIABLE + `":function(${args.join(',')}){`; | |
} | |
constructInjectedModuleParameters() { | |
return [ | |
'module', | |
'exports', | |
'require', | |
'__dirname', | |
'__filename', | |
'global', | |
this._config.injectGlobals ? 'jest' : undefined, | |
...this._config.extraGlobals | |
].filter(notEmpty); | |
} | |
handleExecutionError(e, module) { | |
const moduleNotFoundError = _jestResolve().default.tryCastModuleNotFoundError( | |
e | |
); | |
if (moduleNotFoundError) { | |
if (!moduleNotFoundError.requireStack) { | |
moduleNotFoundError.requireStack = [module.filename || module.id]; | |
for (let cursor = module.parent; cursor; cursor = cursor.parent) { | |
moduleNotFoundError.requireStack.push(cursor.filename || cursor.id); | |
} | |
moduleNotFoundError.buildMessage(this._config.rootDir); | |
} | |
throw moduleNotFoundError; | |
} | |
throw e; | |
} | |
getGlobalsForCjs(from) { | |
const jest = this.jestObjectCaches.get(from); | |
invariant(jest, 'There should always be a Jest object already'); | |
return {...this.getGlobalsFromEnvironment(), jest}; | |
} | |
getGlobalsForEsm(from, context) { | |
let jest = this.jestObjectCaches.get(from); | |
if (!jest) { | |
jest = this._createJestObjectFor(from); | |
this.jestObjectCaches.set(from, jest); | |
} | |
const globals = {...this.getGlobalsFromEnvironment(), jest}; | |
const module = new (_vm().SyntheticModule)( | |
Object.keys(globals), | |
function () { | |
Object.entries(globals).forEach(([key, value]) => { | |
// @ts-expect-error: TS doesn't know what `this` is | |
this.setExport(key, value); | |
}); | |
}, | |
{ | |
context, | |
identifier: '@jest/globals' | |
} | |
); | |
return evaluateSyntheticModule(module); | |
} | |
getGlobalsFromEnvironment() { | |
if (this.jestGlobals) { | |
return {...this.jestGlobals}; | |
} | |
return { | |
afterAll: this._environment.global.afterAll, | |
afterEach: this._environment.global.afterEach, | |
beforeAll: this._environment.global.beforeAll, | |
beforeEach: this._environment.global.beforeEach, | |
describe: this._environment.global.describe, | |
expect: this._environment.global.expect, | |
fdescribe: this._environment.global.fdescribe, | |
fit: this._environment.global.fit, | |
it: this._environment.global.it, | |
test: this._environment.global.test, | |
xdescribe: this._environment.global.xdescribe, | |
xit: this._environment.global.xit, | |
xtest: this._environment.global.xtest | |
}; | |
} | |
readFile(filename) { | |
let source = this._cacheFS.get(filename); | |
if (!source) { | |
source = fs().readFileSync(filename, 'utf8'); | |
this._cacheFS.set(filename, source); | |
} | |
return source; | |
} | |
setGlobalsForRuntime(globals) { | |
this.jestGlobals = globals; | |
} | |
} | |
_defineProperty(Runtime, 'shouldInstrument', _transform().shouldInstrument); | |
function invariant(condition, message) { | |
if (!condition) { | |
throw new Error(message); | |
} | |
} | |
function notEmpty(value) { | |
return value !== null && value !== undefined; | |
} | |
async function evaluateSyntheticModule(module) { | |
await module.link(() => { | |
throw new Error('This should never happen'); | |
}); | |
await module.evaluate(); | |
return module; | |
} | |
module.exports = Runtime; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment