From 455d72464b1a42bf857f42296a0213fca963d494 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 23 Feb 2019 13:01:53 +0100 Subject: [PATCH 01/15] chore: migrate jest-runtime to TypeScript --- packages/jest-circus/package.json | 1 + .../legacy-code-todo-rewrite/jestAdapter.ts | 5 +- packages/jest-circus/tsconfig.json | 11 +- packages/jest-environment/.npmignore | 3 + packages/jest-environment/package.json | 23 ++ packages/jest-environment/src/index.ts | 266 +++++++++++++ packages/jest-environment/tsconfig.json | 12 + packages/jest-resolve/src/index.ts | 4 +- packages/jest-resolve/src/types.ts | 6 +- packages/jest-runtime/package.json | 4 + .../jest-runtime/src/cli/{args.js => args.ts} | 6 +- .../src/cli/{index.js => index.ts} | 30 +- .../src/{helpers.js => helpers.ts} | 9 +- .../jest-runtime/src/{index.js => index.ts} | 370 +++++++++--------- packages/jest-runtime/src/types.ts | 17 + packages/jest-runtime/src/version.ts | 9 + packages/jest-runtime/tsconfig.json | 20 + .../jest-transform/src/ScriptTransformer.ts | 3 +- packages/jest-transform/src/index.ts | 2 +- .../jest-transform/src/shouldInstrument.ts | 4 +- packages/jest-transform/src/types.ts | 15 +- packages/jest-types/src/Argv.ts | 100 +++++ packages/jest-types/src/Config.ts | 2 +- packages/jest-types/src/Environment.ts | 44 --- packages/jest-types/src/index.ts | 4 +- 25 files changed, 689 insertions(+), 281 deletions(-) create mode 100644 packages/jest-environment/.npmignore create mode 100644 packages/jest-environment/package.json create mode 100644 packages/jest-environment/src/index.ts create mode 100644 packages/jest-environment/tsconfig.json rename packages/jest-runtime/src/cli/{args.js => args.ts} (91%) rename packages/jest-runtime/src/cli/{index.js => index.ts} (79%) rename packages/jest-runtime/src/{helpers.js => helpers.ts} (91%) rename packages/jest-runtime/src/{index.js => index.ts} (79%) create mode 100644 packages/jest-runtime/src/types.ts create mode 100644 packages/jest-runtime/src/version.ts create mode 100644 packages/jest-runtime/tsconfig.json create mode 100644 packages/jest-types/src/Argv.ts delete mode 100644 packages/jest-types/src/Environment.ts diff --git a/packages/jest-circus/package.json b/packages/jest-circus/package.json index 1986ebe211cf..d137fb0d5273 100644 --- a/packages/jest-circus/package.json +++ b/packages/jest-circus/package.json @@ -11,6 +11,7 @@ "types": "build/index.d.ts", "dependencies": { "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.1.0", "@jest/types": "^24.1.0", "@types/node": "*", "chalk": "^2.0.1", diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index 84f32c39e2f4..8011efd64a31 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -6,7 +6,8 @@ */ import path from 'path'; -import {Config, TestResult, Environment} from '@jest/types'; +import {Config, TestResult} from '@jest/types'; +import {JestEnvironment} from '@jest/environment'; // @ts-ignore TODO Remove ignore when jest-runtime is migrated to ts import Runtime from 'jest-runtime'; // eslint-disable-line import/no-extraneous-dependencies import {SnapshotState} from 'jest-snapshot'; @@ -16,7 +17,7 @@ const FRAMEWORK_INITIALIZER = require.resolve('./jestAdapterInit'); const jestAdapter = async ( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, - environment: Environment.$JestEnvironment, + environment: JestEnvironment, runtime: Runtime, testPath: string, ): Promise => { diff --git a/packages/jest-circus/tsconfig.json b/packages/jest-circus/tsconfig.json index 3cb4125e6ac7..14772ef4ab7c 100644 --- a/packages/jest-circus/tsconfig.json +++ b/packages/jest-circus/tsconfig.json @@ -4,5 +4,14 @@ "outDir": "build", "rootDir": "src" }, - "references": [{"path": "../jest-types"}, {"path": "../jest-snapshot"}, {"path": "../jest-matcher-utils"}, {"path": "../jest-message-util"}, {"path": "../jest-util"}, {"path": "../pretty-format"}, {"path": "../jest-diff"}] + "references": [ + {"path": "../jest-environment"}, + {"path": "../jest-types"}, + {"path": "../jest-snapshot"}, + {"path": "../jest-matcher-utils"}, + {"path": "../jest-message-util"}, + {"path": "../jest-util"}, + {"path": "../pretty-format"}, + {"path": "../jest-diff"} + ] } diff --git a/packages/jest-environment/.npmignore b/packages/jest-environment/.npmignore new file mode 100644 index 000000000000..85e48fe7b0a4 --- /dev/null +++ b/packages/jest-environment/.npmignore @@ -0,0 +1,3 @@ +**/__mocks__/** +**/__tests__/** +src diff --git a/packages/jest-environment/package.json b/packages/jest-environment/package.json new file mode 100644 index 000000000000..beb221061281 --- /dev/null +++ b/packages/jest-environment/package.json @@ -0,0 +1,23 @@ +{ + "name": "@jest/environment", + "version": "24.1.0", + "repository": { + "type": "git", + "url": "https://github.com/facebook/jest.git", + "directory": "packages/jest-environment" + }, + "license": "MIT", + "main": "build/index.js", + "types": "build/index.d.ts", + "dependencies": { + "@jest/transform": "^24.1.0", + "@jest/types": "^24.1.0", + "@types/istanbul-lib-coverage": "^1.1.0", + "@types/node": "*", + "jest-mock": "^24.0.0" + }, + "engines": { + "node": ">= 6" + }, + "gitHead": "b16789230fd45056a7f2fa199bae06c7a1780deb" +} diff --git a/packages/jest-environment/src/index.ts b/packages/jest-environment/src/index.ts new file mode 100644 index 000000000000..aa044f28afb0 --- /dev/null +++ b/packages/jest-environment/src/index.ts @@ -0,0 +1,266 @@ +/** + * 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 {Script} from 'vm'; +import {Config} from '@jest/types'; +import moduleMocker from 'jest-mock'; +import {ScriptTransformer} from '@jest/transform'; +// eslint-disable-next-line import/no-extraneous-dependencies +import {CoverageMapData} from 'istanbul-lib-coverage'; + +export type EnvironmentContext = { + console?: Console; + testPath?: Config.Path; +}; + +// TODO: Get rid of this at some point +type JasmineType = {_DEFAULT_TIMEOUT_INTERVAL?: number; addMatchers: Function}; + +// TODO: type this better: https://nodejs.org/api/modules.html#modules_the_module_wrapper +type ModuleWrapper = (...args: Array) => unknown; + +export interface JestEnvironment { + new ( + config: Config.ProjectConfig, + context?: EnvironmentContext, + ): JestEnvironment; + runScript( + script: Script, + ): {[ScriptTransformer.EVAL_RESULT_VARIABLE]: ModuleWrapper} | null; + // TODO: Maybe add `| Window` in the future? + global: NodeJS.Global & {__coverage__: CoverageMapData; jasmine: JasmineType}; + // TODO: When `jest-util` is ESM, this can just be `fakeTimers: import('jest-util').FakeTimers` + fakeTimers: { + clearAllTimers(): void; + runAllImmediates(): void; + runAllTicks(): void; + runAllTimers(): void; + advanceTimersByTime(msToRun: number): void; + runOnlyPendingTimers(): void; + runWithRealTimers(callback: () => void): void; + getTimerCount(): number; + useFakeTimers(): void; + useRealTimers(): void; + }; + testFilePath: Config.Path; + moduleMocker: typeof moduleMocker; + setup(): Promise; + teardown(): Promise; +} + +export type Module = typeof module; + +export interface LocalModuleRequire extends NodeRequire { + requireActual(moduleName: string): unknown; + requireMock(moduleName: string): unknown; +} + +// TODO: Move to some separate package +export interface Jest { + /** + * Provides a way to add Jasmine-compatible matchers into your Jest context. + * + * @deprecated Use `expect.extend` instead + */ + addMatchers(matchers: Object): void; + /** + * Disables automatic mocking in the module loader. + */ + autoMockOff(): Jest; + /** + * Enables automatic mocking in the module loader. + */ + autoMockOn(): Jest; + /** + * Clears the mock.calls and mock.instances properties of all mocks. + * Equivalent to calling .mockClear() on every mocked function. + */ + clearAllMocks(): Jest; + /** + * Removes any pending timers from the timer system. If any timers have been + * scheduled, they will be cleared and will never have the opportunity to + * execute in the future. + */ + clearAllTimers(): void; + /** + * Indicates that the module system should never return a mocked version + * of the specified module, including all of the specified module's + * dependencies. + */ + deepUnmock(moduleName: string): Jest; + /** + * Disables automatic mocking in the module loader. + * + * After this method is called, all `require()`s will return the real + * versions of each module (rather than a mocked version). + */ + disableAutomock(): Jest; + /** + * When using `babel-jest`, calls to mock will automatically be hoisted to + * the top of the code block. Use this method if you want to explicitly avoid + * this behavior. + */ + doMock(moduleName: string, moduleFactory?: () => unknown): Jest; + /** + * Indicates that the module system should never return a mocked version + * of the specified module from require() (e.g. that it should always return + * the real module). + */ + dontMock(moduleName: string): Jest; + /** + * Enables automatic mocking in the module loader. + */ + enableAutomock(): Jest; + /** + * Creates a mock function. Optionally takes a mock implementation. + */ + fn: typeof moduleMocker.fn; + /** + * Given the name of a module, use the automatic mocking system to generate a + * mocked version of the module for you. + * + * This is useful when you want to create a manual mock that extends the + * automatic mock's behavior. + */ + genMockFromModule(moduleName: string): unknown; + /** + * Determines if the given function is a mocked function. + */ + isMockFunction(fn: Function): fn is ReturnType; + /** + * Mocks a module with an auto-mocked version when it is being required. + */ + mock( + moduleName: string, + moduleFactory?: () => unknown, + options?: {virtual?: boolean}, + ): Jest; + /** + * Returns the actual module instead of a mock, bypassing all checks on + * whether the module should receive a mock implementation or not. + */ + requireActual: (moduleName: string) => unknown; + /** + * Returns a mock module instead of the actual module, bypassing all checks + * on whether the module should be required normally or not. + */ + requireMock: (moduleName: string) => unknown; + /** + * Resets the state of all mocks. + * Equivalent to calling .mockReset() on every mocked function. + */ + resetAllMocks(): Jest; + /** + * Resets the module registry - the cache of all required modules. This is + * useful to isolate modules where local state might conflict between tests. + * + * @deprecated Use `jest.resetModules()` + */ + resetModuleRegistry(): Jest; + /** + * Resets the module registry - the cache of all required modules. This is + * useful to isolate modules where local state might conflict between tests. + */ + resetModules(): Jest; + /** + * Restores all mocks back to their original value. Equivalent to calling + * `.mockRestore` on every mocked function. + * + * Beware that jest.restoreAllMocks() only works when mock was created with + * jest.spyOn; other mocks will require you to manually restore them. + */ + restoreAllMocks(): Jest; + /** + * Runs failed tests n-times until they pass or until the max number of + * retries is exhausted. This only works with `jest-circus`! + */ + retryTimes(numRetries: number): Jest; + /** + * Exhausts tasks queued by setImmediate(). + */ + runAllImmediates(): void; + /** + * Exhausts the micro-task queue (usually interfaced in node via + * process.nextTick). + */ + runAllTicks(): void; + /** + * Exhausts the macro-task queue (i.e., all tasks queued by setTimeout() + * and setInterval()). + */ + runAllTimers(): void; + /** + * Executes only the macro-tasks that are currently pending (i.e., only the + * tasks that have been queued by setTimeout() or setInterval() up to this + * point). If any of the currently pending macro-tasks schedule new + * macro-tasks, those new tasks will not be executed by this call. + */ + runOnlyPendingTimers(): void; + /** + * Advances all timers by msToRun milliseconds. All pending "macro-tasks" + * that have been queued via setTimeout() or setInterval(), and would be + * executed within this timeframe will be executed. + */ + advanceTimersByTime(msToRun: number): void; + /** + * Executes only the macro task queue (i.e. all tasks queued by setTimeout() + * or setInterval() and setImmediate()). + * + * @deprecated Use `jest.advanceTimersByTime()` + */ + runTimersToTime(msToRun: number): void; + /** + * Returns the number of fake timers still left to run. + */ + getTimerCount(): number; + /** + * Explicitly supplies the mock object that the module system should return + * for the specified module. + * + * Note It is recommended to use `jest.mock()` instead. The `jest.mock` + * API's second argument is a module factory instead of the expected + * exported module object. + */ + setMock(moduleName: string, moduleExports: unknown): Jest; + /** + * Set the default timeout interval for tests and before/after hooks in + * milliseconds. + * + * Note: The default timeout interval is 5 seconds if this method is not + * called. + */ + setTimeout(timeout: number): Jest; + /** + * Creates a mock function similar to `jest.fn` but also tracks calls to + * `object[methodName]`. + * + * Note: By default, jest.spyOn also calls the spied method. This is + * different behavior from most other test libraries. + */ + spyOn: typeof moduleMocker.spyOn; + /** + * Indicates that the module system should never return a mocked version of + * the specified module from require() (e.g. that it should always return the + * real module). + */ + unmock(moduleName: string): Jest; + /** + * Instructs Jest to use fake versions of the standard timer functions. + */ + useFakeTimers(): Jest; + /** + * Instructs Jest to use the real versions of the standard timer functions. + */ + useRealTimers(): Jest; + /** + * `jest.isolateModules(fn)` goes a step further than `jest.resetModules()` + * and creates a sandbox registry for the modules that are loaded inside + * the callback function. This is useful to isolate specific modules for + * every test so that local module state doesn't conflict between tests. + */ + isolateModules(fn: () => void): Jest; +} diff --git a/packages/jest-environment/tsconfig.json b/packages/jest-environment/tsconfig.json new file mode 100644 index 000000000000..8824863bd93b --- /dev/null +++ b/packages/jest-environment/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build" + }, + "references": [ + {"path": "../jest-transform"}, + {"path": "../jest-types"}, + {"path": "../jest-util"} + ] +} diff --git a/packages/jest-resolve/src/index.ts b/packages/jest-resolve/src/index.ts index c08f54cb9eab..12ccc4fe0e22 100644 --- a/packages/jest-resolve/src/index.ts +++ b/packages/jest-resolve/src/index.ts @@ -21,7 +21,7 @@ type FindNodeModuleConfig = { extensions?: Array; moduleDirectory?: Array; paths?: Array; - resolver?: Config.Path; + resolver?: Config.Path | null; rootDir?: Config.Path; }; @@ -403,7 +403,7 @@ const createNoMappedModuleFoundError = ( updatedName: string, mappedModuleName: string, regex: RegExp, - resolver: Function | string, + resolver?: Function | string | null, ) => { const error = new Error( chalk.red(`${chalk.bold('Configuration error')}: diff --git a/packages/jest-resolve/src/types.ts b/packages/jest-resolve/src/types.ts index b765f0333107..1c65ac50af57 100644 --- a/packages/jest-resolve/src/types.ts +++ b/packages/jest-resolve/src/types.ts @@ -9,14 +9,14 @@ import {Config} from '@jest/types'; export type ResolverConfig = { browser?: boolean; - defaultPlatform?: string; + defaultPlatform?: string | null; extensions: Array; hasCoreModules: boolean; moduleDirectories: Array; - moduleNameMapper?: Array; + moduleNameMapper?: Array | null; modulePaths: Array; platforms?: Array; - resolver: Config.Path; + resolver?: Config.Path | null; rootDir: Config.Path; }; diff --git a/packages/jest-runtime/package.json b/packages/jest-runtime/package.json index a4890ce50f79..29cce481fb07 100644 --- a/packages/jest-runtime/package.json +++ b/packages/jest-runtime/package.json @@ -8,8 +8,11 @@ }, "license": "MIT", "main": "build/index.js", + "types": "build/index.d.ts", "dependencies": { + "@jest/environment": "^24.1.0", "@jest/transform": "^24.1.0", + "@jest/types": "^24.1.0", "chalk": "^2.0.1", "exit": "^0.1.2", "glob": "^7.1.3", @@ -17,6 +20,7 @@ "jest-config": "^24.1.0", "jest-haste-map": "^24.0.0", "jest-message-util": "^24.0.0", + "jest-mock": "^24.0.0", "jest-regex-util": "^24.0.0", "jest-resolve": "^24.1.0", "jest-snapshot": "^24.1.0", diff --git a/packages/jest-runtime/src/cli/args.js b/packages/jest-runtime/src/cli/args.ts similarity index 91% rename from packages/jest-runtime/src/cli/args.js rename to packages/jest-runtime/src/cli/args.ts index cce2e3cecda3..7e7055780a36 100644 --- a/packages/jest-runtime/src/cli/args.js +++ b/packages/jest-runtime/src/cli/args.ts @@ -3,13 +3,13 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ +import {Options} from 'yargs'; + export const usage = 'Usage: $0 [--config=] '; -export const options = { +export const options: {[key: string]: Options} = { cache: { default: true, description: diff --git a/packages/jest-runtime/src/cli/index.js b/packages/jest-runtime/src/cli/index.ts similarity index 79% rename from packages/jest-runtime/src/cli/index.js rename to packages/jest-runtime/src/cli/index.ts index 2662efe5407b..b674801c7c51 100644 --- a/packages/jest-runtime/src/cli/index.js +++ b/packages/jest-runtime/src/cli/index.ts @@ -3,26 +3,25 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type {Argv} from 'types/Argv'; -import type {EnvironmentClass} from 'types/Environment'; - -import chalk from 'chalk'; import os from 'os'; import path from 'path'; +import chalk from 'chalk'; import {sync as realpath} from 'realpath-native'; import yargs from 'yargs'; +import {Argv} from '@jest/types'; +import {JestEnvironment} from '@jest/environment'; import {Console, setGlobal} from 'jest-util'; +// @ts-ignore: Not migrated to TS import {validateCLIOptions} from 'jest-validate'; +// @ts-ignore: Not migrated to TS import {readConfig, deprecationEntries} from 'jest-config'; +import {VERSION} from '../version'; +import {Context} from '../types'; import * as args from './args'; -const VERSION = (require('../../package.json').version: string); - -export function run(cliArgv?: Argv, cliInfo?: Array) { +export function run(cliArgv?: Argv.Argv, cliInfo?: Array) { const realFs = require('fs'); const fs = require('graceful-fs'); fs.gracefulify(realFs); @@ -74,23 +73,22 @@ export function run(cliArgv?: Argv, cliInfo?: Array) { }; // Break circular dependency - const Runtime = require('..'); + const Runtime: any = require('..'); - Runtime.createContext(config, { + (Runtime.createContext(config, { maxWorkers: Math.max(os.cpus().length - 1, 1), watchman: globalConfig.watchman, - }) + }) as Promise) .then(hasteMap => { - /* $FlowFixMe */ - const Environment = (require(config.testEnvironment): EnvironmentClass); + const Environment: JestEnvironment = require(config.testEnvironment); const environment = new Environment(config); setGlobal( environment.global, 'console', new Console(process.stdout, process.stderr), ); - environment.global.jestProjectConfig = config; - environment.global.jestGlobalConfig = globalConfig; + setGlobal(environment.global, 'jestProjectConfig', config); + setGlobal(environment.global, 'jestGlobalConfig', globalConfig); const runtime = new Runtime(config, environment, hasteMap.resolver); runtime.requireModule(filePath); diff --git a/packages/jest-runtime/src/helpers.js b/packages/jest-runtime/src/helpers.ts similarity index 91% rename from packages/jest-runtime/src/helpers.js rename to packages/jest-runtime/src/helpers.ts index 19265d836044..5b12d3aeb3aa 100644 --- a/packages/jest-runtime/src/helpers.js +++ b/packages/jest-runtime/src/helpers.ts @@ -1,16 +1,13 @@ // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. -// @flow - -import type {Path} from 'types/Config'; - import path from 'path'; import slash from 'slash'; import glob from 'glob'; +import {Config} from '@jest/types'; export const findSiblingsWithFileExtension = ( - moduleFileExtensions: Array, - from: Path, + moduleFileExtensions: Config.ProjectConfig['moduleFileExtensions'], + from: Config.Path, moduleName: string, ): string => { if (!path.isAbsolute(moduleName) && path.extname(moduleName) === '') { diff --git a/packages/jest-runtime/src/index.js b/packages/jest-runtime/src/index.ts similarity index 79% rename from packages/jest-runtime/src/index.js rename to packages/jest-runtime/src/index.ts index e6f393eef733..eaa14985d7ce 100644 --- a/packages/jest-runtime/src/index.js +++ b/packages/jest-runtime/src/index.ts @@ -3,72 +3,60 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type {Console} from 'console'; -import type {Argv} from 'types/Argv'; -import type {Glob, Path, ProjectConfig} from 'types/Config'; -import type {Environment} from 'types/Environment'; -import type {Context} from 'types/Context'; -import type {Jest, LocalModuleRequire} from 'types/Jest'; -import type {ModuleMap} from 'jest-haste-map'; -import type {MockFunctionMetadata, ModuleMocker} from 'types/Mock'; -import type {SourceMapRegistry} from 'types/SourceMaps'; - import path from 'path'; -import HasteMap from 'jest-haste-map'; +// import {Jest, LocalModuleRequire} from 'types/Jest'; +import {Argv, Config, Mocks, SourceMaps} from '@jest/types'; +import { + Jest, + JestEnvironment, + LocalModuleRequire, + Module, +} from '@jest/environment'; +import jestMock from 'jest-mock'; +import HasteMap, {ModuleMap} from 'jest-haste-map'; import {formatStackTrace, separateMessageFromStack} from 'jest-message-util'; import Resolver from 'jest-resolve'; import {createDirectory, deepCyclicCopy} from 'jest-util'; import {escapePathForRegex} from 'jest-regex-util'; import Snapshot from 'jest-snapshot'; -import {ScriptTransformer, shouldInstrument} from '@jest/transform'; +import { + ScriptTransformer, + ShouldInstrumentOptions, + shouldInstrument, +} from '@jest/transform'; import fs from 'graceful-fs'; import stripBOM from 'strip-bom'; import {run as cliRun} from './cli'; import {options as cliOptions} from './cli/args'; import {findSiblingsWithFileExtension} from './helpers'; +import {Context} from './types'; + +type HasteMapOptions = { + console?: Console; + maxWorkers: number; + resetCache: boolean; + watch?: boolean; + watchman: boolean; +}; -type Module = {| - children: Array, - exports: any, - filename: string, - id: string, - loaded: boolean, - parent?: Module, - paths?: Array, - require?: (id: string) => any, -|}; - -type HasteMapOptions = {| - console?: Console, - maxWorkers: number, - resetCache: boolean, - watch?: boolean, - watchman: boolean, -|}; - -type InternalModuleOptions = {| - isInternalModule: boolean, -|}; - -type CoverageOptions = { - changedFiles: ?Set, - collectCoverage: boolean, - collectCoverageFrom: Array, - collectCoverageOnlyFrom: ?{[key: string]: boolean, __proto__: null}, +type InternalModuleOptions = { + isInternalModule: boolean; }; -type ModuleRegistry = {[key: string]: Module, __proto__: null}; +type ModuleRegistry = {[key: string]: Module}; +type ResolveOptions = Parameters[1]; + +type BooleanObject = {[key: string]: boolean}; +type CacheFS = {[path: string]: string}; -type BooleanObject = {[key: string]: boolean, __proto__: null}; -type CacheFS = {[path: Path]: string, __proto__: null}; +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: ProjectConfig) => { +const getModuleNameMapper = (config: Config.ProjectConfig) => { if ( Array.isArray(config.moduleNameMapper) && config.moduleNameMapper.length @@ -84,45 +72,47 @@ const getModuleNameMapper = (config: ProjectConfig) => { const unmockRegExpCache = new WeakMap(); class Runtime { - static ScriptTransformer: Class; - - _cacheFS: CacheFS; - _config: ProjectConfig; - _coverageOptions: CoverageOptions; - _currentlyExecutingModulePath: string; - _environment: Environment; - _explicitShouldMock: BooleanObject; - _internalModuleRegistry: ModuleRegistry; - _isCurrentlyExecutingManualMock: ?string; - _mockFactories: {[key: string]: () => any, __proto__: null}; - _mockMetaDataCache: {[key: string]: MockFunctionMetadata, __proto__: null}; - _mockRegistry: {[key: string]: any, __proto__: null}; - _isolatedMockRegistry: ?{[key: string]: any, __proto__: null}; - _moduleMocker: ModuleMocker; - _isolatedModuleRegistry: ?ModuleRegistry; - _moduleRegistry: ModuleRegistry; - _needsCoverageMapped: Set; - _resolver: Resolver; - _shouldAutoMock: boolean; - _shouldMockModuleCache: BooleanObject; - _shouldUnmockTransitiveDependenciesCache: BooleanObject; - _sourceMapRegistry: SourceMapRegistry; - _scriptTransformer: ScriptTransformer; - _transitiveShouldMock: BooleanObject; - _unmockList: ?RegExp; - _virtualMocks: BooleanObject; + static ScriptTransformer: typeof ScriptTransformer; + + private _cacheFS: CacheFS; + private _config: Config.ProjectConfig; + private _coverageOptions: ShouldInstrumentOptions; + private _currentlyExecutingModulePath: string; + private _environment: JestEnvironment; + private _explicitShouldMock: BooleanObject; + private _internalModuleRegistry: ModuleRegistry; + private _isCurrentlyExecutingManualMock: string | null; + private _mockFactories: {[key: string]: () => unknown}; + private _mockMetaDataCache: { + [key: string]: Mocks.MockFunctionMetadata; + }; + private _mockRegistry: {[key: string]: any}; + private _isolatedMockRegistry: {[key: string]: any} | null | undefined; + private _moduleMocker: typeof jestMock; + private _isolatedModuleRegistry: ModuleRegistry | null; + private _moduleRegistry: ModuleRegistry; + private _needsCoverageMapped: Set; + private _resolver: Resolver; + private _shouldAutoMock: boolean; + private _shouldMockModuleCache: BooleanObject; + private _shouldUnmockTransitiveDependenciesCache: BooleanObject; + private _sourceMapRegistry: SourceMaps.SourceMapRegistry; + private _scriptTransformer: ScriptTransformer; + private _transitiveShouldMock: BooleanObject; + private _unmockList: RegExp | undefined; + private _virtualMocks: BooleanObject; constructor( - config: ProjectConfig, - environment: Environment, + config: Config.ProjectConfig, + environment: JestEnvironment, resolver: Resolver, cacheFS?: CacheFS, - coverageOptions?: CoverageOptions, + coverageOptions?: ShouldInstrumentOptions, ) { this._cacheFS = cacheFS || Object.create(null); this._config = config; this._coverageOptions = coverageOptions || { - changedFiles: null, + changedFiles: undefined, collectCoverage: false, collectCoverageFrom: [], collectCoverageOnlyFrom: null, @@ -178,30 +168,22 @@ class Runtime { } } + // TODO: Can this be `static shouldInstrument = shouldInstrument;`? static shouldInstrument( - filename: Path, - options: CoverageOptions, - config: ProjectConfig, + filename: Config.Path, + options: ShouldInstrumentOptions, + config: Config.ProjectConfig, ) { - return shouldInstrument( - filename, - { - changedFiles: options.changedFiles, - collectCoverage: options.collectCoverage, - collectCoverageFrom: options.collectCoverageFrom, - collectCoverageOnlyFrom: options.collectCoverageOnlyFrom, - }, - config, - ); + return shouldInstrument(filename, options, config); } static createContext( - config: ProjectConfig, + config: Config.ProjectConfig, options: { - console?: Console, - maxWorkers: number, - watch?: boolean, - watchman: boolean, + console?: Console; + maxWorkers: number; + watch?: boolean; + watchman: boolean; }, ): Promise { createDirectory(config.cacheDirectory); @@ -226,7 +208,7 @@ class Runtime { } static createHasteMap( - config: ProjectConfig, + config: Config.ProjectConfig, options?: HasteMapOptions, ): HasteMap { const ignorePatternParts = [ @@ -238,7 +220,7 @@ class Runtime { const ignorePattern = ignorePatternParts.length > 0 ? new RegExp(ignorePatternParts.join('|')) - : null; + : undefined; return new HasteMap({ cacheDirectory: config.cacheDirectory, @@ -262,7 +244,10 @@ class Runtime { }); } - static createResolver(config: ProjectConfig, moduleMap: ModuleMap): Resolver { + static createResolver( + config: Config.ProjectConfig, + moduleMap: ModuleMap, + ): Resolver { return new Resolver(moduleMap, { browser: config.browser, defaultPlatform: config.haste.defaultPlatform, @@ -277,7 +262,7 @@ class Runtime { }); } - static runCLI(args?: Argv, info?: Array) { + static runCLI(args?: Argv.Argv, info?: Array) { return cliRun(args, info); } @@ -286,10 +271,10 @@ class Runtime { } requireModule( - from: Path, + from: Config.Path, moduleName?: string, - options: ?InternalModuleOptions, - isRequireActual: ?boolean, + options?: InternalModuleOptions | null, + isRequireActual?: boolean | null, ) { const moduleID = this._resolver.getModuleID( this._virtualMocks, @@ -351,7 +336,6 @@ class Runtime { stripBOM(fs.readFileSync(modulePath, 'utf8')), ); } else if (path.extname(modulePath) === '.node') { - // $FlowFixMe localModule.exports = require(modulePath); } else { // Only include the fromPath if a moduleName is given. Else treat as root. @@ -364,15 +348,15 @@ class Runtime { return moduleRegistry[modulePath].exports; } - requireInternalModule(from: Path, to?: string) { + requireInternalModule(from: Config.Path, to?: string) { return this.requireModule(from, to, {isInternalModule: true}); } - requireActual(from: Path, moduleName: string) { + requireActual(from: Config.Path, moduleName: string) { return this.requireModule(from, moduleName, undefined, true); } - requireMock(from: Path, moduleName: string) { + requireMock(from: Config.Path, moduleName: string) { const moduleID = this._resolver.getModuleID( this._virtualMocks, from, @@ -449,7 +433,7 @@ class Runtime { return mockRegistry[moduleID]; } - requireModuleOrMock(from: Path, moduleName: string) { + requireModuleOrMock(from: Config.Path, moduleName: string) { try { if (this._shouldMock(from, moduleName)) { return this.requireMock(from, moduleName); @@ -494,13 +478,14 @@ class Runtime { if (this._environment) { if (this._environment.global) { const envGlobal = this._environment.global; - Object.keys(envGlobal).forEach(key => { + (Object.keys(envGlobal) as Array).forEach(key => { const globalMock = envGlobal[key]; if ( - (typeof globalMock === 'object' && globalMock !== null) || - typeof globalMock === 'function' + ((typeof globalMock === 'object' && globalMock !== null) || + typeof globalMock === 'function') && + globalMock._isMockFunction === true ) { - globalMock._isMockFunction === true && globalMock.mockClear(); + globalMock.mockClear(); } }); } @@ -516,7 +501,9 @@ class Runtime { } getSourceMapInfo(coveredFiles: Set) { - return Object.keys(this._sourceMapRegistry).reduce((result, sourcePath) => { + return Object.keys(this._sourceMapRegistry).reduce<{ + [path: string]: unknown; + }>((result, sourcePath) => { if ( coveredFiles.has(sourcePath) && this._needsCoverageMapped.has(sourcePath) && @@ -528,15 +515,15 @@ class Runtime { }, {}); } - getSourceMaps(): SourceMapRegistry { + getSourceMaps(): SourceMaps.SourceMapRegistry { return this._sourceMapRegistry; } setMock( from: string, moduleName: string, - mockFactory: () => any, - options?: {virtual: boolean}, + mockFactory: () => unknown, + options?: {virtual?: boolean}, ) { if (options && options.virtual) { const mockPath = this._resolver.getModulePath(from, moduleName); @@ -563,14 +550,14 @@ class Runtime { this._moduleMocker.clearAllMocks(); } - _resolveModule(from: Path, to?: ?string) { + private _resolveModule(from: Config.Path, to?: string | null | undefined) { return to ? this._resolver.resolveModule(from, to) : from; } - _requireResolve( - from: Path, + private _requireResolve( + from: Config.Path, moduleName?: string, - {paths}: {paths?: Path[]} = {}, + options: ResolveOptions = {}, ) { if (moduleName == null) { throw new Error( @@ -578,6 +565,8 @@ class Runtime { ); } + const {paths} = options; + if (paths) { for (const p of paths) { const absolutePath = path.resolve(from, '..', p); @@ -610,7 +599,7 @@ class Runtime { } } - _requireResolvePaths(from: Path, moduleName?: string) { + private _requireResolvePaths(from: Config.Path, moduleName?: string) { if (moduleName == null) { throw new Error( 'The first argument to require.resolve.paths must be a string. Received null or undefined.', @@ -631,11 +620,11 @@ class Runtime { return this._resolver.getModulePaths(path.resolve(from, '..')); } - _execModule( + private _execModule( localModule: Module, - options: ?InternalModuleOptions, + options: InternalModuleOptions | null | undefined, moduleRegistry: ModuleRegistry, - from: ?Path, + from: Config.Path | null | undefined, ) { // If the environment was disposed, prevent this module from being executed. if (!this._environment.global) { @@ -652,18 +641,13 @@ class Runtime { const dirname = path.dirname(filename); localModule.children = []; - Object.defineProperty( - localModule, - 'parent', - // https://github.com/facebook/flow/issues/285#issuecomment-270810619 - ({ - enumerable: true, - get() { - const key = from || ''; - return moduleRegistry[key] || null; - }, - }: Object), - ); + Object.defineProperty(localModule, 'parent', { + enumerable: true, + get() { + const key = from || ''; + return moduleRegistry[key] || null; + }, + }); localModule.paths = this._resolver.getModulePaths(dirname); Object.defineProperty(localModule, 'require', { @@ -710,8 +694,7 @@ class Runtime { this._environment.global, // global object this._createJestObjectFor( filename, - // $FlowFixMe - (localModule.require: LocalModuleRequire), + localModule.require as LocalModuleRequire, ), // jest object ...extraGlobals.map(globalVariable => { if (this._environment.global[globalVariable]) { @@ -729,25 +712,24 @@ class Runtime { this._currentlyExecutingModulePath = lastExecutingModulePath; } - _requireCoreModule(moduleName: string) { + private _requireCoreModule(moduleName: string) { if (moduleName === 'process') { return this._environment.global.process; } - // $FlowFixMe return require(moduleName); } - _generateMock(from: Path, moduleName: string) { + private _generateMock(from: Config.Path, moduleName: string) { const modulePath = this._resolver.resolveStubModuleName(from, moduleName) || this._resolveModule(from, moduleName); if (!(modulePath in this._mockMetaDataCache)) { // This allows us to handle circular dependencies while generating an // automock - this._mockMetaDataCache[modulePath] = (this._moduleMocker.getMetadata( + this._mockMetaDataCache[modulePath] = this._moduleMocker.getMetadata( {}, - ): any); + ) as any; // In order to avoid it being possible for automocking to potentially // cause side-effects within the module environment, we need to execute @@ -778,7 +760,7 @@ class Runtime { ); } - _shouldMock(from: Path, moduleName: string) { + private _shouldMock(from: Config.Path, moduleName: string) { const mockPath = this._resolver.getModulePath(from, moduleName); if (mockPath in this._virtualMocks) { return true; @@ -845,45 +827,51 @@ class Runtime { return (this._shouldMockModuleCache[moduleID] = true); } - _createRequireImplementation( + private _createRequireImplementation( from: Module, - options: ?InternalModuleOptions, + options: InternalModuleOptions | null | undefined, ): LocalModuleRequire { - const moduleRequire = + // TODO: somehow avoid having to type the arguments - they should come from `LocalModuleRequire` + const resolve = (moduleName: string, options: ResolveOptions) => + this._requireResolve(from.filename, moduleName, options); + + resolve.paths = (moduleName: string) => + this._requireResolvePaths(from.filename, moduleName); + + const requireImpl: any = options && options.isInternalModule ? (moduleName: string) => this.requireInternalModule(from.filename, moduleName) : this.requireModuleOrMock.bind(this, from.filename); - moduleRequire.cache = Object.create(null); - moduleRequire.extensions = Object.create(null); - moduleRequire.requireActual = this.requireActual.bind(this, from.filename); - moduleRequire.requireMock = this.requireMock.bind(this, from.filename); - moduleRequire.resolve = (moduleName, options) => - this._requireResolve(from.filename, moduleName, options); - moduleRequire.resolve.paths = moduleName => - this._requireResolvePaths(from.filename, moduleName); - Object.defineProperty( - moduleRequire, - 'main', - ({ - enumerable: true, - get() { - let mainModule = from.parent; - while ( - mainModule && - mainModule.parent && - mainModule.id !== mainModule.parent.id - ) { - mainModule = mainModule.parent; - } - return mainModule; - }, - }: Object), - ); + requireImpl.cache = Object.create(null); + requireImpl.extensions = Object.create(null); + requireImpl.requireActual = this.requireActual.bind(this, from.filename); + requireImpl.requireMock = this.requireMock.bind(this, from.filename); + requireImpl.resolve = resolve; + + const moduleRequire: LocalModuleRequire = {...requireImpl}; + + Object.defineProperty(moduleRequire, 'main', { + enumerable: true, + get() { + let mainModule = from.parent; + while ( + mainModule && + mainModule.parent && + mainModule.id !== mainModule.parent.id + ) { + mainModule = mainModule.parent; + } + return mainModule; + }, + }); return moduleRequire; } - _createJestObjectFor(from: Path, localRequire: LocalModuleRequire): Jest { + private _createJestObjectFor( + from: Config.Path, + localRequire: LocalModuleRequire, + ): Jest { const disableAutomock = () => { this._shouldAutoMock = false; return jestObject; @@ -911,11 +899,7 @@ class Runtime { this._transitiveShouldMock[moduleID] = false; return jestObject; }; - const mock = ( - moduleName: string, - mockFactory?: Object, - options?: {virtual: boolean}, - ) => { + const mock: Jest['mock'] = (moduleName, mockFactory, options) => { if (mockFactory !== undefined) { return setMockFactory(moduleName, mockFactory, options); } @@ -928,7 +912,11 @@ class Runtime { this._explicitShouldMock[moduleID] = true; return jestObject; }; - const setMockFactory = (moduleName, mockFactory, options) => { + const setMockFactory = ( + moduleName: string, + mockFactory: () => unknown, + options?: {virtual?: boolean}, + ) => { this.setMock(from, moduleName, mockFactory, options); return jestObject; }; @@ -964,16 +952,18 @@ class Runtime { const spyOn = this._moduleMocker.spyOn.bind(this._moduleMocker); const setTimeout = (timeout: number) => { - this._environment.global.jasmine - ? (this._environment.global.jasmine._DEFAULT_TIMEOUT_INTERVAL = timeout) - : (this._environment.global[ - Symbol.for('TEST_TIMEOUT_SYMBOL') - ] = timeout); + if (this._environment.global.jasmine) { + this._environment.global.jasmine._DEFAULT_TIMEOUT_INTERVAL = timeout; + } else { + // @ts-ignore: https://github.com/Microsoft/TypeScript/issues/24587 + this._environment.global[testTimeoutSymbol] = timeout; + } return jestObject; }; const retryTimes = (numTestRetries: number) => { - this._environment.global[Symbol.for('RETRY_TIMES')] = numTestRetries; + // @ts-ignore: https://github.com/Microsoft/TypeScript/issues/24587 + this._environment.global[retryTimesSymbol] = numTestRetries; return jestObject; }; @@ -988,7 +978,7 @@ class Runtime { return this._environment.fakeTimers; }; - const jestObject = { + const jestObject: Jest = { addMatchers: (matchers: Object) => this._environment.global.jasmine.addMatchers(matchers), advanceTimersByTime: (msToRun: number) => @@ -1022,7 +1012,7 @@ class Runtime { runOnlyPendingTimers: () => _getFakeTimers().runOnlyPendingTimers(), runTimersToTime: (msToRun: number) => _getFakeTimers().advanceTimersByTime(msToRun), - setMock: (moduleName: string, mock: Object) => + setMock: (moduleName: string, mock: unknown) => setMockFactory(moduleName, () => mock), setTimeout, spyOn, @@ -1034,8 +1024,8 @@ class Runtime { } _logFormattedReferenceError(errorMessage: string) { - const originalStack = new ReferenceError(errorMessage).stack - .split('\n') + 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'); @@ -1051,4 +1041,4 @@ class Runtime { Runtime.ScriptTransformer = ScriptTransformer; -module.exports = Runtime; +export = Runtime; diff --git a/packages/jest-runtime/src/types.ts b/packages/jest-runtime/src/types.ts new file mode 100644 index 000000000000..954bcf8d6e71 --- /dev/null +++ b/packages/jest-runtime/src/types.ts @@ -0,0 +1,17 @@ +/** + * 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 {Config} from '@jest/types'; +import HasteResolver from 'jest-resolve'; +import {FS as HasteFS, ModuleMap} from 'jest-haste-map'; + +export type Context = { + config: Config.ProjectConfig; + hasteFS: HasteFS; + moduleMap: ModuleMap; + resolver: HasteResolver; +}; diff --git a/packages/jest-runtime/src/version.ts b/packages/jest-runtime/src/version.ts new file mode 100644 index 000000000000..6c68483e5054 --- /dev/null +++ b/packages/jest-runtime/src/version.ts @@ -0,0 +1,9 @@ +/** + * 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. + */ + +// For some reason, doing `require`ing here works, while inside `cli` fails +export const VERSION: string = require('../package.json').version; diff --git a/packages/jest-runtime/tsconfig.json b/packages/jest-runtime/tsconfig.json new file mode 100644 index 000000000000..b73127d8e1fd --- /dev/null +++ b/packages/jest-runtime/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build" + }, + // TODO: Missing `jest-config`, `jest-validate` and `jest-environment-node` + "references": [ + {"path": "../jest-environment"}, + {"path": "../jest-haste-map"}, + {"path": "../jest-message-util"}, + {"path": "../jest-mock"}, + {"path": "../jest-regex-util"}, + {"path": "../jest-resolve"}, + {"path": "../jest-snapshot"}, + {"path": "../jest-util"}, + {"path": "../jest-types"}, + {"path": "../pretty-format"} + ] +} diff --git a/packages/jest-transform/src/ScriptTransformer.ts b/packages/jest-transform/src/ScriptTransformer.ts index 3d92b9f94cee..2fbf03a78ecf 100644 --- a/packages/jest-transform/src/ScriptTransformer.ts +++ b/packages/jest-transform/src/ScriptTransformer.ts @@ -50,7 +50,7 @@ const projectCaches: WeakMap< const CACHE_VERSION = '1'; export default class ScriptTransformer { - static EVAL_RESULT_VARIABLE: string; + static EVAL_RESULT_VARIABLE: 'Object.'; private _cache: ProjectCache; private _config: Config.ProjectConfig; private _transformCache: Map; @@ -565,4 +565,5 @@ const wrap = (content: string, ...extras: Array) => { ); }; +// TODO: Can this be added to the static property? ScriptTransformer.EVAL_RESULT_VARIABLE = 'Object.'; diff --git a/packages/jest-transform/src/index.ts b/packages/jest-transform/src/index.ts index 6f10151c3051..4a757f5ad9fd 100644 --- a/packages/jest-transform/src/index.ts +++ b/packages/jest-transform/src/index.ts @@ -7,4 +7,4 @@ export {default as ScriptTransformer} from './ScriptTransformer'; export {default as shouldInstrument} from './shouldInstrument'; -export {Transformer} from './types'; +export {Transformer, ShouldInstrumentOptions} from './types'; diff --git a/packages/jest-transform/src/shouldInstrument.ts b/packages/jest-transform/src/shouldInstrument.ts index 2020e724ddb5..0aa7d2f7d74e 100644 --- a/packages/jest-transform/src/shouldInstrument.ts +++ b/packages/jest-transform/src/shouldInstrument.ts @@ -10,7 +10,7 @@ import {Config} from '@jest/types'; import {escapePathForRegex} from 'jest-regex-util'; import {replacePathSepForGlob} from 'jest-util'; import micromatch from 'micromatch'; -import {Options} from './types'; +import {ShouldInstrumentOptions} from './types'; const MOCKS_PATTERN = new RegExp( escapePathForRegex(path.sep + '__mocks__' + path.sep), @@ -18,7 +18,7 @@ const MOCKS_PATTERN = new RegExp( export default function shouldInstrument( filename: Config.Path, - options: Options, + options: ShouldInstrumentOptions, config: Config.ProjectConfig, ): boolean { if (!options.collectCoverage) { diff --git a/packages/jest-transform/src/types.ts b/packages/jest-transform/src/types.ts index 91df3f394de9..636cff4c27e2 100644 --- a/packages/jest-transform/src/types.ts +++ b/packages/jest-transform/src/types.ts @@ -9,18 +9,19 @@ import {Script} from 'vm'; import {RawSourceMap} from 'source-map'; import {Config} from '@jest/types'; -export type Options = Pick< +export type ShouldInstrumentOptions = Pick< Config.GlobalConfig, - | 'collectCoverage' - | 'collectCoverageFrom' - | 'collectCoverageOnlyFrom' - | 'extraGlobals' + 'collectCoverage' | 'collectCoverageFrom' | 'collectCoverageOnlyFrom' > & { changedFiles: Set | undefined; - isCoreModule?: boolean; - isInternalModule?: boolean; }; +export type Options = ShouldInstrumentOptions & + Pick & { + isCoreModule?: boolean; + isInternalModule?: boolean; + }; + // https://stackoverflow.com/a/48216010/1850276 type Omit = Pick>; diff --git a/packages/jest-types/src/Argv.ts b/packages/jest-types/src/Argv.ts new file mode 100644 index 000000000000..a4d1ed880a0b --- /dev/null +++ b/packages/jest-types/src/Argv.ts @@ -0,0 +1,100 @@ +/** + * 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 from `@types` +// eslint-disable-next-line import/no-extraneous-dependencies +import {Arguments} from 'yargs'; + +export type Argv = Arguments<{ + all: boolean; + automock: boolean; + bail: boolean | number; + browser: boolean; + cache: boolean; + cacheDirectory: string; + changedFilesWithAncestor: boolean; + changedSince: string; + ci: boolean; + clearCache: boolean; + clearMocks: boolean; + collectCoverage: boolean; + collectCoverageFrom: Array; + collectCoverageOnlyFrom: Array; + config: string; + coverage: boolean; + coverageDirectory: string; + coveragePathIgnorePatterns: Array; + coverageReporters: Array; + coverageThreshold: string; + debug: boolean; + env: string; + expand: boolean; + findRelatedTests: boolean; + forceExit: boolean; + globals: string; + globalSetup: string | null | undefined; + globalTeardown: string | null | undefined; + h: boolean; + haste: string; + help: boolean; + init: boolean; + json: boolean; + lastCommit: boolean; + logHeapUsage: boolean; + maxWorkers: number; + moduleDirectories: Array; + moduleFileExtensions: Array; + moduleLoader: string; + moduleNameMapper: string; + modulePathIgnorePatterns: Array; + modulePaths: Array; + name: string; + noSCM: boolean; + noStackTrace: boolean; + notify: boolean; + notifyMode: string; + onlyChanged: boolean; + outputFile: string; + preset: string | null | undefined; + projects: Array; + prettierPath: string | null | undefined; + replname: string | null | undefined; + resetMocks: boolean; + resetModules: boolean; + resolver: string | null | undefined; + restoreMocks: boolean; + rootDir: string; + roots: Array; + runInBand: boolean; + setupFiles: Array; + setupFilesAfterEnv: Array; + showConfig: boolean; + silent: boolean; + snapshotSerializers: Array; + testEnvironment: string; + testFailureExitCode: string | null | undefined; + testMatch: Array; + testNamePattern: string; + testPathIgnorePatterns: Array; + testPathPattern: Array; + testRegex: string | Array; + testResultsProcessor: string | null | undefined; + testRunner: string; + testURL: string; + timers: 'real' | 'fake'; + transform: string; + transformIgnorePatterns: Array; + unmockedModulePathPatterns: Array | null | undefined; + updateSnapshot: boolean; + useStderr: boolean; + verbose: boolean | null | undefined; + version: boolean; + watch: boolean; + watchAll: boolean; + watchman: boolean; + watchPathIgnorePatterns: Array; +}>; diff --git a/packages/jest-types/src/Config.ts b/packages/jest-types/src/Config.ts index 85a5db4df75f..36209c91ee97 100644 --- a/packages/jest-types/src/Config.ts +++ b/packages/jest-types/src/Config.ts @@ -313,7 +313,7 @@ export type ProjectConfig = { detectOpenHandles: boolean; displayName: string | null | undefined; errorOnDeprecated: boolean; - extraGlobals: Array; + extraGlobals: Array; filter: Path | null | undefined; forceCoverageMatch: Array; globalSetup: string | null | undefined; diff --git a/packages/jest-types/src/Environment.ts b/packages/jest-types/src/Environment.ts deleted file mode 100644 index 1af4493db851..000000000000 --- a/packages/jest-types/src/Environment.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * 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 {Script} from 'vm'; -import {ProjectConfig} from './Config'; -import {Global} from './Global'; - -// TODO Fix jest-mock and @jest/types has circular dependency -// import {ModuleMocker} from 'jest-mock'; -type ModuleMocker = any; - -export type EnvironmentContext = { - console?: Object; - testPath?: string; -}; - -export declare class $JestEnvironment { - constructor(config: ProjectConfig, context?: EnvironmentContext); - runScript(script: Script): any; - global: Global; - fakeTimers: { - clearAllTimers(): void; - runAllImmediates(): void; - runAllTicks(): void; - runAllTimers(): void; - advanceTimersByTime(msToRun: number): void; - runOnlyPendingTimers(): void; - runWithRealTimers(callback: any): void; - getTimerCount(): number; - useFakeTimers(): void; - useRealTimers(): void; - }; - testFilePath: string; - moduleMocker: ModuleMocker; - setup(): Promise; - teardown(): Promise; -} - -export type Environment = $JestEnvironment; -export type EnvironmentClass = typeof $JestEnvironment; diff --git a/packages/jest-types/src/index.ts b/packages/jest-types/src/index.ts index ed4c3acd0eac..2d0b05192cce 100644 --- a/packages/jest-types/src/index.ts +++ b/packages/jest-types/src/index.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import * as Argv from './Argv'; import * as Config from './Config'; import * as Console from './Console'; import * as Matchers from './Matchers'; @@ -14,9 +15,9 @@ import * as Snapshot from './Snapshot'; import * as SourceMaps from './SourceMaps'; import * as TestResult from './TestResult'; import * as Global from './Global'; -import * as Environment from './Environment'; export { + Argv, Config, Console, Matchers, @@ -26,5 +27,4 @@ export { SourceMaps, TestResult, Global, - Environment, }; From 28cac01f849bef32ca92de80af50de33fc419b3b Mon Sep 17 00:00:00 2001 From: Tim Seckinger Date: Sat, 23 Feb 2019 20:20:28 +0100 Subject: [PATCH 02/15] fix partial Module type errors --- packages/jest-runtime/src/index.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index eaa14985d7ce..2651f7807517 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -45,7 +45,9 @@ type InternalModuleOptions = { isInternalModule: boolean; }; -type ModuleRegistry = {[key: string]: Module}; +type InitialModule = Partial & + Pick; +type ModuleRegistry = {[key: string]: InitialModule}; type ResolveOptions = Parameters[1]; type BooleanObject = {[key: string]: boolean}; @@ -323,7 +325,7 @@ class Runtime { // 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: Module = { + const localModule: InitialModule = { children: [], exports: {}, filename: modulePath, @@ -412,7 +414,7 @@ class Runtime { } } if (isManualMock) { - const localModule: Module = { + const localModule: InitialModule = { children: [], exports: {}, filename: modulePath, @@ -621,7 +623,7 @@ class Runtime { } private _execModule( - localModule: Module, + localModule: InitialModule, options: InternalModuleOptions | null | undefined, moduleRegistry: ModuleRegistry, from: Config.Path | null | undefined, @@ -828,7 +830,7 @@ class Runtime { } private _createRequireImplementation( - from: Module, + from: InitialModule, options: InternalModuleOptions | null | undefined, ): LocalModuleRequire { // TODO: somehow avoid having to type the arguments - they should come from `LocalModuleRequire` From 6669e52a80a4442d9d78c4b6d0d28ac1f07e75c0 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 23 Feb 2019 20:33:57 +0100 Subject: [PATCH 03/15] moduleregistry can contain fully loaded modules as well --- packages/jest-runtime/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 2651f7807517..63e90494a698 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -47,7 +47,7 @@ type InternalModuleOptions = { type InitialModule = Partial & Pick; -type ModuleRegistry = {[key: string]: InitialModule}; +type ModuleRegistry = {[key: string]: InitialModule | Module}; type ResolveOptions = Parameters[1]; type BooleanObject = {[key: string]: boolean}; From fc6749921280d586f7447dcbfcd0739524729a06 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 23 Feb 2019 20:35:11 +0100 Subject: [PATCH 04/15] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 227365427b90..97dbec1c98f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,7 @@ - `[expect]`: Migrate to TypeScript ([#7919](https://github.com/facebook/jest/pull/7919)) - `[jest-circus]`: Migrate to TypeScript ([#7916](https://github.com/facebook/jest/pull/7916)) - `[jest-phabricator]`: Migrate to TypeScript ([#7965](https://github.com/facebook/jest/pull/7965)) +- `[jest-runtime]`: Migrate to TypeScript ([#7964](https://github.com/facebook/jest/pull/7964)) ### Performance From beaaa82637794f9bf27a183bfa447cae8a9527f1 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 23 Feb 2019 20:48:31 +0100 Subject: [PATCH 05/15] fix require implementation generation --- packages/jest-runtime/src/index.ts | 32 +++++++++++++----------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 63e90494a698..00833526ff4e 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -275,7 +275,7 @@ class Runtime { requireModule( from: Config.Path, moduleName?: string, - options?: InternalModuleOptions | null, + options?: InternalModuleOptions, isRequireActual?: boolean | null, ) { const moduleID = this._resolver.getModuleID( @@ -624,7 +624,7 @@ class Runtime { private _execModule( localModule: InitialModule, - options: InternalModuleOptions | null | undefined, + options: InternalModuleOptions | undefined, moduleRegistry: ModuleRegistry, from: Config.Path | null | undefined, ) { @@ -831,27 +831,23 @@ class Runtime { private _createRequireImplementation( from: InitialModule, - options: InternalModuleOptions | null | undefined, + options?: InternalModuleOptions, ): LocalModuleRequire { - // TODO: somehow avoid having to type the arguments - they should come from `LocalModuleRequire` - const resolve = (moduleName: string, options: ResolveOptions) => - this._requireResolve(from.filename, moduleName, options); - - resolve.paths = (moduleName: string) => - this._requireResolvePaths(from.filename, moduleName); - - const requireImpl: any = + // TODO: Should not be `any`, this isn't type safe. Should be `LocalModuleRequire` + const moduleRequire: any = options && options.isInternalModule ? (moduleName: string) => this.requireInternalModule(from.filename, moduleName) : this.requireModuleOrMock.bind(this, from.filename); - requireImpl.cache = Object.create(null); - requireImpl.extensions = Object.create(null); - requireImpl.requireActual = this.requireActual.bind(this, from.filename); - requireImpl.requireMock = this.requireMock.bind(this, from.filename); - requireImpl.resolve = resolve; - - const moduleRequire: LocalModuleRequire = {...requireImpl}; + moduleRequire.cache = Object.create(null); + moduleRequire.extensions = Object.create(null); + moduleRequire.requireActual = this.requireActual.bind(this, from.filename); + moduleRequire.requireMock = this.requireMock.bind(this, from.filename); + // TODO: somehow avoid having to type the arguments - they should come from `NodeRequire.resolve` + moduleRequire.resolve = (moduleName: string, options: ResolveOptions) => + this._requireResolve(from.filename, moduleName, options); + moduleRequire.resolve.paths = (moduleName: string) => + this._requireResolvePaths(from.filename, moduleName); Object.defineProperty(moduleRequire, 'main', { enumerable: true, From 45dd5a861965873c55f155f5e4f0f55e17a3d3f0 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 23 Feb 2019 21:01:59 +0100 Subject: [PATCH 06/15] fix lint --- packages/jest-types/src/Argv.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/jest-types/src/Argv.ts b/packages/jest-types/src/Argv.ts index a4d1ed880a0b..84d4f66893cc 100644 --- a/packages/jest-types/src/Argv.ts +++ b/packages/jest-types/src/Argv.ts @@ -5,8 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -// import from `@types` -// eslint-disable-next-line import/no-extraneous-dependencies import {Arguments} from 'yargs'; export type Argv = Arguments<{ From 9d50f00f51315f881872a2705d870778adf58f24 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 23 Feb 2019 21:08:09 +0100 Subject: [PATCH 07/15] remove ignore in jest-circus --- .../src/legacy-code-todo-rewrite/jestAdapter.ts | 4 ++-- packages/jest-circus/tsconfig.json | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index 8011efd64a31..7064ad335553 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -8,8 +8,8 @@ import path from 'path'; import {Config, TestResult} from '@jest/types'; import {JestEnvironment} from '@jest/environment'; -// @ts-ignore TODO Remove ignore when jest-runtime is migrated to ts -import Runtime from 'jest-runtime'; // eslint-disable-line import/no-extraneous-dependencies +// eslint-disable-next-line import/no-extraneous-dependencies +import Runtime from 'jest-runtime'; import {SnapshotState} from 'jest-snapshot'; const FRAMEWORK_INITIALIZER = require.resolve('./jestAdapterInit'); diff --git a/packages/jest-circus/tsconfig.json b/packages/jest-circus/tsconfig.json index 14772ef4ab7c..726c0ac6b1e5 100644 --- a/packages/jest-circus/tsconfig.json +++ b/packages/jest-circus/tsconfig.json @@ -5,13 +5,14 @@ "rootDir": "src" }, "references": [ + {"path": "../jest-diff"}, {"path": "../jest-environment"}, - {"path": "../jest-types"}, - {"path": "../jest-snapshot"}, {"path": "../jest-matcher-utils"}, {"path": "../jest-message-util"}, + {"path": "../jest-runtime"}, + {"path": "../jest-snapshot"}, + {"path": "../jest-types"}, {"path": "../jest-util"}, - {"path": "../pretty-format"}, - {"path": "../jest-diff"} + {"path": "../pretty-format"} ] } From 3e12637a58cde45a3f0660888939377b465aedbc Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sat, 23 Feb 2019 21:26:02 +0100 Subject: [PATCH 08/15] remove some `undefined` from types --- packages/jest-runtime/src/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 00833526ff4e..e5cc6642450b 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -89,7 +89,7 @@ class Runtime { [key: string]: Mocks.MockFunctionMetadata; }; private _mockRegistry: {[key: string]: any}; - private _isolatedMockRegistry: {[key: string]: any} | null | undefined; + private _isolatedMockRegistry: {[key: string]: any} | null; private _moduleMocker: typeof jestMock; private _isolatedModuleRegistry: ModuleRegistry | null; private _moduleRegistry: ModuleRegistry; @@ -128,6 +128,7 @@ class Runtime { this._mockRegistry = Object.create(null); this._moduleMocker = this._environment.moduleMocker; this._isolatedModuleRegistry = null; + this._isolatedMockRegistry = null; this._moduleRegistry = Object.create(null); this._needsCoverageMapped = new Set(); this._resolver = resolver; @@ -552,7 +553,7 @@ class Runtime { this._moduleMocker.clearAllMocks(); } - private _resolveModule(from: Config.Path, to?: string | null | undefined) { + private _resolveModule(from: Config.Path, to?: string) { return to ? this._resolver.resolveModule(from, to) : from; } @@ -626,7 +627,7 @@ class Runtime { localModule: InitialModule, options: InternalModuleOptions | undefined, moduleRegistry: ModuleRegistry, - from: Config.Path | null | undefined, + from: Config.Path | null, ) { // If the environment was disposed, prevent this module from being executed. if (!this._environment.global) { From 95e4b6ab5bd01db81e1f6222bf9aa8eff5c63808 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sun, 24 Feb 2019 01:08:43 +0100 Subject: [PATCH 09/15] remove comment --- packages/jest-runtime/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index e5cc6642450b..38d50dd1fa72 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -6,7 +6,6 @@ */ import path from 'path'; -// import {Jest, LocalModuleRequire} from 'types/Jest'; import {Argv, Config, Mocks, SourceMaps} from '@jest/types'; import { Jest, From 67940855d01801577243dc00e95b77445cd23da6 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Sun, 24 Feb 2019 16:14:59 +0100 Subject: [PATCH 10/15] remove todo and any --- packages/jest-runtime/src/index.ts | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 38d50dd1fa72..ce01456853ff 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -833,21 +833,24 @@ class Runtime { from: InitialModule, options?: InternalModuleOptions, ): LocalModuleRequire { - // TODO: Should not be `any`, this isn't type safe. Should be `LocalModuleRequire` - const moduleRequire: any = - options && options.isInternalModule - ? (moduleName: string) => - this.requireInternalModule(from.filename, moduleName) - : this.requireModuleOrMock.bind(this, from.filename); + // TODO: somehow avoid having to type the arguments - they should come from `NodeRequire/LocalModuleRequire.resolve` + const resolve = (moduleName: string, options: ResolveOptions) => + this._requireResolve(from.filename, moduleName, options); + resolve.paths = (moduleName: string) => + this._requireResolvePaths(from.filename, moduleName); + + const moduleRequire = (options && options.isInternalModule + ? (moduleName: string) => + this.requireInternalModule(from.filename, moduleName) + : this.requireModuleOrMock.bind( + this, + from.filename, + )) as LocalModuleRequire; moduleRequire.cache = Object.create(null); moduleRequire.extensions = Object.create(null); moduleRequire.requireActual = this.requireActual.bind(this, from.filename); moduleRequire.requireMock = this.requireMock.bind(this, from.filename); - // TODO: somehow avoid having to type the arguments - they should come from `NodeRequire.resolve` - moduleRequire.resolve = (moduleName: string, options: ResolveOptions) => - this._requireResolve(from.filename, moduleName, options); - moduleRequire.resolve.paths = (moduleName: string) => - this._requireResolvePaths(from.filename, moduleName); + moduleRequire.resolve = resolve; Object.defineProperty(moduleRequire, 'main', { enumerable: true, From 93a024aa7f66b3c0c15aed3f6774581868ce16cc Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Mon, 25 Feb 2019 01:29:25 +0100 Subject: [PATCH 11/15] use common global type declaration --- packages/jest-environment/package.json | 1 - packages/jest-environment/src/index.ts | 10 ++-------- packages/jest-types/src/Global.ts | 10 +++++++++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/jest-environment/package.json b/packages/jest-environment/package.json index beb221061281..d1888425032d 100644 --- a/packages/jest-environment/package.json +++ b/packages/jest-environment/package.json @@ -12,7 +12,6 @@ "dependencies": { "@jest/transform": "^24.1.0", "@jest/types": "^24.1.0", - "@types/istanbul-lib-coverage": "^1.1.0", "@types/node": "*", "jest-mock": "^24.0.0" }, diff --git a/packages/jest-environment/src/index.ts b/packages/jest-environment/src/index.ts index aa044f28afb0..8f9d1e08502e 100644 --- a/packages/jest-environment/src/index.ts +++ b/packages/jest-environment/src/index.ts @@ -6,20 +6,15 @@ */ import {Script} from 'vm'; -import {Config} from '@jest/types'; +import {Config, Global} from '@jest/types'; import moduleMocker from 'jest-mock'; import {ScriptTransformer} from '@jest/transform'; -// eslint-disable-next-line import/no-extraneous-dependencies -import {CoverageMapData} from 'istanbul-lib-coverage'; export type EnvironmentContext = { console?: Console; testPath?: Config.Path; }; -// TODO: Get rid of this at some point -type JasmineType = {_DEFAULT_TIMEOUT_INTERVAL?: number; addMatchers: Function}; - // TODO: type this better: https://nodejs.org/api/modules.html#modules_the_module_wrapper type ModuleWrapper = (...args: Array) => unknown; @@ -31,8 +26,7 @@ export interface JestEnvironment { runScript( script: Script, ): {[ScriptTransformer.EVAL_RESULT_VARIABLE]: ModuleWrapper} | null; - // TODO: Maybe add `| Window` in the future? - global: NodeJS.Global & {__coverage__: CoverageMapData; jasmine: JasmineType}; + global: Global.Global; // TODO: When `jest-util` is ESM, this can just be `fakeTimers: import('jest-util').FakeTimers` fakeTimers: { clearAllTimers(): void; diff --git a/packages/jest-types/src/Global.ts b/packages/jest-types/src/Global.ts index ed7739615e14..de0d500ca9cd 100644 --- a/packages/jest-types/src/Global.ts +++ b/packages/jest-types/src/Global.ts @@ -5,12 +5,17 @@ * LICENSE file in the root directory of this source tree. */ +import {CoverageMapData} from 'istanbul-lib-coverage'; + export type DoneFn = (reason?: string | Error) => void; export type TestName = string; export type TestFn = (done?: DoneFn) => Promise | void | undefined; export type BlockFn = () => void; export type BlockName = string; +// TODO: Get rid of this at some point +type JasmineType = {_DEFAULT_TIMEOUT_INTERVAL?: number; addMatchers: Function}; + // TODO Replace with actual type when `jest-each` is ready type Each = () => void; @@ -48,7 +53,8 @@ export interface Describe extends DescribeBase { skip: ItBase; } -export interface Global { +// TODO: Maybe add `| Window` in the future? +export interface Global extends NodeJS.Global { it: It; test: ItConcurrent; fit: ItBase; @@ -57,6 +63,8 @@ export interface Global { describe: Describe; xdescribe: DescribeBase; fdescribe: DescribeBase; + __coverage__: CoverageMapData; + jasmine: JasmineType; } declare global { From e24b5f27a21bc15e6585b7a9d44ad7b5244dfbf0 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Mon, 25 Feb 2019 11:04:01 +0100 Subject: [PATCH 12/15] tweaks after merge of master --- packages/jest-runner/package.json | 1 + packages/jest-runner/src/runTest.ts | 15 +++++---------- packages/jest-runner/src/testWorker.ts | 1 - packages/jest-runner/src/types.ts | 6 +++--- packages/jest-runner/tsconfig.json | 2 ++ packages/jest-runtime/src/index.ts | 8 ++++---- 6 files changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/jest-runner/package.json b/packages/jest-runner/package.json index 67cd2369cb63..bb54f544ac33 100644 --- a/packages/jest-runner/package.json +++ b/packages/jest-runner/package.json @@ -10,6 +10,7 @@ "main": "build/index.js", "types": "build/index.d.ts", "dependencies": { + "@jest/environment": "^24.1.0", "@jest/types": "^24.1.0", "chalk": "^2.4.2", "exit": "^0.1.2", diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index 7b581863bb2a..94c759a5188f 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -6,13 +6,8 @@ * */ -import { - Environment, - Config, - TestResult, - Console as ConsoleType, -} from '@jest/types'; -// @ts-ignore: not migrated to TS +import {Config, TestResult, Console as ConsoleType} from '@jest/types'; +import {JestEnvironment} from '@jest/environment'; import RuntimeClass from 'jest-runtime'; import fs from 'graceful-fs'; import { @@ -101,16 +96,16 @@ async function runTestInternal( }); } - const TestEnvironment: Environment.EnvironmentClass = require(testEnvironment); + const TestEnvironment: JestEnvironment = require(testEnvironment); const testFramework: TestFramework = process.env.JEST_CIRCUS === '1' ? require('jest-circus/runner') // eslint-disable-line import/no-extraneous-dependencies : require(config.testRunner); - const Runtime: RuntimeClass = config.moduleLoader + const Runtime: typeof RuntimeClass = config.moduleLoader ? require(config.moduleLoader) : require('jest-runtime'); - let runtime: RuntimeClass = undefined; + let runtime: RuntimeClass | undefined = undefined; const consoleOut = globalConfig.useStderr ? process.stderr : process.stdout; const consoleFormatter = ( diff --git a/packages/jest-runner/src/testWorker.ts b/packages/jest-runner/src/testWorker.ts index 51c8fbc3dd1c..fed1e1e4a669 100644 --- a/packages/jest-runner/src/testWorker.ts +++ b/packages/jest-runner/src/testWorker.ts @@ -10,7 +10,6 @@ import {Config, TestResult} from '@jest/types'; import HasteMap, {SerializableModuleMap, ModuleMap} from 'jest-haste-map'; import exit from 'exit'; import {separateMessageFromStack} from 'jest-message-util'; -// @ts-ignore: Not migrated to TS import Runtime from 'jest-runtime'; import {ErrorWithCode, TestRunnerContext} from './types'; import runTest from './runTest'; diff --git a/packages/jest-runner/src/types.ts b/packages/jest-runner/src/types.ts index 5f1aeb7c557a..86f26d086fa2 100644 --- a/packages/jest-runner/src/types.ts +++ b/packages/jest-runner/src/types.ts @@ -6,10 +6,10 @@ */ import {EventEmitter} from 'events'; -import {Environment, Config, TestResult} from '@jest/types'; +import {Config, TestResult} from '@jest/types'; +import {JestEnvironment} from '@jest/environment'; import {ModuleMap, FS as HasteFS} from 'jest-haste-map'; import HasteResolver from 'jest-resolve'; -// @ts-ignore: not migrated to TS import Runtime from 'jest-runtime'; export type ErrorWithCode = Error & {code?: string}; @@ -63,7 +63,7 @@ export type Reporter = { export type TestFramework = ( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, - environment: Environment.Environment, + environment: JestEnvironment, runtime: Runtime, testPath: string, ) => Promise; diff --git a/packages/jest-runner/tsconfig.json b/packages/jest-runner/tsconfig.json index 59665ff7c74e..72bf161339bc 100644 --- a/packages/jest-runner/tsconfig.json +++ b/packages/jest-runner/tsconfig.json @@ -6,10 +6,12 @@ }, "references": [ {"path": "../jest-docblock"}, + {"path": "../jest-environment"}, {"path": "../jest-haste-map"}, {"path": "../jest-leak-detector"}, {"path": "../jest-message-util"}, {"path": "../jest-resolve"}, + {"path": "../jest-runtime"}, {"path": "../jest-types"}, {"path": "../jest-worker"}, {"path": "../jest-util"} diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index ce01456853ff..cbdc2ae0d83d 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -6,14 +6,14 @@ */ import path from 'path'; -import {Argv, Config, Mocks, SourceMaps} from '@jest/types'; +import {Argv, Config, SourceMaps} from '@jest/types'; import { Jest, JestEnvironment, LocalModuleRequire, Module, } from '@jest/environment'; -import jestMock from 'jest-mock'; +import jestMock, {MockFunctionMetadata} from 'jest-mock'; import HasteMap, {ModuleMap} from 'jest-haste-map'; import {formatStackTrace, separateMessageFromStack} from 'jest-message-util'; import Resolver from 'jest-resolve'; @@ -85,7 +85,7 @@ class Runtime { private _isCurrentlyExecutingManualMock: string | null; private _mockFactories: {[key: string]: () => unknown}; private _mockMetaDataCache: { - [key: string]: Mocks.MockFunctionMetadata; + [key: string]: MockFunctionMetadata; }; private _mockRegistry: {[key: string]: any}; private _isolatedMockRegistry: {[key: string]: any} | null; @@ -504,7 +504,7 @@ class Runtime { getSourceMapInfo(coveredFiles: Set) { return Object.keys(this._sourceMapRegistry).reduce<{ - [path: string]: unknown; + [path: string]: string; }>((result, sourcePath) => { if ( coveredFiles.has(sourcePath) && From 0375e70f7ccb7e100361d603bf14131ee3c3fe09 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Mon, 25 Feb 2019 11:34:18 +0100 Subject: [PATCH 13/15] correctly export runtime cli argument types --- packages/jest-runtime/package.json | 2 +- packages/jest-runtime/src/cli/args.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/jest-runtime/package.json b/packages/jest-runtime/package.json index 29cce481fb07..f2f36459e08b 100644 --- a/packages/jest-runtime/package.json +++ b/packages/jest-runtime/package.json @@ -13,6 +13,7 @@ "@jest/environment": "^24.1.0", "@jest/transform": "^24.1.0", "@jest/types": "^24.1.0", + "@types/yargs": "^12.0.2", "chalk": "^2.0.1", "exit": "^0.1.2", "glob": "^7.1.3", @@ -37,7 +38,6 @@ "@types/graceful-fs": "^4.1.2", "@types/slash": "^2.0.0", "@types/strip-bom": "^3.0.0", - "@types/yargs": "^12.0.2", "jest-environment-node": "^24.0.0" }, "bin": { diff --git a/packages/jest-runtime/src/cli/args.ts b/packages/jest-runtime/src/cli/args.ts index 7e7055780a36..7af5ba6c24f5 100644 --- a/packages/jest-runtime/src/cli/args.ts +++ b/packages/jest-runtime/src/cli/args.ts @@ -9,7 +9,10 @@ import {Options} from 'yargs'; export const usage = 'Usage: $0 [--config=] '; -export const options: {[key: string]: Options} = { +export const options: Record< + 'cache' | 'config' | 'debug' | 'version' | 'watchman', + Options +> = { cache: { default: true, description: From 5ea519b7f363512a68927ccf0483d7c4b00d422e Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Mon, 25 Feb 2019 11:49:07 +0100 Subject: [PATCH 14/15] don't keep separate argv config file --- packages/jest-runtime/src/cli/index.ts | 4 +- packages/jest-runtime/src/index.ts | 4 +- packages/jest-types/src/Argv.ts | 98 -------------------------- packages/jest-types/src/Config.ts | 93 ++++++++++++++++++++++++ packages/jest-types/src/index.ts | 3 +- 5 files changed, 98 insertions(+), 104 deletions(-) delete mode 100644 packages/jest-types/src/Argv.ts diff --git a/packages/jest-runtime/src/cli/index.ts b/packages/jest-runtime/src/cli/index.ts index b674801c7c51..cb4527e312ec 100644 --- a/packages/jest-runtime/src/cli/index.ts +++ b/packages/jest-runtime/src/cli/index.ts @@ -10,7 +10,7 @@ import path from 'path'; import chalk from 'chalk'; import {sync as realpath} from 'realpath-native'; import yargs from 'yargs'; -import {Argv} from '@jest/types'; +import {Config} from '@jest/types'; import {JestEnvironment} from '@jest/environment'; import {Console, setGlobal} from 'jest-util'; // @ts-ignore: Not migrated to TS @@ -21,7 +21,7 @@ import {VERSION} from '../version'; import {Context} from '../types'; import * as args from './args'; -export function run(cliArgv?: Argv.Argv, cliInfo?: Array) { +export function run(cliArgv?: Config.Argv, cliInfo?: Array) { const realFs = require('fs'); const fs = require('graceful-fs'); fs.gracefulify(realFs); diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index cbdc2ae0d83d..6c8849a792ee 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -6,7 +6,7 @@ */ import path from 'path'; -import {Argv, Config, SourceMaps} from '@jest/types'; +import {Config, SourceMaps} from '@jest/types'; import { Jest, JestEnvironment, @@ -264,7 +264,7 @@ class Runtime { }); } - static runCLI(args?: Argv.Argv, info?: Array) { + static runCLI(args?: Config.Argv, info?: Array) { return cliRun(args, info); } diff --git a/packages/jest-types/src/Argv.ts b/packages/jest-types/src/Argv.ts deleted file mode 100644 index 84d4f66893cc..000000000000 --- a/packages/jest-types/src/Argv.ts +++ /dev/null @@ -1,98 +0,0 @@ -/** - * 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 {Arguments} from 'yargs'; - -export type Argv = Arguments<{ - all: boolean; - automock: boolean; - bail: boolean | number; - browser: boolean; - cache: boolean; - cacheDirectory: string; - changedFilesWithAncestor: boolean; - changedSince: string; - ci: boolean; - clearCache: boolean; - clearMocks: boolean; - collectCoverage: boolean; - collectCoverageFrom: Array; - collectCoverageOnlyFrom: Array; - config: string; - coverage: boolean; - coverageDirectory: string; - coveragePathIgnorePatterns: Array; - coverageReporters: Array; - coverageThreshold: string; - debug: boolean; - env: string; - expand: boolean; - findRelatedTests: boolean; - forceExit: boolean; - globals: string; - globalSetup: string | null | undefined; - globalTeardown: string | null | undefined; - h: boolean; - haste: string; - help: boolean; - init: boolean; - json: boolean; - lastCommit: boolean; - logHeapUsage: boolean; - maxWorkers: number; - moduleDirectories: Array; - moduleFileExtensions: Array; - moduleLoader: string; - moduleNameMapper: string; - modulePathIgnorePatterns: Array; - modulePaths: Array; - name: string; - noSCM: boolean; - noStackTrace: boolean; - notify: boolean; - notifyMode: string; - onlyChanged: boolean; - outputFile: string; - preset: string | null | undefined; - projects: Array; - prettierPath: string | null | undefined; - replname: string | null | undefined; - resetMocks: boolean; - resetModules: boolean; - resolver: string | null | undefined; - restoreMocks: boolean; - rootDir: string; - roots: Array; - runInBand: boolean; - setupFiles: Array; - setupFilesAfterEnv: Array; - showConfig: boolean; - silent: boolean; - snapshotSerializers: Array; - testEnvironment: string; - testFailureExitCode: string | null | undefined; - testMatch: Array; - testNamePattern: string; - testPathIgnorePatterns: Array; - testPathPattern: Array; - testRegex: string | Array; - testResultsProcessor: string | null | undefined; - testRunner: string; - testURL: string; - timers: 'real' | 'fake'; - transform: string; - transformIgnorePatterns: Array; - unmockedModulePathPatterns: Array | null | undefined; - updateSnapshot: boolean; - useStderr: boolean; - verbose: boolean | null | undefined; - version: boolean; - watch: boolean; - watchAll: boolean; - watchman: boolean; - watchPathIgnorePatterns: Array; -}>; diff --git a/packages/jest-types/src/Config.ts b/packages/jest-types/src/Config.ts index 36209c91ee97..eeb6b8e2789e 100644 --- a/packages/jest-types/src/Config.ts +++ b/packages/jest-types/src/Config.ts @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. */ +import {Arguments} from 'yargs'; + export type Path = string; export type Glob = string; @@ -355,3 +357,94 @@ export type ProjectConfig = { watchPathIgnorePatterns: Array; unmockedModulePathPatterns: Array | null | undefined; }; + +export type Argv = Arguments<{ + all: boolean; + automock: boolean; + bail: boolean | number; + browser: boolean; + cache: boolean; + cacheDirectory: string; + changedFilesWithAncestor: boolean; + changedSince: string; + ci: boolean; + clearCache: boolean; + clearMocks: boolean; + collectCoverage: boolean; + collectCoverageFrom: Array; + collectCoverageOnlyFrom: Array; + config: string; + coverage: boolean; + coverageDirectory: string; + coveragePathIgnorePatterns: Array; + coverageReporters: Array; + coverageThreshold: string; + debug: boolean; + env: string; + expand: boolean; + findRelatedTests: boolean; + forceExit: boolean; + globals: string; + globalSetup: string | null | undefined; + globalTeardown: string | null | undefined; + h: boolean; + haste: string; + help: boolean; + init: boolean; + json: boolean; + lastCommit: boolean; + logHeapUsage: boolean; + maxWorkers: number; + moduleDirectories: Array; + moduleFileExtensions: Array; + moduleLoader: string; + moduleNameMapper: string; + modulePathIgnorePatterns: Array; + modulePaths: Array; + name: string; + noSCM: boolean; + noStackTrace: boolean; + notify: boolean; + notifyMode: string; + onlyChanged: boolean; + outputFile: string; + preset: string | null | undefined; + projects: Array; + prettierPath: string | null | undefined; + replname: string | null | undefined; + resetMocks: boolean; + resetModules: boolean; + resolver: string | null | undefined; + restoreMocks: boolean; + rootDir: string; + roots: Array; + runInBand: boolean; + setupFiles: Array; + setupFilesAfterEnv: Array; + showConfig: boolean; + silent: boolean; + snapshotSerializers: Array; + testEnvironment: string; + testFailureExitCode: string | null | undefined; + testMatch: Array; + testNamePattern: string; + testPathIgnorePatterns: Array; + testPathPattern: Array; + testRegex: string | Array; + testResultsProcessor: string | null | undefined; + testRunner: string; + testURL: string; + timers: 'real' | 'fake'; + transform: string; + transformIgnorePatterns: Array; + unmockedModulePathPatterns: Array | null | undefined; + updateSnapshot: boolean; + useStderr: boolean; + verbose: boolean | null | undefined; + version: boolean; + watch: boolean; + watchAll: boolean; + watchman: boolean; + watchPathIgnorePatterns: Array; +}>; + diff --git a/packages/jest-types/src/index.ts b/packages/jest-types/src/index.ts index 7d869b686966..458831633460 100644 --- a/packages/jest-types/src/index.ts +++ b/packages/jest-types/src/index.ts @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -import * as Argv from './Argv'; import * as Config from './Config'; import * as Console from './Console'; import * as Matchers from './Matchers'; @@ -13,4 +12,4 @@ import * as SourceMaps from './SourceMaps'; import * as TestResult from './TestResult'; import * as Global from './Global'; -export {Argv, Config, Console, Matchers, SourceMaps, TestResult, Global}; +export {Config, Console, Matchers, SourceMaps, TestResult, Global}; From 79a59aa8e7aa026164e14caaa545d5ddddf07cde Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Mon, 25 Feb 2019 12:12:21 +0100 Subject: [PATCH 15/15] lint --- packages/jest-types/src/Config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/jest-types/src/Config.ts b/packages/jest-types/src/Config.ts index eeb6b8e2789e..bdd9c64efc39 100644 --- a/packages/jest-types/src/Config.ts +++ b/packages/jest-types/src/Config.ts @@ -447,4 +447,3 @@ export type Argv = Arguments<{ watchman: boolean; watchPathIgnorePatterns: Array; }>; -