mirror of https://github.com/facebook/jest.git
chore: remove jest-config dependency from jest-runner (#11466)
This commit is contained in:
parent
ae3fc943d4
commit
5f4dd187d8
|
@ -77,7 +77,7 @@ module.exports = {
|
|||
'packages/jest-jasmine2/src/jasmine/Suite.ts',
|
||||
'packages/jest-jasmine2/src/jasmine/jasmineLight.ts',
|
||||
'packages/jest-jasmine2/src/jestExpect.ts',
|
||||
'packages/jest-resolve/src/index.ts',
|
||||
'packages/jest-resolve/src/resolver.ts',
|
||||
],
|
||||
rules: {
|
||||
'local/prefer-spread-eventually': 'warn',
|
||||
|
|
|
@ -3,9 +3,13 @@
|
|||
### Features
|
||||
|
||||
- `[jest-reporters]` Expose the `getResultHeader` util ([#11460](https://github.com/facebook/jest/pull/11460))
|
||||
- `[jest-resolver]` Export `resolve*` utils for different Jest modules ([#11466](https://github.com/facebook/jest/pull/11466))
|
||||
- `[@jest/test-result]` Export `Test`, `TestEvents` and `TestFileEvent` ([#11466](https://github.com/facebook/jest/pull/11466))
|
||||
|
||||
### Fixes
|
||||
|
||||
- `[jest-circus, @jest/test-sequencer]` Remove dependency on `jest-runner` ([#11466](https://github.com/facebook/jest/pull/11466))
|
||||
- `[jest-runner]` Remove dependency on `jest-config` ([#11466](https://github.com/facebook/jest/pull/11466))
|
||||
- `[jest-worker]` Loosen engine requirement to `>= 10.13.0` ([#11451](https://github.com/facebook/jest/pull/11451))
|
||||
|
||||
### Chore & Maintenance
|
||||
|
|
|
@ -41,7 +41,7 @@ FAIL __tests__/index.js
|
|||
12 | module.exports = () => 'test';
|
||||
13 |
|
||||
|
||||
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/index.js:558:17)
|
||||
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/resolver.js:558:17)
|
||||
at Object.require (index.js:10:1)
|
||||
`;
|
||||
|
||||
|
@ -70,6 +70,6 @@ FAIL __tests__/index.js
|
|||
12 | module.exports = () => 'test';
|
||||
13 |
|
||||
|
||||
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/index.js:558:17)
|
||||
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/resolver.js:558:17)
|
||||
at Object.require (index.js:10:1)
|
||||
`;
|
||||
|
|
|
@ -37,6 +37,6 @@ FAIL __tests__/test.js
|
|||
| ^
|
||||
9 |
|
||||
|
||||
at Resolver.resolveModule (../../packages/jest-resolve/build/index.js:311:11)
|
||||
at Resolver.resolveModule (../../packages/jest-resolve/build/resolver.js:311:11)
|
||||
at Object.require (index.js:8:18)
|
||||
`;
|
||||
|
|
|
@ -82,7 +82,7 @@ describe('Stack Trace', () => {
|
|||
);
|
||||
|
||||
expect(stderr).toMatch(
|
||||
/\s+at\s(?:.+?)\s\((?:.+?)jest-resolve\/build\/index\.js/,
|
||||
/\s+at\s(?:.+?)\s\((?:.+?)jest-resolve\/build\/resolver\.js/,
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
"testEnvironment": "node",
|
||||
"transformIgnorePatterns": [
|
||||
"jest-circus",
|
||||
"jest-jasmine2"
|
||||
"jest-jasmine2",
|
||||
"jest-runner"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
"transformIgnorePatterns": [
|
||||
"jest-circus",
|
||||
"jest-environment-node",
|
||||
"jest-jasmine2"
|
||||
"jest-jasmine2",
|
||||
"jest-runner"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,9 @@
|
|||
"transformIgnorePatterns": [
|
||||
"jest-circus",
|
||||
"jest-each",
|
||||
"jest-environment-node/",
|
||||
"jest-jasmine2"
|
||||
"jest-environment-node",
|
||||
"jest-jasmine2",
|
||||
"jest-runner"
|
||||
],
|
||||
"moduleFileExtensions": [
|
||||
"js"
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
"jest-circus",
|
||||
"jest-each",
|
||||
"jest-environment-node",
|
||||
"jest-jasmine2"
|
||||
"jest-jasmine2",
|
||||
"jest-runner"
|
||||
],
|
||||
"transform": {
|
||||
"\\.js$": "<rootDir>/preprocessor.js"
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
{
|
||||
"jest": {
|
||||
"testEnvironment": "node"
|
||||
"testEnvironment": "node",
|
||||
"transformIgnorePatterns": [
|
||||
"node_modules",
|
||||
"jest-runner"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
"transformIgnorePatterns": [
|
||||
"jest-circus",
|
||||
"jest-environment-node",
|
||||
"jest-jasmine2"
|
||||
"jest-jasmine2",
|
||||
"jest-runner"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
@ -6,13 +6,12 @@
|
|||
*/
|
||||
|
||||
import throat from 'throat';
|
||||
import {TestResult, createEmptyTestResult} from '@jest/test-result';
|
||||
import {Test, TestResult, createEmptyTestResult} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import {
|
||||
import type {
|
||||
OnTestFailure,
|
||||
OnTestStart,
|
||||
OnTestSuccess,
|
||||
Test,
|
||||
TestRunnerContext,
|
||||
TestWatcher,
|
||||
} from 'jest-runner';
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
"jest-each": "^27.0.1",
|
||||
"jest-matcher-utils": "^27.0.1",
|
||||
"jest-message-util": "^27.0.1",
|
||||
"jest-runner": "^27.0.1",
|
||||
"jest-runtime": "^27.0.1",
|
||||
"jest-snapshot": "^27.0.1",
|
||||
"jest-util": "^27.0.1",
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
*/
|
||||
|
||||
import type {JestEnvironment} from '@jest/environment';
|
||||
import type {TestResult} from '@jest/test-result';
|
||||
import type {TestFileEvent, TestResult} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import type {TestFileEvent} from 'jest-runner';
|
||||
import type Runtime from 'jest-runtime';
|
||||
import type {SnapshotStateType} from 'jest-snapshot';
|
||||
import {deepCyclicCopy} from 'jest-util';
|
||||
|
|
|
@ -10,6 +10,7 @@ import type {JestEnvironment} from '@jest/environment';
|
|||
import {
|
||||
AssertionResult,
|
||||
Status,
|
||||
TestFileEvent,
|
||||
TestResult,
|
||||
createEmptyTestResult,
|
||||
} from '@jest/test-result';
|
||||
|
@ -17,7 +18,6 @@ import type {Circus, Config, Global} from '@jest/types';
|
|||
import {extractExpectedAssertionsErrors, getState, setState} from 'expect';
|
||||
import {bind} from 'jest-each';
|
||||
import {formatExecError, formatResultsErrors} from 'jest-message-util';
|
||||
import type {TestFileEvent} from 'jest-runner';
|
||||
import {
|
||||
SnapshotState,
|
||||
SnapshotStateType,
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {TestFileEvent} from '@jest/test-result';
|
||||
import type {Circus} from '@jest/types';
|
||||
import type {TestFileEvent} from 'jest-runner';
|
||||
import {makeSingleTestResult, parseSingleTestResult} from './utils';
|
||||
|
||||
const testCaseReportHandler =
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
{"path": "../jest-environment"},
|
||||
{"path": "../jest-matcher-utils"},
|
||||
{"path": "../jest-message-util"},
|
||||
{"path": "../jest-runner"},
|
||||
{"path": "../jest-runtime"},
|
||||
{"path": "../jest-snapshot"},
|
||||
{"path": "../jest-test-result"},
|
||||
|
|
|
@ -15,7 +15,11 @@ import normalize from './normalize';
|
|||
import readConfigFileAndSetRootDir from './readConfigFileAndSetRootDir';
|
||||
import resolveConfigPath from './resolveConfigPath';
|
||||
import {isJSONString, replaceRootDirInPath} from './utils';
|
||||
export {getTestEnvironment, isJSONString} from './utils';
|
||||
|
||||
// TODO: remove export in Jest 28
|
||||
export {resolveTestEnvironment as getTestEnvironment} from 'jest-resolve';
|
||||
|
||||
export {isJSONString} from './utils';
|
||||
export {default as normalize} from './normalize';
|
||||
export {default as deprecationEntries} from './Deprecated';
|
||||
export {replaceRootDirInPath} from './utils';
|
||||
|
|
|
@ -14,7 +14,12 @@ import {statSync} from 'graceful-fs';
|
|||
import micromatch = require('micromatch');
|
||||
import type {Config} from '@jest/types';
|
||||
import {replacePathSepForRegex} from 'jest-regex-util';
|
||||
import Resolver from 'jest-resolve';
|
||||
import Resolver, {
|
||||
resolveRunner,
|
||||
resolveSequencer,
|
||||
resolveTestEnvironment,
|
||||
resolveWatchPlugin,
|
||||
} from 'jest-resolve';
|
||||
import {
|
||||
clearLine,
|
||||
replacePathSepForGlob,
|
||||
|
@ -35,14 +40,11 @@ import {
|
|||
DOCUMENTATION_NOTE,
|
||||
_replaceRootDirTags,
|
||||
escapeGlobCharacters,
|
||||
getRunner,
|
||||
getSequencer,
|
||||
getTestEnvironment,
|
||||
getWatchPlugin,
|
||||
replaceRootDirInPath,
|
||||
resolve,
|
||||
} from './utils';
|
||||
import validatePattern from './validatePattern';
|
||||
|
||||
const ERROR = `${BULLET}Validation Error`;
|
||||
const PRESET_EXTENSIONS = ['.json', '.js', '.cjs', '.mjs'];
|
||||
const PRESET_NAME = 'jest-preset';
|
||||
|
@ -604,7 +606,7 @@ export default async function normalize(
|
|||
options.setupFilesAfterEnv.push(options.setupTestFrameworkScriptFile);
|
||||
}
|
||||
|
||||
options.testEnvironment = getTestEnvironment({
|
||||
options.testEnvironment = resolveTestEnvironment({
|
||||
rootDir: options.rootDir,
|
||||
testEnvironment: options.testEnvironment || DEFAULT_CONFIG.testEnvironment,
|
||||
});
|
||||
|
@ -739,7 +741,7 @@ export default async function normalize(
|
|||
const option = oldOptions[key];
|
||||
value =
|
||||
option &&
|
||||
getRunner(newOptions.resolver, {
|
||||
resolveRunner(newOptions.resolver, {
|
||||
filePath: option,
|
||||
rootDir: options.rootDir,
|
||||
});
|
||||
|
@ -1010,7 +1012,7 @@ export default async function normalize(
|
|||
if (typeof watchPlugin === 'string') {
|
||||
return {
|
||||
config: {},
|
||||
path: getWatchPlugin(newOptions.resolver, {
|
||||
path: resolveWatchPlugin(newOptions.resolver, {
|
||||
filePath: watchPlugin,
|
||||
rootDir: options.rootDir,
|
||||
}),
|
||||
|
@ -1018,7 +1020,7 @@ export default async function normalize(
|
|||
} else {
|
||||
return {
|
||||
config: watchPlugin[1] || {},
|
||||
path: getWatchPlugin(newOptions.resolver, {
|
||||
path: resolveWatchPlugin(newOptions.resolver, {
|
||||
filePath: watchPlugin[0],
|
||||
rootDir: options.rootDir,
|
||||
}),
|
||||
|
@ -1051,7 +1053,7 @@ export default async function normalize(
|
|||
// ignored
|
||||
}
|
||||
|
||||
newOptions.testSequencer = getSequencer(newOptions.resolver, {
|
||||
newOptions.testSequencer = resolveSequencer(newOptions.resolver, {
|
||||
filePath: options.testSequencer || DEFAULT_CONFIG.testSequencer,
|
||||
rootDir: options.rootDir,
|
||||
});
|
||||
|
|
|
@ -117,134 +117,9 @@ export const _replaceRootDirTags = <T extends ReplaceRootDirConfigValues>(
|
|||
return config;
|
||||
};
|
||||
|
||||
export const resolveWithPrefix = (
|
||||
resolver: string | undefined | null,
|
||||
{
|
||||
filePath,
|
||||
humanOptionName,
|
||||
optionName,
|
||||
prefix,
|
||||
rootDir,
|
||||
}: {
|
||||
filePath: string;
|
||||
humanOptionName: string;
|
||||
optionName: string;
|
||||
prefix: string;
|
||||
rootDir: Config.Path;
|
||||
},
|
||||
): string => {
|
||||
const fileName = replaceRootDirInPath(rootDir, filePath);
|
||||
let module = Resolver.findNodeModule(`${prefix}${fileName}`, {
|
||||
basedir: rootDir,
|
||||
resolver: resolver || undefined,
|
||||
});
|
||||
if (module) {
|
||||
return module;
|
||||
}
|
||||
|
||||
try {
|
||||
return require.resolve(`${prefix}${fileName}`);
|
||||
} catch {}
|
||||
|
||||
module = Resolver.findNodeModule(fileName, {
|
||||
basedir: rootDir,
|
||||
resolver: resolver || undefined,
|
||||
});
|
||||
if (module) {
|
||||
return module;
|
||||
}
|
||||
|
||||
try {
|
||||
return require.resolve(fileName);
|
||||
} catch {}
|
||||
|
||||
throw createValidationError(
|
||||
` ${humanOptionName} ${chalk.bold(
|
||||
fileName,
|
||||
)} cannot be found. Make sure the ${chalk.bold(
|
||||
optionName,
|
||||
)} configuration option points to an existing node module.`,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds the test environment to use:
|
||||
*
|
||||
* 1. looks for jest-environment-<name> relative to project.
|
||||
* 1. looks for jest-environment-<name> relative to Jest.
|
||||
* 1. looks for <name> relative to project.
|
||||
* 1. looks for <name> relative to Jest.
|
||||
*/
|
||||
export const getTestEnvironment = ({
|
||||
rootDir,
|
||||
testEnvironment: filePath,
|
||||
}: {
|
||||
rootDir: Config.Path;
|
||||
testEnvironment: string;
|
||||
}): string =>
|
||||
resolveWithPrefix(undefined, {
|
||||
filePath,
|
||||
humanOptionName: 'Test environment',
|
||||
optionName: 'testEnvironment',
|
||||
prefix: 'jest-environment-',
|
||||
rootDir,
|
||||
});
|
||||
|
||||
/**
|
||||
* Finds the watch plugins to use:
|
||||
*
|
||||
* 1. looks for jest-watch-<name> relative to project.
|
||||
* 1. looks for jest-watch-<name> relative to Jest.
|
||||
* 1. looks for <name> relative to project.
|
||||
* 1. looks for <name> relative to Jest.
|
||||
*/
|
||||
export const getWatchPlugin = (
|
||||
resolver: string | undefined | null,
|
||||
{filePath, rootDir}: {filePath: string; rootDir: Config.Path},
|
||||
): string =>
|
||||
resolveWithPrefix(resolver, {
|
||||
filePath,
|
||||
humanOptionName: 'Watch plugin',
|
||||
optionName: 'watchPlugins',
|
||||
prefix: 'jest-watch-',
|
||||
rootDir,
|
||||
});
|
||||
|
||||
/**
|
||||
* Finds the runner to use:
|
||||
*
|
||||
* 1. looks for jest-runner-<name> relative to project.
|
||||
* 1. looks for jest-runner-<name> relative to Jest.
|
||||
* 1. looks for <name> relative to project.
|
||||
* 1. looks for <name> relative to Jest.
|
||||
*/
|
||||
export const getRunner = (
|
||||
resolver: string | undefined | null,
|
||||
{filePath, rootDir}: {filePath: string; rootDir: Config.Path},
|
||||
): string =>
|
||||
resolveWithPrefix(resolver, {
|
||||
filePath,
|
||||
humanOptionName: 'Jest Runner',
|
||||
optionName: 'runner',
|
||||
prefix: 'jest-runner-',
|
||||
rootDir,
|
||||
});
|
||||
|
||||
type JSONString = string & {readonly $$type: never}; // newtype
|
||||
export const isJSONString = (text?: JSONString | string): text is JSONString =>
|
||||
text != null &&
|
||||
typeof text === 'string' &&
|
||||
text.startsWith('{') &&
|
||||
text.endsWith('}');
|
||||
|
||||
export const getSequencer = (
|
||||
resolver: string | undefined | null,
|
||||
{filePath, rootDir}: {filePath: string; rootDir: Config.Path},
|
||||
): string =>
|
||||
resolveWithPrefix(resolver, {
|
||||
filePath,
|
||||
humanOptionName: 'Jest Sequencer',
|
||||
optionName: 'testSequencer',
|
||||
prefix: 'jest-sequencer-',
|
||||
rootDir,
|
||||
});
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {TestResult} from '@jest/test-result';
|
||||
import type {Test} from 'jest-runner';
|
||||
import type {Test, TestResult} from '@jest/test-result';
|
||||
|
||||
type TestMap = Record<string, Record<string, boolean>>;
|
||||
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
import type {Reporter, ReporterOnStartOptions} from '@jest/reporters';
|
||||
import type {
|
||||
AggregatedResult,
|
||||
Test,
|
||||
TestCaseResult,
|
||||
TestResult,
|
||||
} from '@jest/test-result';
|
||||
import type {Test} from 'jest-runner';
|
||||
import type {Context} from 'jest-runtime';
|
||||
|
||||
export default class ReporterDispatcher {
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import micromatch = require('micromatch');
|
||||
import type {Test} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import type {ChangedFiles} from 'jest-changed-files';
|
||||
import {replaceRootDirInPath} from 'jest-config';
|
||||
import {escapePathForRegex} from 'jest-regex-util';
|
||||
import {DependencyResolver} from 'jest-resolve-dependencies';
|
||||
import type {Test} from 'jest-runner';
|
||||
import type {Context} from 'jest-runtime';
|
||||
import {buildSnapshotResolver} from 'jest-snapshot';
|
||||
import {globsToMatcher, testPathPatternToRegExp} from 'jest-util';
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {Test} from 'jest-runner';
|
||||
import type {Test} from '@jest/test-result';
|
||||
import type {Context} from 'jest-runtime';
|
||||
import {
|
||||
PatternPrompt,
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
import {
|
||||
AggregatedResult,
|
||||
SerializableError,
|
||||
Test,
|
||||
TestResult,
|
||||
addResult,
|
||||
buildFailureTestResult,
|
||||
|
@ -28,7 +29,7 @@ import {
|
|||
import {createScriptTransformer} from '@jest/transform';
|
||||
import type {Config} from '@jest/types';
|
||||
import {formatExecError} from 'jest-message-util';
|
||||
import TestRunner, {Test} from 'jest-runner';
|
||||
import type TestRunner from 'jest-runner';
|
||||
import type {Context} from 'jest-runtime';
|
||||
import snapshot = require('jest-snapshot');
|
||||
import {requireOrImportModule} from 'jest-util';
|
||||
|
@ -36,10 +37,6 @@ import ReporterDispatcher from './ReporterDispatcher';
|
|||
import type TestWatcher from './TestWatcher';
|
||||
import {shouldRunInBand} from './testSchedulerHelper';
|
||||
|
||||
// The default jest-runner is required because it is the default test runner
|
||||
// and required implicitly through the `runner` ProjectConfig option.
|
||||
TestRunner;
|
||||
|
||||
export type TestSchedulerOptions = {
|
||||
startRun: (globalConfig: Config.GlobalConfig) => void;
|
||||
};
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
*/
|
||||
|
||||
import * as path from 'path';
|
||||
import type {Test} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import {normalize} from 'jest-config';
|
||||
import type {Test} from 'jest-runner';
|
||||
import Runtime from 'jest-runtime';
|
||||
import SearchSource, {SearchResult} from '../SearchSource';
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
import * as util from 'util';
|
||||
import pEachSeries = require('p-each-series');
|
||||
import type {Test} from '@jest/test-result';
|
||||
import {createScriptTransformer} from '@jest/transform';
|
||||
import type {Config} from '@jest/types';
|
||||
import type {Test} from 'jest-runner';
|
||||
import prettyFormat from 'pretty-format';
|
||||
|
||||
export default async ({
|
||||
|
|
|
@ -12,13 +12,13 @@ import * as fs from 'graceful-fs';
|
|||
import {CustomConsole} from '@jest/console';
|
||||
import {
|
||||
AggregatedResult,
|
||||
Test,
|
||||
formatTestResults,
|
||||
makeEmptyAggregatedTestResult,
|
||||
} from '@jest/test-result';
|
||||
import type TestSequencer from '@jest/test-sequencer';
|
||||
import type {Config} from '@jest/types';
|
||||
import type {ChangedFiles, ChangedFilesPromise} from 'jest-changed-files';
|
||||
import type {Test} from 'jest-runner';
|
||||
import type {Context} from 'jest-runtime';
|
||||
import {requireOrImportModule, tryRealpath} from 'jest-util';
|
||||
import {JestHook, JestHookEmitter} from 'jest-watcher';
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {Test} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import type {Test} from 'jest-runner';
|
||||
|
||||
const SLOW_TEST_TIME = 1000;
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {Test} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import type {Test} from 'jest-runner';
|
||||
import type {Context} from 'jest-runtime';
|
||||
|
||||
export type Stats = {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"graceful-fs": "^4.2.4",
|
||||
"jest-pnp-resolver": "^1.2.2",
|
||||
"jest-util": "^27.0.1",
|
||||
"jest-validate": "^27.0.1",
|
||||
"resolve": "^1.20.0",
|
||||
"slash": "^3.0.0"
|
||||
},
|
||||
|
|
|
@ -10,10 +10,10 @@ import * as path from 'path';
|
|||
import * as fs from 'graceful-fs';
|
||||
import {sync as resolveSync} from 'resolve';
|
||||
import {ModuleMap} from 'jest-haste-map';
|
||||
import Resolver from '../';
|
||||
import userResolver from '../__mocks__/userResolver';
|
||||
import defaultResolver from '../defaultResolver';
|
||||
import nodeModulesPaths from '../nodeModulesPaths';
|
||||
import Resolver from '../resolver';
|
||||
import type {ResolverConfig} from '../types';
|
||||
|
||||
jest.mock('../__mocks__/userResolver');
|
||||
|
|
|
@ -5,493 +5,9 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* eslint-disable local/prefer-spread-eventually */
|
||||
import Resolver from './resolver';
|
||||
|
||||
import * as path from 'path';
|
||||
import chalk = require('chalk');
|
||||
import slash = require('slash');
|
||||
import type {Config} from '@jest/types';
|
||||
import type {IModuleMap} from 'jest-haste-map';
|
||||
import {tryRealpath} from 'jest-util';
|
||||
import ModuleNotFoundError from './ModuleNotFoundError';
|
||||
import defaultResolver, {clearDefaultResolverCache} from './defaultResolver';
|
||||
import isBuiltinModule from './isBuiltinModule';
|
||||
import nodeModulesPaths from './nodeModulesPaths';
|
||||
import shouldLoadAsEsm, {clearCachedLookups} from './shouldLoadAsEsm';
|
||||
import type {ResolverConfig} from './types';
|
||||
export type {ResolveModuleConfig} from './resolver';
|
||||
export * from './utils';
|
||||
|
||||
type FindNodeModuleConfig = {
|
||||
basedir: Config.Path;
|
||||
browser?: boolean;
|
||||
extensions?: Array<string>;
|
||||
moduleDirectory?: Array<string>;
|
||||
paths?: Array<Config.Path>;
|
||||
resolver?: Config.Path | null;
|
||||
rootDir?: Config.Path;
|
||||
throwIfNotFound?: boolean;
|
||||
};
|
||||
|
||||
export type ResolveModuleConfig = {
|
||||
skipNodeResolution?: boolean;
|
||||
paths?: Array<Config.Path>;
|
||||
};
|
||||
|
||||
const NATIVE_PLATFORM = 'native';
|
||||
|
||||
// We might be inside a symlink.
|
||||
const resolvedCwd = tryRealpath(process.cwd());
|
||||
const {NODE_PATH} = process.env;
|
||||
const nodePaths = NODE_PATH
|
||||
? NODE_PATH.split(path.delimiter)
|
||||
.filter(Boolean)
|
||||
// The resolver expects absolute paths.
|
||||
.map(p => path.resolve(resolvedCwd, p))
|
||||
: undefined;
|
||||
|
||||
export default class Resolver {
|
||||
private readonly _options: ResolverConfig;
|
||||
private readonly _moduleMap: IModuleMap;
|
||||
private readonly _moduleIDCache: Map<string, string>;
|
||||
private readonly _moduleNameCache: Map<string, Config.Path>;
|
||||
private readonly _modulePathCache: Map<string, Array<Config.Path>>;
|
||||
private readonly _supportsNativePlatform: boolean;
|
||||
|
||||
constructor(moduleMap: IModuleMap, options: ResolverConfig) {
|
||||
this._options = {
|
||||
defaultPlatform: options.defaultPlatform,
|
||||
extensions: options.extensions,
|
||||
hasCoreModules:
|
||||
options.hasCoreModules === undefined ? true : options.hasCoreModules,
|
||||
moduleDirectories: options.moduleDirectories || ['node_modules'],
|
||||
moduleNameMapper: options.moduleNameMapper,
|
||||
modulePaths: options.modulePaths,
|
||||
platforms: options.platforms,
|
||||
resolver: options.resolver,
|
||||
rootDir: options.rootDir,
|
||||
};
|
||||
this._supportsNativePlatform = options.platforms
|
||||
? options.platforms.includes(NATIVE_PLATFORM)
|
||||
: false;
|
||||
this._moduleMap = moduleMap;
|
||||
this._moduleIDCache = new Map();
|
||||
this._moduleNameCache = new Map();
|
||||
this._modulePathCache = new Map();
|
||||
}
|
||||
|
||||
static ModuleNotFoundError = ModuleNotFoundError;
|
||||
|
||||
static tryCastModuleNotFoundError(
|
||||
error: unknown,
|
||||
): ModuleNotFoundError | null {
|
||||
if (error instanceof ModuleNotFoundError) {
|
||||
return error as ModuleNotFoundError;
|
||||
}
|
||||
|
||||
const casted = error as ModuleNotFoundError;
|
||||
if (casted.code === 'MODULE_NOT_FOUND') {
|
||||
return ModuleNotFoundError.duckType(casted);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static clearDefaultResolverCache(): void {
|
||||
clearDefaultResolverCache();
|
||||
clearCachedLookups();
|
||||
}
|
||||
|
||||
static findNodeModule(
|
||||
path: Config.Path,
|
||||
options: FindNodeModuleConfig,
|
||||
): Config.Path | null {
|
||||
const resolver: typeof defaultResolver = options.resolver
|
||||
? require(options.resolver)
|
||||
: defaultResolver;
|
||||
const paths = options.paths;
|
||||
|
||||
try {
|
||||
return resolver(path, {
|
||||
basedir: options.basedir,
|
||||
browser: options.browser,
|
||||
defaultResolver,
|
||||
extensions: options.extensions,
|
||||
moduleDirectory: options.moduleDirectory,
|
||||
paths: paths ? (nodePaths || []).concat(paths) : nodePaths,
|
||||
rootDir: options.rootDir,
|
||||
});
|
||||
} catch (e) {
|
||||
if (options.throwIfNotFound) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// unstable as it should be replaced by https://github.com/nodejs/modules/issues/393, and we don't want people to use it
|
||||
static unstable_shouldLoadAsEsm = shouldLoadAsEsm;
|
||||
|
||||
resolveModuleFromDirIfExists(
|
||||
dirname: Config.Path,
|
||||
moduleName: string,
|
||||
options?: ResolveModuleConfig,
|
||||
): Config.Path | null {
|
||||
const paths = (options && options.paths) || this._options.modulePaths;
|
||||
const moduleDirectory = this._options.moduleDirectories;
|
||||
const key = dirname + path.delimiter + moduleName;
|
||||
const defaultPlatform = this._options.defaultPlatform;
|
||||
const extensions = this._options.extensions.slice();
|
||||
let module;
|
||||
|
||||
if (this._supportsNativePlatform) {
|
||||
extensions.unshift(
|
||||
...this._options.extensions.map(ext => '.' + NATIVE_PLATFORM + ext),
|
||||
);
|
||||
}
|
||||
if (defaultPlatform) {
|
||||
extensions.unshift(
|
||||
...this._options.extensions.map(ext => '.' + defaultPlatform + ext),
|
||||
);
|
||||
}
|
||||
|
||||
// 1. If we have already resolved this module for this directory name,
|
||||
// return a value from the cache.
|
||||
const cacheResult = this._moduleNameCache.get(key);
|
||||
if (cacheResult) {
|
||||
return cacheResult;
|
||||
}
|
||||
|
||||
// 2. Check if the module is a haste module.
|
||||
module = this.getModule(moduleName);
|
||||
if (module) {
|
||||
this._moduleNameCache.set(key, module);
|
||||
return module;
|
||||
}
|
||||
|
||||
// 3. Check if the module is a node module and resolve it based on
|
||||
// the node module resolution algorithm. If skipNodeResolution is given we
|
||||
// ignore all modules that look like node modules (ie. are not relative
|
||||
// requires). This enables us to speed up resolution when we build a
|
||||
// dependency graph because we don't have to look at modules that may not
|
||||
// exist and aren't mocked.
|
||||
const skipResolution =
|
||||
options && options.skipNodeResolution && !moduleName.includes(path.sep);
|
||||
|
||||
const resolveNodeModule = (name: Config.Path, throwIfNotFound = false) =>
|
||||
Resolver.findNodeModule(name, {
|
||||
basedir: dirname,
|
||||
extensions,
|
||||
moduleDirectory,
|
||||
paths,
|
||||
resolver: this._options.resolver,
|
||||
rootDir: this._options.rootDir,
|
||||
throwIfNotFound,
|
||||
});
|
||||
|
||||
if (!skipResolution) {
|
||||
module = resolveNodeModule(moduleName, Boolean(process.versions.pnp));
|
||||
|
||||
if (module) {
|
||||
this._moduleNameCache.set(key, module);
|
||||
return module;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Resolve "haste packages" which are `package.json` files outside of
|
||||
// `node_modules` folders anywhere in the file system.
|
||||
const parts = moduleName.split('/');
|
||||
const hastePackage = this.getPackage(parts.shift()!);
|
||||
if (hastePackage) {
|
||||
try {
|
||||
const module = path.join.apply(
|
||||
path,
|
||||
[path.dirname(hastePackage)].concat(parts),
|
||||
);
|
||||
// try resolving with custom resolver first to support extensions,
|
||||
// then fallback to require.resolve
|
||||
const resolvedModule =
|
||||
resolveNodeModule(module) || require.resolve(module);
|
||||
this._moduleNameCache.set(key, resolvedModule);
|
||||
return resolvedModule;
|
||||
} catch {}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
resolveModule(
|
||||
from: Config.Path,
|
||||
moduleName: string,
|
||||
options?: ResolveModuleConfig,
|
||||
): Config.Path {
|
||||
const dirname = path.dirname(from);
|
||||
const module =
|
||||
this.resolveStubModuleName(from, moduleName) ||
|
||||
this.resolveModuleFromDirIfExists(dirname, moduleName, options);
|
||||
if (module) return module;
|
||||
|
||||
// 5. Throw an error if the module could not be found. `resolve.sync` only
|
||||
// produces an error based on the dirname but we have the actual current
|
||||
// module name available.
|
||||
const relativePath =
|
||||
slash(path.relative(this._options.rootDir, from)) || '.';
|
||||
|
||||
throw new ModuleNotFoundError(
|
||||
`Cannot find module '${moduleName}' from '${relativePath}'`,
|
||||
moduleName,
|
||||
);
|
||||
}
|
||||
|
||||
private _isAliasModule(moduleName: string): boolean {
|
||||
const moduleNameMapper = this._options.moduleNameMapper;
|
||||
if (!moduleNameMapper) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return moduleNameMapper.some(({regex}) => regex.test(moduleName));
|
||||
}
|
||||
|
||||
isCoreModule(moduleName: string): boolean {
|
||||
return (
|
||||
this._options.hasCoreModules &&
|
||||
isBuiltinModule(moduleName) &&
|
||||
!this._isAliasModule(moduleName)
|
||||
);
|
||||
}
|
||||
|
||||
getModule(name: string): Config.Path | null {
|
||||
return this._moduleMap.getModule(
|
||||
name,
|
||||
this._options.defaultPlatform,
|
||||
this._supportsNativePlatform,
|
||||
);
|
||||
}
|
||||
|
||||
getModulePath(from: Config.Path, moduleName: string): Config.Path {
|
||||
if (moduleName[0] !== '.' || path.isAbsolute(moduleName)) {
|
||||
return moduleName;
|
||||
}
|
||||
return path.normalize(path.dirname(from) + '/' + moduleName);
|
||||
}
|
||||
|
||||
getPackage(name: string): Config.Path | null {
|
||||
return this._moduleMap.getPackage(
|
||||
name,
|
||||
this._options.defaultPlatform,
|
||||
this._supportsNativePlatform,
|
||||
);
|
||||
}
|
||||
|
||||
getMockModule(from: Config.Path, name: string): Config.Path | null {
|
||||
const mock = this._moduleMap.getMockModule(name);
|
||||
if (mock) {
|
||||
return mock;
|
||||
} else {
|
||||
const moduleName = this.resolveStubModuleName(from, name);
|
||||
if (moduleName) {
|
||||
return this.getModule(moduleName) || moduleName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getModulePaths(from: Config.Path): Array<Config.Path> {
|
||||
const cachedModule = this._modulePathCache.get(from);
|
||||
if (cachedModule) {
|
||||
return cachedModule;
|
||||
}
|
||||
|
||||
const moduleDirectory = this._options.moduleDirectories;
|
||||
const paths = nodeModulesPaths(from, {moduleDirectory});
|
||||
if (paths[paths.length - 1] === undefined) {
|
||||
// circumvent node-resolve bug that adds `undefined` as last item.
|
||||
paths.pop();
|
||||
}
|
||||
this._modulePathCache.set(from, paths);
|
||||
return paths;
|
||||
}
|
||||
|
||||
getModuleID(
|
||||
virtualMocks: Map<string, boolean>,
|
||||
from: Config.Path,
|
||||
_moduleName?: string,
|
||||
): string {
|
||||
const moduleName = _moduleName || '';
|
||||
|
||||
const key = from + path.delimiter + moduleName;
|
||||
const cachedModuleID = this._moduleIDCache.get(key);
|
||||
if (cachedModuleID) {
|
||||
return cachedModuleID;
|
||||
}
|
||||
|
||||
const moduleType = this._getModuleType(moduleName);
|
||||
const absolutePath = this._getAbsolutePath(virtualMocks, from, moduleName);
|
||||
const mockPath = this._getMockPath(from, moduleName);
|
||||
|
||||
const sep = path.delimiter;
|
||||
const id =
|
||||
moduleType +
|
||||
sep +
|
||||
(absolutePath ? absolutePath + sep : '') +
|
||||
(mockPath ? mockPath + sep : '');
|
||||
|
||||
this._moduleIDCache.set(key, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
private _getModuleType(moduleName: string): 'node' | 'user' {
|
||||
return this.isCoreModule(moduleName) ? 'node' : 'user';
|
||||
}
|
||||
|
||||
private _getAbsolutePath(
|
||||
virtualMocks: Map<string, boolean>,
|
||||
from: Config.Path,
|
||||
moduleName: string,
|
||||
): Config.Path | null {
|
||||
if (this.isCoreModule(moduleName)) {
|
||||
return moduleName;
|
||||
}
|
||||
return this._isModuleResolved(from, moduleName)
|
||||
? this.getModule(moduleName)
|
||||
: this._getVirtualMockPath(virtualMocks, from, moduleName);
|
||||
}
|
||||
|
||||
private _getMockPath(
|
||||
from: Config.Path,
|
||||
moduleName: string,
|
||||
): Config.Path | null {
|
||||
return !this.isCoreModule(moduleName)
|
||||
? this.getMockModule(from, moduleName)
|
||||
: null;
|
||||
}
|
||||
|
||||
private _getVirtualMockPath(
|
||||
virtualMocks: Map<string, boolean>,
|
||||
from: Config.Path,
|
||||
moduleName: string,
|
||||
): Config.Path {
|
||||
const virtualMockPath = this.getModulePath(from, moduleName);
|
||||
return virtualMocks.get(virtualMockPath)
|
||||
? virtualMockPath
|
||||
: moduleName
|
||||
? this.resolveModule(from, moduleName)
|
||||
: from;
|
||||
}
|
||||
|
||||
private _isModuleResolved(from: Config.Path, moduleName: string): boolean {
|
||||
return !!(
|
||||
this.getModule(moduleName) || this.getMockModule(from, moduleName)
|
||||
);
|
||||
}
|
||||
|
||||
resolveStubModuleName(
|
||||
from: Config.Path,
|
||||
moduleName: string,
|
||||
): Config.Path | null {
|
||||
const dirname = path.dirname(from);
|
||||
const paths = this._options.modulePaths;
|
||||
const extensions = this._options.extensions.slice();
|
||||
const moduleDirectory = this._options.moduleDirectories;
|
||||
const moduleNameMapper = this._options.moduleNameMapper;
|
||||
const resolver = this._options.resolver;
|
||||
const defaultPlatform = this._options.defaultPlatform;
|
||||
|
||||
if (this._supportsNativePlatform) {
|
||||
extensions.unshift(
|
||||
...this._options.extensions.map(ext => '.' + NATIVE_PLATFORM + ext),
|
||||
);
|
||||
}
|
||||
|
||||
if (defaultPlatform) {
|
||||
extensions.unshift(
|
||||
...this._options.extensions.map(ext => '.' + defaultPlatform + ext),
|
||||
);
|
||||
}
|
||||
|
||||
if (moduleNameMapper) {
|
||||
for (const {moduleName: mappedModuleName, regex} of moduleNameMapper) {
|
||||
if (regex.test(moduleName)) {
|
||||
// Note: once a moduleNameMapper matches the name, it must result
|
||||
// in a module, or else an error is thrown.
|
||||
const matches = moduleName.match(regex);
|
||||
const mapModuleName = matches
|
||||
? (moduleName: string) =>
|
||||
moduleName.replace(
|
||||
/\$([0-9]+)/g,
|
||||
(_, index) => matches[parseInt(index, 10)],
|
||||
)
|
||||
: (moduleName: string) => moduleName;
|
||||
|
||||
const possibleModuleNames = Array.isArray(mappedModuleName)
|
||||
? mappedModuleName
|
||||
: [mappedModuleName];
|
||||
let module: string | null = null;
|
||||
for (const possibleModuleName of possibleModuleNames) {
|
||||
const updatedName = mapModuleName(possibleModuleName);
|
||||
|
||||
module =
|
||||
this.getModule(updatedName) ||
|
||||
Resolver.findNodeModule(updatedName, {
|
||||
basedir: dirname,
|
||||
extensions,
|
||||
moduleDirectory,
|
||||
paths,
|
||||
resolver,
|
||||
rootDir: this._options.rootDir,
|
||||
});
|
||||
|
||||
if (module) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!module) {
|
||||
throw createNoMappedModuleFoundError(
|
||||
moduleName,
|
||||
mapModuleName,
|
||||
mappedModuleName,
|
||||
regex,
|
||||
resolver,
|
||||
);
|
||||
}
|
||||
return module;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const createNoMappedModuleFoundError = (
|
||||
moduleName: string,
|
||||
mapModuleName: (moduleName: string) => string,
|
||||
mappedModuleName: string | Array<string>,
|
||||
regex: RegExp,
|
||||
resolver?: ((...args: Array<unknown>) => unknown) | string | null,
|
||||
) => {
|
||||
const mappedAs = Array.isArray(mappedModuleName)
|
||||
? JSON.stringify(mappedModuleName.map(mapModuleName), null, 2)
|
||||
: mappedModuleName;
|
||||
const original = Array.isArray(mappedModuleName)
|
||||
? JSON.stringify(mappedModuleName, null, 6) // using 6 because of misalignment when nested below
|
||||
.slice(0, -1) + ' ]' /// align last bracket correctly as well
|
||||
: mappedModuleName;
|
||||
|
||||
const error = new Error(
|
||||
chalk.red(`${chalk.bold('Configuration error')}:
|
||||
|
||||
Could not locate module ${chalk.bold(moduleName)} mapped as:
|
||||
${chalk.bold(mappedAs)}.
|
||||
|
||||
Please check your configuration for these entries:
|
||||
{
|
||||
"moduleNameMapper": {
|
||||
"${regex.toString()}": "${chalk.bold(original)}"
|
||||
},
|
||||
"resolver": ${chalk.bold(String(resolver))}
|
||||
}`),
|
||||
);
|
||||
|
||||
error.name = '';
|
||||
|
||||
return error;
|
||||
};
|
||||
export default Resolver;
|
||||
|
|
|
@ -0,0 +1,497 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable local/prefer-spread-eventually */
|
||||
|
||||
import * as path from 'path';
|
||||
import chalk = require('chalk');
|
||||
import slash = require('slash');
|
||||
import type {Config} from '@jest/types';
|
||||
import type {IModuleMap} from 'jest-haste-map';
|
||||
import {tryRealpath} from 'jest-util';
|
||||
import ModuleNotFoundError from './ModuleNotFoundError';
|
||||
import defaultResolver, {clearDefaultResolverCache} from './defaultResolver';
|
||||
import isBuiltinModule from './isBuiltinModule';
|
||||
import nodeModulesPaths from './nodeModulesPaths';
|
||||
import shouldLoadAsEsm, {clearCachedLookups} from './shouldLoadAsEsm';
|
||||
import type {ResolverConfig} from './types';
|
||||
|
||||
type FindNodeModuleConfig = {
|
||||
basedir: Config.Path;
|
||||
browser?: boolean;
|
||||
extensions?: Array<string>;
|
||||
moduleDirectory?: Array<string>;
|
||||
paths?: Array<Config.Path>;
|
||||
resolver?: Config.Path | null;
|
||||
rootDir?: Config.Path;
|
||||
throwIfNotFound?: boolean;
|
||||
};
|
||||
|
||||
export type ResolveModuleConfig = {
|
||||
skipNodeResolution?: boolean;
|
||||
paths?: Array<Config.Path>;
|
||||
};
|
||||
|
||||
const NATIVE_PLATFORM = 'native';
|
||||
|
||||
// We might be inside a symlink.
|
||||
const resolvedCwd = tryRealpath(process.cwd());
|
||||
const {NODE_PATH} = process.env;
|
||||
const nodePaths = NODE_PATH
|
||||
? NODE_PATH.split(path.delimiter)
|
||||
.filter(Boolean)
|
||||
// The resolver expects absolute paths.
|
||||
.map(p => path.resolve(resolvedCwd, p))
|
||||
: undefined;
|
||||
|
||||
export default class Resolver {
|
||||
private readonly _options: ResolverConfig;
|
||||
private readonly _moduleMap: IModuleMap;
|
||||
private readonly _moduleIDCache: Map<string, string>;
|
||||
private readonly _moduleNameCache: Map<string, Config.Path>;
|
||||
private readonly _modulePathCache: Map<string, Array<Config.Path>>;
|
||||
private readonly _supportsNativePlatform: boolean;
|
||||
|
||||
constructor(moduleMap: IModuleMap, options: ResolverConfig) {
|
||||
this._options = {
|
||||
defaultPlatform: options.defaultPlatform,
|
||||
extensions: options.extensions,
|
||||
hasCoreModules:
|
||||
options.hasCoreModules === undefined ? true : options.hasCoreModules,
|
||||
moduleDirectories: options.moduleDirectories || ['node_modules'],
|
||||
moduleNameMapper: options.moduleNameMapper,
|
||||
modulePaths: options.modulePaths,
|
||||
platforms: options.platforms,
|
||||
resolver: options.resolver,
|
||||
rootDir: options.rootDir,
|
||||
};
|
||||
this._supportsNativePlatform = options.platforms
|
||||
? options.platforms.includes(NATIVE_PLATFORM)
|
||||
: false;
|
||||
this._moduleMap = moduleMap;
|
||||
this._moduleIDCache = new Map();
|
||||
this._moduleNameCache = new Map();
|
||||
this._modulePathCache = new Map();
|
||||
}
|
||||
|
||||
static ModuleNotFoundError = ModuleNotFoundError;
|
||||
|
||||
static tryCastModuleNotFoundError(
|
||||
error: unknown,
|
||||
): ModuleNotFoundError | null {
|
||||
if (error instanceof ModuleNotFoundError) {
|
||||
return error as ModuleNotFoundError;
|
||||
}
|
||||
|
||||
const casted = error as ModuleNotFoundError;
|
||||
if (casted.code === 'MODULE_NOT_FOUND') {
|
||||
return ModuleNotFoundError.duckType(casted);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static clearDefaultResolverCache(): void {
|
||||
clearDefaultResolverCache();
|
||||
clearCachedLookups();
|
||||
}
|
||||
|
||||
static findNodeModule(
|
||||
path: Config.Path,
|
||||
options: FindNodeModuleConfig,
|
||||
): Config.Path | null {
|
||||
const resolver: typeof defaultResolver = options.resolver
|
||||
? require(options.resolver)
|
||||
: defaultResolver;
|
||||
const paths = options.paths;
|
||||
|
||||
try {
|
||||
return resolver(path, {
|
||||
basedir: options.basedir,
|
||||
browser: options.browser,
|
||||
defaultResolver,
|
||||
extensions: options.extensions,
|
||||
moduleDirectory: options.moduleDirectory,
|
||||
paths: paths ? (nodePaths || []).concat(paths) : nodePaths,
|
||||
rootDir: options.rootDir,
|
||||
});
|
||||
} catch (e) {
|
||||
if (options.throwIfNotFound) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// unstable as it should be replaced by https://github.com/nodejs/modules/issues/393, and we don't want people to use it
|
||||
static unstable_shouldLoadAsEsm = shouldLoadAsEsm;
|
||||
|
||||
resolveModuleFromDirIfExists(
|
||||
dirname: Config.Path,
|
||||
moduleName: string,
|
||||
options?: ResolveModuleConfig,
|
||||
): Config.Path | null {
|
||||
const paths = (options && options.paths) || this._options.modulePaths;
|
||||
const moduleDirectory = this._options.moduleDirectories;
|
||||
const key = dirname + path.delimiter + moduleName;
|
||||
const defaultPlatform = this._options.defaultPlatform;
|
||||
const extensions = this._options.extensions.slice();
|
||||
let module;
|
||||
|
||||
if (this._supportsNativePlatform) {
|
||||
extensions.unshift(
|
||||
...this._options.extensions.map(ext => '.' + NATIVE_PLATFORM + ext),
|
||||
);
|
||||
}
|
||||
if (defaultPlatform) {
|
||||
extensions.unshift(
|
||||
...this._options.extensions.map(ext => '.' + defaultPlatform + ext),
|
||||
);
|
||||
}
|
||||
|
||||
// 1. If we have already resolved this module for this directory name,
|
||||
// return a value from the cache.
|
||||
const cacheResult = this._moduleNameCache.get(key);
|
||||
if (cacheResult) {
|
||||
return cacheResult;
|
||||
}
|
||||
|
||||
// 2. Check if the module is a haste module.
|
||||
module = this.getModule(moduleName);
|
||||
if (module) {
|
||||
this._moduleNameCache.set(key, module);
|
||||
return module;
|
||||
}
|
||||
|
||||
// 3. Check if the module is a node module and resolve it based on
|
||||
// the node module resolution algorithm. If skipNodeResolution is given we
|
||||
// ignore all modules that look like node modules (ie. are not relative
|
||||
// requires). This enables us to speed up resolution when we build a
|
||||
// dependency graph because we don't have to look at modules that may not
|
||||
// exist and aren't mocked.
|
||||
const skipResolution =
|
||||
options && options.skipNodeResolution && !moduleName.includes(path.sep);
|
||||
|
||||
const resolveNodeModule = (name: Config.Path, throwIfNotFound = false) =>
|
||||
Resolver.findNodeModule(name, {
|
||||
basedir: dirname,
|
||||
extensions,
|
||||
moduleDirectory,
|
||||
paths,
|
||||
resolver: this._options.resolver,
|
||||
rootDir: this._options.rootDir,
|
||||
throwIfNotFound,
|
||||
});
|
||||
|
||||
if (!skipResolution) {
|
||||
module = resolveNodeModule(moduleName, Boolean(process.versions.pnp));
|
||||
|
||||
if (module) {
|
||||
this._moduleNameCache.set(key, module);
|
||||
return module;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Resolve "haste packages" which are `package.json` files outside of
|
||||
// `node_modules` folders anywhere in the file system.
|
||||
const parts = moduleName.split('/');
|
||||
const hastePackage = this.getPackage(parts.shift()!);
|
||||
if (hastePackage) {
|
||||
try {
|
||||
const module = path.join.apply(
|
||||
path,
|
||||
[path.dirname(hastePackage)].concat(parts),
|
||||
);
|
||||
// try resolving with custom resolver first to support extensions,
|
||||
// then fallback to require.resolve
|
||||
const resolvedModule =
|
||||
resolveNodeModule(module) || require.resolve(module);
|
||||
this._moduleNameCache.set(key, resolvedModule);
|
||||
return resolvedModule;
|
||||
} catch {}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
resolveModule(
|
||||
from: Config.Path,
|
||||
moduleName: string,
|
||||
options?: ResolveModuleConfig,
|
||||
): Config.Path {
|
||||
const dirname = path.dirname(from);
|
||||
const module =
|
||||
this.resolveStubModuleName(from, moduleName) ||
|
||||
this.resolveModuleFromDirIfExists(dirname, moduleName, options);
|
||||
if (module) return module;
|
||||
|
||||
// 5. Throw an error if the module could not be found. `resolve.sync` only
|
||||
// produces an error based on the dirname but we have the actual current
|
||||
// module name available.
|
||||
const relativePath =
|
||||
slash(path.relative(this._options.rootDir, from)) || '.';
|
||||
|
||||
throw new ModuleNotFoundError(
|
||||
`Cannot find module '${moduleName}' from '${relativePath}'`,
|
||||
moduleName,
|
||||
);
|
||||
}
|
||||
|
||||
private _isAliasModule(moduleName: string): boolean {
|
||||
const moduleNameMapper = this._options.moduleNameMapper;
|
||||
if (!moduleNameMapper) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return moduleNameMapper.some(({regex}) => regex.test(moduleName));
|
||||
}
|
||||
|
||||
isCoreModule(moduleName: string): boolean {
|
||||
return (
|
||||
this._options.hasCoreModules &&
|
||||
isBuiltinModule(moduleName) &&
|
||||
!this._isAliasModule(moduleName)
|
||||
);
|
||||
}
|
||||
|
||||
getModule(name: string): Config.Path | null {
|
||||
return this._moduleMap.getModule(
|
||||
name,
|
||||
this._options.defaultPlatform,
|
||||
this._supportsNativePlatform,
|
||||
);
|
||||
}
|
||||
|
||||
getModulePath(from: Config.Path, moduleName: string): Config.Path {
|
||||
if (moduleName[0] !== '.' || path.isAbsolute(moduleName)) {
|
||||
return moduleName;
|
||||
}
|
||||
return path.normalize(path.dirname(from) + '/' + moduleName);
|
||||
}
|
||||
|
||||
getPackage(name: string): Config.Path | null {
|
||||
return this._moduleMap.getPackage(
|
||||
name,
|
||||
this._options.defaultPlatform,
|
||||
this._supportsNativePlatform,
|
||||
);
|
||||
}
|
||||
|
||||
getMockModule(from: Config.Path, name: string): Config.Path | null {
|
||||
const mock = this._moduleMap.getMockModule(name);
|
||||
if (mock) {
|
||||
return mock;
|
||||
} else {
|
||||
const moduleName = this.resolveStubModuleName(from, name);
|
||||
if (moduleName) {
|
||||
return this.getModule(moduleName) || moduleName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getModulePaths(from: Config.Path): Array<Config.Path> {
|
||||
const cachedModule = this._modulePathCache.get(from);
|
||||
if (cachedModule) {
|
||||
return cachedModule;
|
||||
}
|
||||
|
||||
const moduleDirectory = this._options.moduleDirectories;
|
||||
const paths = nodeModulesPaths(from, {moduleDirectory});
|
||||
if (paths[paths.length - 1] === undefined) {
|
||||
// circumvent node-resolve bug that adds `undefined` as last item.
|
||||
paths.pop();
|
||||
}
|
||||
this._modulePathCache.set(from, paths);
|
||||
return paths;
|
||||
}
|
||||
|
||||
getModuleID(
|
||||
virtualMocks: Map<string, boolean>,
|
||||
from: Config.Path,
|
||||
_moduleName?: string,
|
||||
): string {
|
||||
const moduleName = _moduleName || '';
|
||||
|
||||
const key = from + path.delimiter + moduleName;
|
||||
const cachedModuleID = this._moduleIDCache.get(key);
|
||||
if (cachedModuleID) {
|
||||
return cachedModuleID;
|
||||
}
|
||||
|
||||
const moduleType = this._getModuleType(moduleName);
|
||||
const absolutePath = this._getAbsolutePath(virtualMocks, from, moduleName);
|
||||
const mockPath = this._getMockPath(from, moduleName);
|
||||
|
||||
const sep = path.delimiter;
|
||||
const id =
|
||||
moduleType +
|
||||
sep +
|
||||
(absolutePath ? absolutePath + sep : '') +
|
||||
(mockPath ? mockPath + sep : '');
|
||||
|
||||
this._moduleIDCache.set(key, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
private _getModuleType(moduleName: string): 'node' | 'user' {
|
||||
return this.isCoreModule(moduleName) ? 'node' : 'user';
|
||||
}
|
||||
|
||||
private _getAbsolutePath(
|
||||
virtualMocks: Map<string, boolean>,
|
||||
from: Config.Path,
|
||||
moduleName: string,
|
||||
): Config.Path | null {
|
||||
if (this.isCoreModule(moduleName)) {
|
||||
return moduleName;
|
||||
}
|
||||
return this._isModuleResolved(from, moduleName)
|
||||
? this.getModule(moduleName)
|
||||
: this._getVirtualMockPath(virtualMocks, from, moduleName);
|
||||
}
|
||||
|
||||
private _getMockPath(
|
||||
from: Config.Path,
|
||||
moduleName: string,
|
||||
): Config.Path | null {
|
||||
return !this.isCoreModule(moduleName)
|
||||
? this.getMockModule(from, moduleName)
|
||||
: null;
|
||||
}
|
||||
|
||||
private _getVirtualMockPath(
|
||||
virtualMocks: Map<string, boolean>,
|
||||
from: Config.Path,
|
||||
moduleName: string,
|
||||
): Config.Path {
|
||||
const virtualMockPath = this.getModulePath(from, moduleName);
|
||||
return virtualMocks.get(virtualMockPath)
|
||||
? virtualMockPath
|
||||
: moduleName
|
||||
? this.resolveModule(from, moduleName)
|
||||
: from;
|
||||
}
|
||||
|
||||
private _isModuleResolved(from: Config.Path, moduleName: string): boolean {
|
||||
return !!(
|
||||
this.getModule(moduleName) || this.getMockModule(from, moduleName)
|
||||
);
|
||||
}
|
||||
|
||||
resolveStubModuleName(
|
||||
from: Config.Path,
|
||||
moduleName: string,
|
||||
): Config.Path | null {
|
||||
const dirname = path.dirname(from);
|
||||
const paths = this._options.modulePaths;
|
||||
const extensions = this._options.extensions.slice();
|
||||
const moduleDirectory = this._options.moduleDirectories;
|
||||
const moduleNameMapper = this._options.moduleNameMapper;
|
||||
const resolver = this._options.resolver;
|
||||
const defaultPlatform = this._options.defaultPlatform;
|
||||
|
||||
if (this._supportsNativePlatform) {
|
||||
extensions.unshift(
|
||||
...this._options.extensions.map(ext => '.' + NATIVE_PLATFORM + ext),
|
||||
);
|
||||
}
|
||||
|
||||
if (defaultPlatform) {
|
||||
extensions.unshift(
|
||||
...this._options.extensions.map(ext => '.' + defaultPlatform + ext),
|
||||
);
|
||||
}
|
||||
|
||||
if (moduleNameMapper) {
|
||||
for (const {moduleName: mappedModuleName, regex} of moduleNameMapper) {
|
||||
if (regex.test(moduleName)) {
|
||||
// Note: once a moduleNameMapper matches the name, it must result
|
||||
// in a module, or else an error is thrown.
|
||||
const matches = moduleName.match(regex);
|
||||
const mapModuleName = matches
|
||||
? (moduleName: string) =>
|
||||
moduleName.replace(
|
||||
/\$([0-9]+)/g,
|
||||
(_, index) => matches[parseInt(index, 10)],
|
||||
)
|
||||
: (moduleName: string) => moduleName;
|
||||
|
||||
const possibleModuleNames = Array.isArray(mappedModuleName)
|
||||
? mappedModuleName
|
||||
: [mappedModuleName];
|
||||
let module: string | null = null;
|
||||
for (const possibleModuleName of possibleModuleNames) {
|
||||
const updatedName = mapModuleName(possibleModuleName);
|
||||
|
||||
module =
|
||||
this.getModule(updatedName) ||
|
||||
Resolver.findNodeModule(updatedName, {
|
||||
basedir: dirname,
|
||||
extensions,
|
||||
moduleDirectory,
|
||||
paths,
|
||||
resolver,
|
||||
rootDir: this._options.rootDir,
|
||||
});
|
||||
|
||||
if (module) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!module) {
|
||||
throw createNoMappedModuleFoundError(
|
||||
moduleName,
|
||||
mapModuleName,
|
||||
mappedModuleName,
|
||||
regex,
|
||||
resolver,
|
||||
);
|
||||
}
|
||||
return module;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const createNoMappedModuleFoundError = (
|
||||
moduleName: string,
|
||||
mapModuleName: (moduleName: string) => string,
|
||||
mappedModuleName: string | Array<string>,
|
||||
regex: RegExp,
|
||||
resolver?: ((...args: Array<unknown>) => unknown) | string | null,
|
||||
) => {
|
||||
const mappedAs = Array.isArray(mappedModuleName)
|
||||
? JSON.stringify(mappedModuleName.map(mapModuleName), null, 2)
|
||||
: mappedModuleName;
|
||||
const original = Array.isArray(mappedModuleName)
|
||||
? JSON.stringify(mappedModuleName, null, 6) // using 6 because of misalignment when nested below
|
||||
.slice(0, -1) + ' ]' /// align last bracket correctly as well
|
||||
: mappedModuleName;
|
||||
|
||||
const error = new Error(
|
||||
chalk.red(`${chalk.bold('Configuration error')}:
|
||||
|
||||
Could not locate module ${chalk.bold(moduleName)} mapped as:
|
||||
${chalk.bold(mappedAs)}.
|
||||
|
||||
Please check your configuration for these entries:
|
||||
{
|
||||
"moduleNameMapper": {
|
||||
"${regex.toString()}": "${chalk.bold(original)}"
|
||||
},
|
||||
"resolver": ${chalk.bold(String(resolver))}
|
||||
}`),
|
||||
);
|
||||
|
||||
error.name = '';
|
||||
|
||||
return error;
|
||||
};
|
|
@ -0,0 +1,159 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import * as path from 'path';
|
||||
import chalk = require('chalk');
|
||||
import type {Config} from '@jest/types';
|
||||
import {ValidationError} from 'jest-validate';
|
||||
import Resolver from './resolver';
|
||||
|
||||
const BULLET: string = chalk.bold('\u25cf ');
|
||||
const DOCUMENTATION_NOTE = ` ${chalk.bold('Configuration Documentation:')}
|
||||
https://jestjs.io/docs/configuration
|
||||
`;
|
||||
|
||||
const createValidationError = (message: string) =>
|
||||
new ValidationError(`${BULLET}Validation Error`, message, DOCUMENTATION_NOTE);
|
||||
|
||||
const replaceRootDirInPath = (
|
||||
rootDir: Config.Path,
|
||||
filePath: Config.Path,
|
||||
): string => {
|
||||
if (!/^<rootDir>/.test(filePath)) {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
return path.resolve(
|
||||
rootDir,
|
||||
path.normalize('./' + filePath.substr('<rootDir>'.length)),
|
||||
);
|
||||
};
|
||||
|
||||
const resolveWithPrefix = (
|
||||
resolver: string | undefined | null,
|
||||
{
|
||||
filePath,
|
||||
humanOptionName,
|
||||
optionName,
|
||||
prefix,
|
||||
rootDir,
|
||||
}: {
|
||||
filePath: string;
|
||||
humanOptionName: string;
|
||||
optionName: string;
|
||||
prefix: string;
|
||||
rootDir: Config.Path;
|
||||
},
|
||||
): string => {
|
||||
const fileName = replaceRootDirInPath(rootDir, filePath);
|
||||
let module = Resolver.findNodeModule(`${prefix}${fileName}`, {
|
||||
basedir: rootDir,
|
||||
resolver: resolver || undefined,
|
||||
});
|
||||
if (module) {
|
||||
return module;
|
||||
}
|
||||
|
||||
try {
|
||||
return require.resolve(`${prefix}${fileName}`);
|
||||
} catch {}
|
||||
|
||||
module = Resolver.findNodeModule(fileName, {
|
||||
basedir: rootDir,
|
||||
resolver: resolver || undefined,
|
||||
});
|
||||
if (module) {
|
||||
return module;
|
||||
}
|
||||
|
||||
try {
|
||||
return require.resolve(fileName);
|
||||
} catch {}
|
||||
|
||||
throw createValidationError(
|
||||
` ${humanOptionName} ${chalk.bold(
|
||||
fileName,
|
||||
)} cannot be found. Make sure the ${chalk.bold(
|
||||
optionName,
|
||||
)} configuration option points to an existing node module.`,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds the test environment to use:
|
||||
*
|
||||
* 1. looks for jest-environment-<name> relative to project.
|
||||
* 1. looks for jest-environment-<name> relative to Jest.
|
||||
* 1. looks for <name> relative to project.
|
||||
* 1. looks for <name> relative to Jest.
|
||||
*/
|
||||
export const resolveTestEnvironment = ({
|
||||
rootDir,
|
||||
testEnvironment: filePath,
|
||||
}: {
|
||||
rootDir: Config.Path;
|
||||
testEnvironment: string;
|
||||
}): string =>
|
||||
resolveWithPrefix(undefined, {
|
||||
filePath,
|
||||
humanOptionName: 'Test environment',
|
||||
optionName: 'testEnvironment',
|
||||
prefix: 'jest-environment-',
|
||||
rootDir,
|
||||
});
|
||||
|
||||
/**
|
||||
* Finds the watch plugins to use:
|
||||
*
|
||||
* 1. looks for jest-watch-<name> relative to project.
|
||||
* 1. looks for jest-watch-<name> relative to Jest.
|
||||
* 1. looks for <name> relative to project.
|
||||
* 1. looks for <name> relative to Jest.
|
||||
*/
|
||||
export const resolveWatchPlugin = (
|
||||
resolver: string | undefined | null,
|
||||
{filePath, rootDir}: {filePath: string; rootDir: Config.Path},
|
||||
): string =>
|
||||
resolveWithPrefix(resolver, {
|
||||
filePath,
|
||||
humanOptionName: 'Watch plugin',
|
||||
optionName: 'watchPlugins',
|
||||
prefix: 'jest-watch-',
|
||||
rootDir,
|
||||
});
|
||||
|
||||
/**
|
||||
* Finds the runner to use:
|
||||
*
|
||||
* 1. looks for jest-runner-<name> relative to project.
|
||||
* 1. looks for jest-runner-<name> relative to Jest.
|
||||
* 1. looks for <name> relative to project.
|
||||
* 1. looks for <name> relative to Jest.
|
||||
*/
|
||||
export const resolveRunner = (
|
||||
resolver: string | undefined | null,
|
||||
{filePath, rootDir}: {filePath: string; rootDir: Config.Path},
|
||||
): string =>
|
||||
resolveWithPrefix(resolver, {
|
||||
filePath,
|
||||
humanOptionName: 'Jest Runner',
|
||||
optionName: 'runner',
|
||||
prefix: 'jest-runner-',
|
||||
rootDir,
|
||||
});
|
||||
|
||||
export const resolveSequencer = (
|
||||
resolver: string | undefined | null,
|
||||
{filePath, rootDir}: {filePath: string; rootDir: Config.Path},
|
||||
): string =>
|
||||
resolveWithPrefix(resolver, {
|
||||
filePath,
|
||||
humanOptionName: 'Jest Sequencer',
|
||||
optionName: 'testSequencer',
|
||||
prefix: 'jest-sequencer-',
|
||||
rootDir,
|
||||
});
|
|
@ -7,6 +7,7 @@
|
|||
"references": [
|
||||
{"path": "../jest-haste-map"},
|
||||
{"path": "../jest-types"},
|
||||
{"path": "../jest-util"}
|
||||
{"path": "../jest-util"},
|
||||
{"path": "../jest-validate"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
"emittery": "^0.8.1",
|
||||
"exit": "^0.1.2",
|
||||
"graceful-fs": "^4.2.4",
|
||||
"jest-config": "^27.0.1",
|
||||
"jest-docblock": "^27.0.1",
|
||||
"jest-haste-map": "^27.0.1",
|
||||
"jest-leak-detector": "^27.0.1",
|
||||
|
|
|
@ -9,7 +9,13 @@ import chalk = require('chalk');
|
|||
import Emittery = require('emittery');
|
||||
import exit = require('exit');
|
||||
import throat from 'throat';
|
||||
import type {SerializableError, TestResult} from '@jest/test-result';
|
||||
import type {
|
||||
SerializableError,
|
||||
Test,
|
||||
TestEvents,
|
||||
TestFileEvent,
|
||||
TestResult,
|
||||
} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import {deepCyclicCopy} from 'jest-util';
|
||||
import {PromiseWithCustomMessage, Worker} from 'jest-worker';
|
||||
|
@ -19,14 +25,14 @@ import type {
|
|||
OnTestFailure,
|
||||
OnTestStart,
|
||||
OnTestSuccess,
|
||||
Test,
|
||||
TestEvents,
|
||||
TestFileEvent,
|
||||
TestRunnerContext,
|
||||
TestRunnerOptions,
|
||||
TestWatcher,
|
||||
} from './types';
|
||||
|
||||
// TODO: remove re-export in Jest 28
|
||||
export type {Test, TestFileEvent, TestEvents} from '@jest/test-result';
|
||||
|
||||
const TEST_WORKER_PATH = require.resolve('./testWorker');
|
||||
|
||||
interface WorkerInterface extends Worker {
|
||||
|
@ -34,14 +40,12 @@ interface WorkerInterface extends Worker {
|
|||
}
|
||||
|
||||
export type {
|
||||
Test,
|
||||
OnTestFailure,
|
||||
OnTestStart,
|
||||
OnTestSuccess,
|
||||
TestWatcher,
|
||||
TestRunnerContext,
|
||||
TestRunnerOptions,
|
||||
TestFileEvent,
|
||||
} from './types';
|
||||
|
||||
export default class TestRunner {
|
||||
|
|
|
@ -18,17 +18,16 @@ import {
|
|||
getConsoleOutput,
|
||||
} from '@jest/console';
|
||||
import type {JestEnvironment} from '@jest/environment';
|
||||
import type {TestResult} from '@jest/test-result';
|
||||
import type {TestFileEvent, TestResult} from '@jest/test-result';
|
||||
import {createScriptTransformer} from '@jest/transform';
|
||||
import type {Config} from '@jest/types';
|
||||
import {getTestEnvironment} from 'jest-config';
|
||||
import * as docblock from 'jest-docblock';
|
||||
import LeakDetector from 'jest-leak-detector';
|
||||
import {formatExecError} from 'jest-message-util';
|
||||
import type Resolver from 'jest-resolve';
|
||||
import Resolver, {resolveTestEnvironment} from 'jest-resolve';
|
||||
import type RuntimeClass from 'jest-runtime';
|
||||
import {ErrorWithStack, interopRequireDefault, setGlobal} from 'jest-util';
|
||||
import type {TestFileEvent, TestFramework, TestRunnerContext} from './types';
|
||||
import type {TestFramework, TestRunnerContext} from './types';
|
||||
|
||||
type RunTestInternalResult = {
|
||||
leakDetector: LeakDetector | null;
|
||||
|
@ -97,7 +96,7 @@ async function runTestInternal(
|
|||
)}"`,
|
||||
);
|
||||
}
|
||||
testEnvironment = getTestEnvironment({
|
||||
testEnvironment = resolveTestEnvironment({
|
||||
...config,
|
||||
testEnvironment: customEnvironment,
|
||||
});
|
||||
|
|
|
@ -7,7 +7,11 @@
|
|||
*/
|
||||
|
||||
import exit = require('exit');
|
||||
import type {SerializableError, TestResult} from '@jest/test-result';
|
||||
import type {
|
||||
SerializableError,
|
||||
TestFileEvent,
|
||||
TestResult,
|
||||
} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import HasteMap, {SerializableModuleMap} from 'jest-haste-map';
|
||||
import {separateMessageFromStack} from 'jest-message-util';
|
||||
|
@ -15,11 +19,7 @@ import type Resolver from 'jest-resolve';
|
|||
import Runtime from 'jest-runtime';
|
||||
import {messageParent} from 'jest-worker';
|
||||
import runTest from './runTest';
|
||||
import type {
|
||||
ErrorWithCode,
|
||||
TestFileEvent,
|
||||
TestRunnerSerializedContext,
|
||||
} from './types';
|
||||
import type {ErrorWithCode, TestRunnerSerializedContext} from './types';
|
||||
|
||||
export type SerializableResolver = {
|
||||
config: Config.ProjectConfig;
|
||||
|
|
|
@ -8,28 +8,15 @@
|
|||
import Emittery = require('emittery');
|
||||
import type {JestEnvironment} from '@jest/environment';
|
||||
import type {
|
||||
AssertionResult,
|
||||
SerializableError,
|
||||
Test,
|
||||
TestFileEvent,
|
||||
TestResult,
|
||||
} from '@jest/test-result';
|
||||
import type {Config} from '@jest/types';
|
||||
import type {FS as HasteFS, ModuleMap} from 'jest-haste-map';
|
||||
import type Resolver from 'jest-resolve';
|
||||
import type RuntimeType from 'jest-runtime';
|
||||
|
||||
export type ErrorWithCode = Error & {code?: string};
|
||||
export type Test = {
|
||||
context: Context;
|
||||
duration?: number;
|
||||
path: Config.Path;
|
||||
};
|
||||
|
||||
export type Context = {
|
||||
config: Config.ProjectConfig;
|
||||
hasteFS: HasteFS;
|
||||
moduleMap: ModuleMap;
|
||||
resolver: Resolver;
|
||||
};
|
||||
|
||||
export type OnTestStart = (test: Test) => Promise<void>;
|
||||
export type OnTestFailure = (
|
||||
|
@ -41,19 +28,6 @@ export type OnTestSuccess = (
|
|||
testResult: TestResult,
|
||||
) => Promise<void>;
|
||||
|
||||
// Typings for `sendMessageToJest` events
|
||||
export type TestEvents = {
|
||||
'test-file-start': [Test];
|
||||
'test-file-success': [Test, TestResult];
|
||||
'test-file-failure': [Test, SerializableError];
|
||||
'test-case-result': [Config.Path, AssertionResult];
|
||||
};
|
||||
|
||||
export type TestFileEvent<T extends keyof TestEvents = keyof TestEvents> = (
|
||||
eventName: T,
|
||||
args: TestEvents[T],
|
||||
) => unknown;
|
||||
|
||||
export type TestFramework = (
|
||||
globalConfig: Config.GlobalConfig,
|
||||
config: Config.ProjectConfig,
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
"outDir": "build"
|
||||
},
|
||||
"references": [
|
||||
{"path": "../jest-config"},
|
||||
{"path": "../jest-console"},
|
||||
{"path": "../jest-docblock"},
|
||||
{"path": "../jest-environment"},
|
||||
|
|
|
@ -24,6 +24,9 @@ export type {
|
|||
SnapshotSummary,
|
||||
Status,
|
||||
Suite,
|
||||
Test,
|
||||
TestEvents,
|
||||
TestFileEvent,
|
||||
TestResult,
|
||||
TestCaseResult,
|
||||
V8CoverageResult,
|
||||
|
|
|
@ -9,6 +9,8 @@ import type {V8Coverage} from 'collect-v8-coverage';
|
|||
import type {CoverageMap, CoverageMapData} from 'istanbul-lib-coverage';
|
||||
import type {ConsoleBuffer} from '@jest/console';
|
||||
import type {Config, TestResult, TransformTypes} from '@jest/types';
|
||||
import type {FS as HasteFS, ModuleMap} from 'jest-haste-map';
|
||||
import type Resolver from 'jest-resolve';
|
||||
|
||||
export interface RuntimeTransformResult extends TransformTypes.TransformResult {
|
||||
wrapperLength: number;
|
||||
|
@ -175,3 +177,29 @@ export type SnapshotSummary = {
|
|||
unmatched: number;
|
||||
updated: number;
|
||||
};
|
||||
|
||||
export type Test = {
|
||||
context: Context;
|
||||
duration?: number;
|
||||
path: Config.Path;
|
||||
};
|
||||
|
||||
type Context = {
|
||||
config: Config.ProjectConfig;
|
||||
hasteFS: HasteFS;
|
||||
moduleMap: ModuleMap;
|
||||
resolver: Resolver;
|
||||
};
|
||||
|
||||
// Typings for `sendMessageToJest` events
|
||||
export type TestEvents = {
|
||||
'test-file-start': [Test];
|
||||
'test-file-success': [Test, TestResult];
|
||||
'test-file-failure': [Test, SerializableError];
|
||||
'test-case-result': [Config.Path, AssertionResult];
|
||||
};
|
||||
|
||||
export type TestFileEvent<T extends keyof TestEvents = keyof TestEvents> = (
|
||||
eventName: T,
|
||||
args: TestEvents[T],
|
||||
) => unknown;
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
"@jest/test-result": "^27.0.1",
|
||||
"graceful-fs": "^4.2.4",
|
||||
"jest-haste-map": "^27.0.1",
|
||||
"jest-runner": "^27.0.1",
|
||||
"jest-runtime": "^27.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
*/
|
||||
|
||||
import * as fs from 'graceful-fs';
|
||||
import type {AggregatedResult} from '@jest/test-result';
|
||||
import type {AggregatedResult, Test} from '@jest/test-result';
|
||||
import HasteMap from 'jest-haste-map';
|
||||
import type {Test} from 'jest-runner';
|
||||
import type {Context} from 'jest-runtime';
|
||||
|
||||
const FAIL = 0;
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
},
|
||||
"references": [
|
||||
{"path": "../jest-haste-map"},
|
||||
{"path": "../jest-runner"},
|
||||
{"path": "../jest-runtime"},
|
||||
{"path": "../jest-test-result"}
|
||||
]
|
||||
|
|
|
@ -773,18 +773,18 @@ class ScriptTransformer {
|
|||
},
|
||||
},
|
||||
);
|
||||
const module: ModuleType = await requireOrImportModule(
|
||||
moduleName,
|
||||
applyInteropRequireDefault,
|
||||
);
|
||||
|
||||
if (!callback) {
|
||||
revertHook();
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
try {
|
||||
const module: ModuleType = await requireOrImportModule(
|
||||
moduleName,
|
||||
applyInteropRequireDefault,
|
||||
);
|
||||
|
||||
if (!callback) {
|
||||
revertHook();
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
const cbResult = callback(module);
|
||||
|
||||
if (isPromise(cbResult)) {
|
||||
|
@ -792,11 +792,11 @@ class ScriptTransformer {
|
|||
() => module,
|
||||
);
|
||||
}
|
||||
|
||||
return module;
|
||||
} finally {
|
||||
revertHook();
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
shouldTransform(filename: Config.Path): boolean {
|
||||
|
|
|
@ -2761,7 +2761,6 @@ __metadata:
|
|||
"@types/graceful-fs": ^4.1.3
|
||||
graceful-fs: ^4.2.4
|
||||
jest-haste-map: ^27.0.1
|
||||
jest-runner: ^27.0.1
|
||||
jest-runtime: ^27.0.1
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
@ -13262,7 +13261,6 @@ fsevents@^1.2.7:
|
|||
jest-each: ^27.0.1
|
||||
jest-matcher-utils: ^27.0.1
|
||||
jest-message-util: ^27.0.1
|
||||
jest-runner: ^27.0.1
|
||||
jest-runtime: ^27.0.1
|
||||
jest-snapshot: ^27.0.1
|
||||
jest-snapshot-serializer-raw: ^1.1.0
|
||||
|
@ -13698,6 +13696,7 @@ fsevents@^1.2.7:
|
|||
jest-haste-map: ^27.0.1
|
||||
jest-pnp-resolver: ^1.2.2
|
||||
jest-util: ^27.0.1
|
||||
jest-validate: ^27.0.1
|
||||
resolve: ^1.20.0
|
||||
slash: ^3.0.0
|
||||
languageName: unknown
|
||||
|
@ -13731,7 +13730,6 @@ fsevents@^1.2.7:
|
|||
emittery: ^0.8.1
|
||||
exit: ^0.1.2
|
||||
graceful-fs: ^4.2.4
|
||||
jest-config: ^27.0.1
|
||||
jest-docblock: ^27.0.1
|
||||
jest-haste-map: ^27.0.1
|
||||
jest-jasmine2: ^27.0.1
|
||||
|
|
Loading…
Reference in New Issue