Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
- `[jest-environment-jsdom]` [**BREAKING**] Upgrade JSDOM from v11 to v15 ([#8851](https://github.com/facebook/jest/pull/8851))
- `[jest-util]` [**BREAKING**] Remove deprecated exports ([#8863](https://github.com/facebook/jest/pull/8863))
- `[jest-validate]` [**BREAKING**] Use ESM exports ([#8874](https://github.com/facebook/jest/pull/8874))
- `[jest-types]` Mark `InitialOptions` as `Partial` ([#8848](https://github.com/facebook/jest/pull/8848))
- `[jest-config]` Refactor `normalize` to be more type safe ([#8848](https://github.com/facebook/jest/pull/8848))

### Performance

Expand Down
41 changes: 22 additions & 19 deletions packages/jest-config/src/normalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const createConfigError = (message: string) =>

// TS 3.5 forces us to split these into 2
const mergeModuleNameMapperWithPreset = (
options: Config.InitialOptions,
options: Config.InitialOptionsWithRootDir,
preset: Config.InitialOptions,
) => {
if (options['moduleNameMapper'] && preset['moduleNameMapper']) {
Expand All @@ -61,7 +61,7 @@ const mergeModuleNameMapperWithPreset = (
};

const mergeTransformWithPreset = (
options: Config.InitialOptions,
options: Config.InitialOptionsWithRootDir,
preset: Config.InitialOptions,
) => {
if (options['transform'] && preset['transform']) {
Expand All @@ -88,9 +88,9 @@ const mergeGlobalsWithPreset = (
};

const setupPreset = (
options: Config.InitialOptions,
options: Config.InitialOptionsWithRootDir,
optionsPreset: string,
): Config.InitialOptions => {
): Config.InitialOptionsWithRootDir => {
let preset: Config.InitialOptions;
const presetPath = replaceRootDirInPath(options.rootDir, optionsPreset);
const presetModule = Resolver.findNodeModule(
Expand Down Expand Up @@ -168,7 +168,7 @@ const setupPreset = (
return {...preset, ...options};
};

const setupBabelJest = (options: Config.InitialOptions) => {
const setupBabelJest = (options: Config.InitialOptionsWithRootDir) => {
const transform = options.transform;
let babelJest;
if (transform) {
Expand Down Expand Up @@ -210,7 +210,7 @@ const setupBabelJest = (options: Config.InitialOptions) => {
};

const normalizeCollectCoverageOnlyFrom = (
options: Config.InitialOptions &
options: Config.InitialOptionsWithRootDir &
Required<Pick<Config.InitialOptions, 'collectCoverageOnlyFrom'>>,
key: keyof Pick<Config.InitialOptions, 'collectCoverageOnlyFrom'>,
) => {
Expand Down Expand Up @@ -263,7 +263,7 @@ const normalizeCollectCoverageFrom = (
};

const normalizeUnmockedModulePathPatterns = (
options: Config.InitialOptions,
options: Config.InitialOptionsWithRootDir,
key: keyof Pick<
Config.InitialOptions,
| 'coveragePathIgnorePatterns'
Expand All @@ -285,8 +285,8 @@ const normalizeUnmockedModulePathPatterns = (
);

const normalizePreprocessor = (
options: Config.InitialOptions,
): Config.InitialOptions => {
options: Config.InitialOptionsWithRootDir,
): Config.InitialOptionsWithRootDir => {
if (options.scriptPreprocessor && options.transform) {
throw createConfigError(
` Options: ${chalk.bold('scriptPreprocessor')} and ${chalk.bold(
Expand Down Expand Up @@ -323,10 +323,10 @@ const normalizePreprocessor = (
};

const normalizeMissingOptions = (
options: Config.InitialOptions,
options: Config.InitialOptionsWithRootDir,
configPath: Config.Path | null | undefined,
projectIndex: number,
): Config.InitialOptions => {
): Config.InitialOptionsWithRootDir => {
if (!options.name) {
options.name = createHash('md5')
.update(options.rootDir)
Expand All @@ -345,9 +345,9 @@ const normalizeMissingOptions = (

const normalizeRootDir = (
options: Config.InitialOptions,
): Config.InitialOptions => {
): Config.InitialOptionsWithRootDir => {
// Assert that there *is* a rootDir
if (!options.hasOwnProperty('rootDir')) {
if (!options.rootDir) {
throw createConfigError(
` Configuration option ${chalk.bold('rootDir')} must be specified.`,
);
Expand All @@ -361,10 +361,13 @@ const normalizeRootDir = (
// ignored
}

return options;
return {
...options,
rootDir: options.rootDir,
};
};

const normalizeReporters = (options: Config.InitialOptions) => {
const normalizeReporters = (options: Config.InitialOptionsWithRootDir) => {
const reporters = options.reporters;
if (!reporters || !Array.isArray(reporters)) {
return options;
Expand Down Expand Up @@ -441,15 +444,15 @@ const showTestPathPatternError = (testPathPattern: string) => {
};

export default function normalize(
options: Config.InitialOptions,
initialOptions: Config.InitialOptions,
argv: Config.Argv,
configPath?: Config.Path | null,
projectIndex: number = Infinity,
): {
hasDeprecationWarnings: boolean;
options: AllOptions;
} {
const {hasDeprecationWarnings} = validate(options, {
const {hasDeprecationWarnings} = validate(initialOptions, {
comment: DOCUMENTATION_NOTE,
deprecatedConfig: DEPRECATED_CONFIG,
exampleConfig: VALID_CONFIG,
Expand All @@ -465,10 +468,10 @@ export default function normalize(
],
});

options = normalizePreprocessor(
let options = normalizePreprocessor(
normalizeReporters(
normalizeMissingOptions(
normalizeRootDir(setFromArgv(options, argv)),
normalizeRootDir(setFromArgv(initialOptions, argv)),
configPath,
projectIndex,
),
Expand Down
201 changes: 102 additions & 99 deletions packages/jest-types/src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,117 +115,120 @@ export type DisplayName =
color: DisplayNameColor;
};

export type InitialOptions = {
automock?: boolean;
bail?: boolean | number;
browser?: boolean;
cache?: boolean;
cacheDirectory?: Path;
clearMocks?: boolean;
changedFilesWithAncestor?: boolean;
changedSince?: string;
collectCoverage?: boolean;
collectCoverageFrom?: Array<Glob>;
collectCoverageOnlyFrom?: {
export type InitialOptionsWithRootDir = InitialOptions &
Required<Pick<InitialOptions, 'rootDir'>>;

export type InitialOptions = Partial<{
automock: boolean;
bail: boolean | number;
browser: boolean;
cache: boolean;
cacheDirectory: Path;
clearMocks: boolean;
changedFilesWithAncestor: boolean;
changedSince: string;
collectCoverage: boolean;
collectCoverageFrom: Array<Glob>;
collectCoverageOnlyFrom: {
[key: string]: boolean;
};
coverageDirectory?: string;
coveragePathIgnorePatterns?: Array<string>;
coverageReporters?: Array<string>;
coverageThreshold?: {
coverageDirectory: string;
coveragePathIgnorePatterns: Array<string>;
coverageReporters: Array<string>;
coverageThreshold: {
global: {
[key: string]: number;
};
};
dependencyExtractor?: string;
detectLeaks?: boolean;
detectOpenHandles?: boolean;
displayName?: DisplayName;
expand?: boolean;
extraGlobals?: Array<string>;
filter?: Path;
findRelatedTests?: boolean;
forceCoverageMatch?: Array<Glob>;
forceExit?: boolean;
json?: boolean;
globals?: ConfigGlobals;
globalSetup?: string | null | undefined;
globalTeardown?: string | null | undefined;
haste?: HasteConfig;
reporters?: Array<string | ReporterConfig>;
logHeapUsage?: boolean;
lastCommit?: boolean;
listTests?: boolean;
mapCoverage?: boolean;
maxConcurrency?: number;
dependencyExtractor: string;
detectLeaks: boolean;
detectOpenHandles: boolean;
displayName: DisplayName;
expand: boolean;
extraGlobals: Array<string>;
filter: Path;
findRelatedTests: boolean;
forceCoverageMatch: Array<Glob>;
forceExit: boolean;
json: boolean;
globals: ConfigGlobals;
globalSetup: string | null | undefined;
globalTeardown: string | null | undefined;
haste: HasteConfig;
reporters: Array<string | ReporterConfig>;
logHeapUsage: boolean;
lastCommit: boolean;
listTests: boolean;
mapCoverage: boolean;
maxConcurrency: number;
maxWorkers: number | string;
moduleDirectories?: Array<string>;
moduleFileExtensions?: Array<string>;
moduleLoader?: Path;
moduleNameMapper?: {
moduleDirectories: Array<string>;
moduleFileExtensions: Array<string>;
moduleLoader: Path;
moduleNameMapper: {
[key: string]: string;
};
modulePathIgnorePatterns?: Array<string>;
modulePaths?: Array<string>;
name?: string;
noStackTrace?: boolean;
notify?: boolean;
notifyMode?: string;
onlyChanged?: boolean;
outputFile?: Path;
passWithNoTests?: boolean;
preprocessorIgnorePatterns?: Array<Glob>;
preset?: string | null | undefined;
prettierPath?: string | null | undefined;
projects?: Array<Glob>;
replname?: string | null | undefined;
resetMocks?: boolean;
resetModules?: boolean;
resolver?: Path | null | undefined;
restoreMocks?: boolean;
modulePathIgnorePatterns: Array<string>;
modulePaths: Array<string>;
name: string;
noStackTrace: boolean;
notify: boolean;
notifyMode: string;
onlyChanged: boolean;
outputFile: Path;
passWithNoTests: boolean;
preprocessorIgnorePatterns: Array<Glob>;
preset: string | null | undefined;
prettierPath: string | null | undefined;
projects: Array<Glob>;
replname: string | null | undefined;
resetMocks: boolean;
resetModules: boolean;
resolver: Path | null | undefined;
restoreMocks: boolean;
rootDir: Path;
roots?: Array<Path>;
runner?: string;
runTestsByPath?: boolean;
scriptPreprocessor?: string;
setupFiles?: Array<Path>;
setupTestFrameworkScriptFile?: Path;
setupFilesAfterEnv?: Array<Path>;
silent?: boolean;
skipFilter?: boolean;
skipNodeResolution?: boolean;
snapshotResolver?: Path;
snapshotSerializers?: Array<Path>;
errorOnDeprecated?: boolean;
testEnvironment?: string;
testEnvironmentOptions?: Record<string, any>;
testFailureExitCode?: string | number;
testLocationInResults?: boolean;
testMatch?: Array<Glob>;
testNamePattern?: string;
testPathDirs?: Array<Path>;
testPathIgnorePatterns?: Array<string>;
testRegex?: string | Array<string>;
testResultsProcessor?: string | null | undefined;
testRunner?: string;
testSequencer?: string;
testURL?: string;
testTimeout?: number;
timers?: 'real' | 'fake';
transform?: {
roots: Array<Path>;
runner: string;
runTestsByPath: boolean;
scriptPreprocessor: string;
setupFiles: Array<Path>;
setupTestFrameworkScriptFile: Path;
setupFilesAfterEnv: Array<Path>;
silent: boolean;
skipFilter: boolean;
skipNodeResolution: boolean;
snapshotResolver: Path;
snapshotSerializers: Array<Path>;
errorOnDeprecated: boolean;
testEnvironment: string;
testEnvironmentOptions: Record<string, any>;
testFailureExitCode: string | number;
testLocationInResults: boolean;
testMatch: Array<Glob>;
testNamePattern: string;
testPathDirs: Array<Path>;
testPathIgnorePatterns: Array<string>;
testRegex: string | Array<string>;
testResultsProcessor: string | null | undefined;
testRunner: string;
testSequencer: string;
testURL: string;
testTimeout: number;
timers: 'real' | 'fake';
transform: {
[regex: string]: Path | TransformerConfig;
};
transformIgnorePatterns?: Array<Glob>;
watchPathIgnorePatterns?: Array<string>;
unmockedModulePathPatterns?: Array<string>;
updateSnapshot?: boolean;
useStderr?: boolean;
verbose?: boolean | null | undefined;
watch?: boolean;
watchAll?: boolean;
watchman?: boolean;
watchPlugins?: Array<string | [string, Record<string, any>]>;
};
transformIgnorePatterns: Array<Glob>;
watchPathIgnorePatterns: Array<string>;
unmockedModulePathPatterns: Array<string>;
updateSnapshot: boolean;
useStderr: boolean;
verbose: boolean | null | undefined;
watch: boolean;
watchAll: boolean;
watchman: boolean;
watchPlugins: Array<string | [string, Record<string, any>]>;
}>;

export type SnapshotUpdateState = 'all' | 'new' | 'none';

Expand Down