diff --git a/CHANGELOG.md b/CHANGELOG.md index 039968ce1d74..b02a9d22fc9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,7 @@ - `[jest-repl]`: Migrate to TypeScript ([#8000](https://github.com/facebook/jest/pull/8000)) - `[jest-validate]`: Migrate to TypeScript ([#7991](https://github.com/facebook/jest/pull/7991)) - `[docs]`: Update CONTRIBUTING.md to add information about running jest with `jest-circus` locally ([#8013](https://github.com/facebook/jest/pull/8013)). +- `[@jest/core]`: Migrate to TypeScript ([#7998](https://github.com/facebook/jest/pull/7998)) ### Performance diff --git a/packages/jest-changed-files/src/index.ts b/packages/jest-changed-files/src/index.ts index 9d31072168e6..0b8c802e915d 100644 --- a/packages/jest-changed-files/src/index.ts +++ b/packages/jest-changed-files/src/index.ts @@ -15,6 +15,8 @@ import hg from './hg'; type RootPromise = ReturnType; +export {ChangedFiles, ChangedFilesPromise} from './types'; + function notEmpty(value: T | null | undefined): value is T { return value != null; } diff --git a/packages/jest-changed-files/src/types.ts b/packages/jest-changed-files/src/types.ts index 3d040a6c49dd..e45c07d3eb37 100644 --- a/packages/jest-changed-files/src/types.ts +++ b/packages/jest-changed-files/src/types.ts @@ -14,12 +14,10 @@ export type Options = { includePaths?: Array; }; -type ChangedFiles = Set; -export type Repos = {git: ChangedFiles; hg: ChangedFiles}; -export type ChangedFilesPromise = Promise<{ - repos: Repos; - changedFiles: ChangedFiles; -}>; +type Paths = Set; +export type Repos = {git: Paths; hg: Paths}; +export type ChangedFiles = {repos: Repos; changedFiles: Paths}; +export type ChangedFilesPromise = Promise; export type SCMAdapter = { findChangedFiles: ( diff --git a/packages/jest-core/package.json b/packages/jest-core/package.json index adc6256996b9..df5b1957d691 100644 --- a/packages/jest-core/package.json +++ b/packages/jest-core/package.json @@ -4,6 +4,7 @@ "version": "24.1.0", "main": "build/jest.js", "dependencies": { + "@jest/types": "^24.1.0", "@jest/reporters": "^24.1.0", "@jest/transform": "^24.1.0", "ansi-escapes": "^3.0.0", @@ -24,7 +25,7 @@ "jest-watcher": "^24.0.0", "micromatch": "^3.1.10", "p-each-series": "^1.0.0", - "pirates": "^4.0.0", + "pirates": "^4.0.1", "realpath-native": "^1.1.0", "rimraf": "^2.5.4", "strip-ansi": "^5.0.0" diff --git a/packages/jest-core/src/FailedTestsCache.js b/packages/jest-core/src/FailedTestsCache.ts similarity index 51% rename from packages/jest-core/src/FailedTestsCache.js rename to packages/jest-core/src/FailedTestsCache.ts index 73c0970e1646..f0bb0fde064d 100644 --- a/packages/jest-core/src/FailedTestsCache.js +++ b/packages/jest-core/src/FailedTestsCache.ts @@ -3,45 +3,49 @@ * * 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 {Test} from 'types/TestRunner'; -import type {TestResult} from 'types/TestResult'; -import type {GlobalConfig} from 'types/Config'; +import {Test} from 'jest-runner'; +import {Config, TestResult} from '@jest/types'; + +type TestMap = {[key: string]: {[key: string]: boolean}}; export default class FailedTestsCache { - _enabledTestsMap: ?{[key: string]: {[key: string]: boolean}}; + private _enabledTestsMap?: TestMap; filterTests(tests: Array): Array { - if (!this._enabledTestsMap) { + const enabledTestsMap = this._enabledTestsMap; + + if (!enabledTestsMap) { return tests; } - // $FlowFixMe - return tests.filter(testResult => this._enabledTestsMap[testResult.path]); + return tests.filter(testResult => enabledTestsMap[testResult.path]); } - setTestResults(testResults: Array) { + setTestResults(testResults: Array) { this._enabledTestsMap = (testResults || []) .filter(testResult => testResult.numFailingTests) - .reduce((suiteMap, testResult) => { + .reduce((suiteMap, testResult) => { suiteMap[testResult.testFilePath] = testResult.testResults .filter(test => test.status === 'failed') - .reduce((testMap, test) => { - testMap[test.fullName] = true; - return testMap; - }, {}); + .reduce( + (testMap, test) => { + testMap[test.fullName] = true; + return testMap; + }, + {} as {[name: string]: true}, + ); return suiteMap; }, {}); + this._enabledTestsMap = Object.freeze(this._enabledTestsMap); } - updateConfig(globalConfig: GlobalConfig): GlobalConfig { + updateConfig(globalConfig: Config.GlobalConfig): Config.GlobalConfig { if (!this._enabledTestsMap) { return globalConfig; } - const newConfig: GlobalConfig = {...globalConfig}; + const newConfig: Config.GlobalConfig = {...globalConfig}; newConfig.enabledTestsMap = this._enabledTestsMap; return Object.freeze(newConfig); } diff --git a/packages/jest-core/src/ReporterDispatcher.js b/packages/jest-core/src/ReporterDispatcher.ts similarity index 69% rename from packages/jest-core/src/ReporterDispatcher.js rename to packages/jest-core/src/ReporterDispatcher.ts index 6e492dcd571b..b36299aa1cb9 100644 --- a/packages/jest-core/src/ReporterDispatcher.js +++ b/packages/jest-core/src/ReporterDispatcher.ts @@ -3,23 +3,15 @@ * * 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 {Context} from 'types/Context'; -import type {Reporter, Test} from 'types/TestRunner'; -import type {TestResult, AggregatedResult} from 'types/TestResult'; -import type {ReporterOnStartOptions} from 'types/Reporters'; - -export type RunOptions = {| - estimatedTime: number, - showStatus: boolean, -|}; +import {TestResult} from '@jest/types'; +import {Test} from 'jest-runner'; +import {Context} from 'jest-runtime'; +import {Reporter, ReporterOnStartOptions} from './types'; export default class ReporterDispatcher { - _disabled: boolean; - _reporters: Array; + private _reporters: Array; constructor() { this._reporters = []; @@ -37,8 +29,8 @@ export default class ReporterDispatcher { async onTestResult( test: Test, - testResult: TestResult, - results: AggregatedResult, + testResult: TestResult.TestResult, + results: TestResult.AggregatedResult, ) { for (const reporter of this._reporters) { reporter.onTestResult && @@ -52,13 +44,19 @@ export default class ReporterDispatcher { } } - async onRunStart(results: AggregatedResult, options: ReporterOnStartOptions) { + async onRunStart( + results: TestResult.AggregatedResult, + options: ReporterOnStartOptions, + ) { for (const reporter of this._reporters) { reporter.onRunStart && (await reporter.onRunStart(results, options)); } } - async onRunComplete(contexts: Set, results: AggregatedResult) { + async onRunComplete( + contexts: Set, + results: TestResult.AggregatedResult, + ) { for (const reporter of this._reporters) { reporter.onRunComplete && (await reporter.onRunComplete(contexts, results)); @@ -67,7 +65,7 @@ export default class ReporterDispatcher { // Return a list of last errors for every reporter getErrors(): Array { - return this._reporters.reduce((list, reporter) => { + return this._reporters.reduce>((list, reporter) => { const error = reporter.getLastError && reporter.getLastError(); return error ? list.concat(error) : list; }, []); diff --git a/packages/jest-core/src/SearchSource.js b/packages/jest-core/src/SearchSource.ts similarity index 70% rename from packages/jest-core/src/SearchSource.js rename to packages/jest-core/src/SearchSource.ts index bba5158d00e6..5c1992b55d94 100644 --- a/packages/jest-core/src/SearchSource.js +++ b/packages/jest-core/src/SearchSource.ts @@ -3,52 +3,55 @@ * * 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 {Context} from 'types/Context'; -import type {Glob, GlobalConfig, Path} from 'types/Config'; -import type {Test} from 'types/TestRunner'; -import type {ChangedFilesInfo} from 'types/ChangedFiles'; - import path from 'path'; import micromatch from 'micromatch'; +import {Context} from 'jest-runtime'; +import {Config} from '@jest/types'; +import {Test} from 'jest-runner'; +import {ChangedFiles} from 'jest-changed-files'; import DependencyResolver from 'jest-resolve-dependencies'; import {escapePathForRegex} from 'jest-regex-util'; import {replaceRootDirInPath} from 'jest-config'; import {buildSnapshotResolver} from 'jest-snapshot'; import {replacePathSepForGlob, testPathPatternToRegExp} from 'jest-util'; +import { + Stats, + TestPathCases, + TestPathCasesWithPathPattern, + TestPathCaseWithPathPatternStats, +} from './types'; + +export type SearchResult = { + noSCM?: boolean; + stats?: Stats; + collectCoverageFrom?: Set; + tests: Array; + total?: number; +}; -type SearchResult = {| - noSCM?: boolean, - stats?: {[key: string]: number}, - collectCoverageFrom?: Set, - tests: Array, - total?: number, -|}; - -export type TestSelectionConfig = {| - input?: string, - findRelatedTests?: boolean, - onlyChanged?: boolean, - paths?: Array, - shouldTreatInputAsPattern?: boolean, - testPathPattern?: string, - watch?: boolean, -|}; +export type TestSelectionConfig = { + input?: string; + findRelatedTests?: boolean; + onlyChanged?: boolean; + paths?: Array; + shouldTreatInputAsPattern?: boolean; + testPathPattern?: string; + watch?: boolean; +}; type FilterResult = { - test: string, - message: string, + test: string; + message: string; }; -const globsToMatcher = (globs: ?Array) => { +const globsToMatcher = (globs?: Array | null) => { if (globs == null || globs.length === 0) { return () => true; } - return path => + return (path: Config.Path) => micromatch.some(replacePathSepForGlob(path), globs, {dot: true}); }; @@ -57,10 +60,11 @@ const regexToMatcher = (testRegex: Array) => { return () => true; } - return path => testRegex.some(testRegex => new RegExp(testRegex).test(path)); + return (path: Config.Path) => + testRegex.some(testRegex => new RegExp(testRegex).test(path)); }; -const toTests = (context, tests) => +const toTests = (context: Context, tests: Array) => tests.map(path => ({ context, duration: undefined, @@ -68,15 +72,10 @@ const toTests = (context, tests) => })); export default class SearchSource { - _context: Context; - _rootPattern: RegExp; - _testIgnorePattern: ?RegExp; - _testPathCases: { - roots: (path: Path) => boolean, - testMatch: (path: Path) => boolean, - testRegex: (path: Path) => boolean, - testPathIgnorePatterns: (path: Path) => boolean, - }; + private _context: Context; + private _rootPattern: RegExp; + private _testIgnorePattern: RegExp | null; + private _testPathCases: TestPathCases; constructor(context: Context) { const {config} = context; @@ -99,12 +98,21 @@ export default class SearchSource { }; } - _filterTestPathsWithStats( + private _filterTestPathsWithStats( allPaths: Array, testPathPattern?: string, ): SearchResult { - const data = { - stats: {}, + const data: { + stats: Stats; + tests: Array; + total: number; + } = { + stats: { + roots: 0, + testMatch: 0, + testPathIgnorePatterns: 0, + testRegex: 0, + }, tests: [], total: allPaths.length, }; @@ -112,17 +120,21 @@ export default class SearchSource { const testCases = Object.assign({}, this._testPathCases); if (testPathPattern) { const regex = testPathPatternToRegExp(testPathPattern); - testCases.testPathPattern = path => regex.test(path); + (testCases as TestPathCasesWithPathPattern).testPathPattern = ( + path: Config.Path, + ) => regex.test(path); + (data.stats as TestPathCaseWithPathPatternStats).testPathPattern = 0; } - const testCasesKeys = Object.keys(testCases); + const testCasesKeys = Object.keys(testCases) as Array; data.tests = allPaths.filter(test => testCasesKeys.reduce((flag, key) => { + const {stats} = data; if (testCases[key](test.path)) { - data.stats[key] = ++data.stats[key] || 1; + stats[key] = stats[key] === undefined ? 1 : stats[key] + 1; return flag && true; } - data.stats[key] = data.stats[key] || 0; + stats[key] = stats[key] || 0; return false; }, true), ); @@ -130,25 +142,25 @@ export default class SearchSource { return data; } - _getAllTestPaths(testPathPattern: string): SearchResult { + private _getAllTestPaths(testPathPattern?: string): SearchResult { return this._filterTestPathsWithStats( toTests(this._context, this._context.hasteFS.getAllFiles()), testPathPattern, ); } - isTestFilePath(path: Path): boolean { - return Object.keys(this._testPathCases).every(key => - this._testPathCases[key](path), - ); + isTestFilePath(path: Config.Path): boolean { + return (Object.keys(this._testPathCases) as Array< + keyof TestPathCases + >).every(key => this._testPathCases[key](path)); } - findMatchingTests(testPathPattern: string): SearchResult { + findMatchingTests(testPathPattern?: string): SearchResult { return this._getAllTestPaths(testPathPattern); } findRelatedTests( - allPaths: Set, + allPaths: Set, collectCoverage: boolean, ): SearchResult { const dependencyResolver = new DependencyResolver( @@ -208,7 +220,7 @@ export default class SearchSource { }; } - findTestsByPaths(paths: Array): SearchResult { + findTestsByPaths(paths: Array): SearchResult { return { tests: toTests( this._context, @@ -220,7 +232,7 @@ export default class SearchSource { } findRelatedTestsFromPattern( - paths: Array, + paths: Array, collectCoverage: boolean, ): SearchResult { if (Array.isArray(paths) && paths.length) { @@ -233,20 +245,22 @@ export default class SearchSource { } findTestRelatedToChangedFiles( - changedFilesInfo: ChangedFilesInfo, + changedFilesInfo: ChangedFiles, collectCoverage: boolean, ) { const {repos, changedFiles} = changedFilesInfo; // no SCM (git/hg/...) is found in any of the roots. - const noSCM = Object.keys(repos).every(scm => repos[scm].size === 0); + const noSCM = (Object.keys(repos) as Array< + keyof ChangedFiles['repos'] + >).every(scm => repos[scm].size === 0); return noSCM ? {noSCM: true, tests: []} : this.findRelatedTests(changedFiles, collectCoverage); } - _getTestPaths( - globalConfig: GlobalConfig, - changedFiles: ?ChangedFilesInfo, + private _getTestPaths( + globalConfig: Config.GlobalConfig, + changedFiles?: ChangedFiles, ): SearchResult { const paths = globalConfig.nonFlagArgs; @@ -274,8 +288,8 @@ export default class SearchSource { } async getTestPaths( - globalConfig: GlobalConfig, - changedFiles: ?ChangedFilesInfo, + globalConfig: Config.GlobalConfig, + changedFiles: ChangedFiles | undefined, ): Promise { const searchResult = this._getTestPaths(globalConfig, changedFiles); @@ -284,9 +298,10 @@ export default class SearchSource { if (filterPath && !globalConfig.skipFilter) { const tests = searchResult.tests; - // $FlowFixMe: dynamic require. - const filter: Array = require(filterPath); - const filterResult = await filter(tests.map(test => test.path)); + const filter = require(filterPath); + const filterResult: {filtered: Array} = await filter( + tests.map(test => test.path), + ); if (!Array.isArray(filterResult.filtered)) { throw new Error( diff --git a/packages/jest-core/src/SnapshotInteractiveMode.js b/packages/jest-core/src/SnapshotInteractiveMode.ts similarity index 85% rename from packages/jest-core/src/SnapshotInteractiveMode.js rename to packages/jest-core/src/SnapshotInteractiveMode.ts index 07c2a5a8f478..ab09e39c6979 100644 --- a/packages/jest-core/src/SnapshotInteractiveMode.js +++ b/packages/jest-core/src/SnapshotInteractiveMode.ts @@ -4,14 +4,11 @@ * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow */ -import type {AggregatedResult, AssertionLocation} from 'types/TestResult'; - import chalk from 'chalk'; import ansiEscapes from 'ansi-escapes'; +import {TestResult} from '@jest/types'; import {KEYS} from 'jest-watcher'; import {pluralize, specialChars} from 'jest-util'; @@ -19,17 +16,17 @@ import {pluralize, specialChars} from 'jest-util'; const {ARROW, CLEAR} = specialChars; export default class SnapshotInteractiveMode { - _pipe: stream$Writable | tty$WriteStream; - _isActive: boolean; - _updateTestRunnerConfig: ( - assertion: ?AssertionLocation, + private _pipe: NodeJS.WritableStream; + private _isActive: boolean; + private _updateTestRunnerConfig!: ( + assertion: TestResult.AssertionLocation | null, shouldUpdateSnapshot: boolean, - ) => *; - _testAssertions: Array; - _countPaths: number; - _skippedNum: number; + ) => unknown; + private _testAssertions!: Array; + private _countPaths!: number; + private _skippedNum: number; - constructor(pipe: stream$Writable | tty$WriteStream) { + constructor(pipe: NodeJS.WritableStream) { this._pipe = pipe; this._isActive = false; this._skippedNum = 0; @@ -43,12 +40,12 @@ export default class SnapshotInteractiveMode { return this._skippedNum; } - _clearTestSummary() { + private _clearTestSummary() { this._pipe.write(ansiEscapes.cursorUp(6)); this._pipe.write(ansiEscapes.eraseDown); } - _drawUIProgress() { + private _drawUIProgress() { this._clearTestSummary(); const numPass = this._countPaths - this._testAssertions.length; const numRemaining = this._countPaths - numPass - this._skippedNum; @@ -90,7 +87,7 @@ export default class SnapshotInteractiveMode { this._pipe.write(messages.filter(Boolean).join('\n') + '\n'); } - _drawUIDoneWithSkipped() { + private _drawUIDoneWithSkipped() { this._pipe.write(CLEAR); const numPass = this._countPaths - this._testAssertions.length; @@ -123,7 +120,7 @@ export default class SnapshotInteractiveMode { this._pipe.write(messages.filter(Boolean).join('\n') + '\n'); } - _drawUIDone() { + private _drawUIDone() { this._pipe.write(CLEAR); const numPass = this._countPaths - this._testAssertions.length; @@ -147,7 +144,7 @@ export default class SnapshotInteractiveMode { this._pipe.write(messages.filter(Boolean).join('\n') + '\n'); } - _drawUIOverlay() { + private _drawUIOverlay() { if (this._testAssertions.length === 0) { return this._drawUIDone(); } @@ -166,7 +163,7 @@ export default class SnapshotInteractiveMode { this._skippedNum += 1; // move skipped test to the end - this._testAssertions.push(this._testAssertions.shift()); + this._testAssertions.push(this._testAssertions.shift()!); if (this._testAssertions.length - this._skippedNum > 0) { this._run(false); } else { @@ -208,7 +205,7 @@ export default class SnapshotInteractiveMode { this._run(false); } - updateWithResults(results: AggregatedResult) { + updateWithResults(results: TestResult.AggregatedResult) { const hasSnapshotFailure = !!results.snapshot.failure; if (hasSnapshotFailure) { this._drawUIOverlay(); @@ -225,23 +222,23 @@ export default class SnapshotInteractiveMode { this._run(false); } - _run(shouldUpdateSnapshot: boolean) { + private _run(shouldUpdateSnapshot: boolean) { const testAssertion = this._testAssertions[0]; this._updateTestRunnerConfig(testAssertion, shouldUpdateSnapshot); } run( - failedSnapshotTestAssertions: Array, + failedSnapshotTestAssertions: Array, onConfigChange: ( - assertion: ?AssertionLocation, + assertion: TestResult.AssertionLocation | null, shouldUpdateSnapshot: boolean, - ) => *, + ) => unknown, ) { if (!failedSnapshotTestAssertions.length) { return; } - this._testAssertions = [].concat(failedSnapshotTestAssertions); + this._testAssertions = [...failedSnapshotTestAssertions]; this._countPaths = this._testAssertions.length; this._updateTestRunnerConfig = onConfigChange; this._isActive = true; diff --git a/packages/jest-core/src/TestNamePatternPrompt.js b/packages/jest-core/src/TestNamePatternPrompt.ts similarity index 72% rename from packages/jest-core/src/TestNamePatternPrompt.js rename to packages/jest-core/src/TestNamePatternPrompt.ts index bf728f272fa8..fe55aa6caf01 100644 --- a/packages/jest-core/src/TestNamePatternPrompt.js +++ b/packages/jest-core/src/TestNamePatternPrompt.ts @@ -3,24 +3,22 @@ * * 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 {TestResult} from 'types/TestResult'; -import type {ScrollOptions} from 'types/Watch'; - import { PatternPrompt, Prompt, + ScrollOptions, printPatternCaret, printRestoredPatternCaret, } from 'jest-watcher'; +import {TestResult} from '@jest/types'; +// TODO: Make underscored props `private` export default class TestNamePatternPrompt extends PatternPrompt { - _cachedTestResults: Array; + _cachedTestResults: Array; - constructor(pipe: stream$Writable | tty$WriteStream, prompt: Prompt) { + constructor(pipe: NodeJS.WritableStream, prompt: Prompt) { super(pipe, prompt); this._entityName = 'tests'; this._cachedTestResults = []; @@ -28,17 +26,17 @@ export default class TestNamePatternPrompt extends PatternPrompt { _onChange(pattern: string, options: ScrollOptions) { super._onChange(pattern, options); - this._printPrompt(pattern, options); + this._printPrompt(pattern); } - _printPrompt(pattern: string, options: ScrollOptions) { + _printPrompt(pattern: string) { const pipe = this._pipe; printPatternCaret(pattern, pipe); printRestoredPatternCaret(pattern, this._currentUsageRows, pipe); } _getMatchedTests(pattern: string) { - let regex; + let regex: RegExp; try { regex = new RegExp(pattern, 'i'); @@ -46,7 +44,7 @@ export default class TestNamePatternPrompt extends PatternPrompt { return []; } - const matchedTests = []; + const matchedTests: Array = []; this._cachedTestResults.forEach(({testResults}) => testResults.forEach(({title}) => { @@ -59,7 +57,7 @@ export default class TestNamePatternPrompt extends PatternPrompt { return matchedTests; } - updateCachedTestResults(testResults: Array = []) { + updateCachedTestResults(testResults: Array = []) { this._cachedTestResults = testResults; } } diff --git a/packages/jest-core/src/TestPathPatternPrompt.js b/packages/jest-core/src/TestPathPatternPrompt.ts similarity index 64% rename from packages/jest-core/src/TestPathPatternPrompt.js rename to packages/jest-core/src/TestPathPatternPrompt.ts index 330be132fdbe..47922c4e91c5 100644 --- a/packages/jest-core/src/TestPathPatternPrompt.js +++ b/packages/jest-core/src/TestPathPatternPrompt.ts @@ -3,41 +3,40 @@ * * 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 {Context} from 'types/Context'; -import type {Test} from 'types/TestRunner'; -import type {ScrollOptions} from 'types/Watch'; -import type SearchSource from './SearchSource'; +import {Context} from 'jest-runtime'; +import {Test} from 'jest-runner'; import { PatternPrompt, Prompt, + ScrollOptions, printPatternCaret, printRestoredPatternCaret, } from 'jest-watcher'; +import SearchSource from './SearchSource'; -type SearchSources = Array<{| - context: Context, - searchSource: SearchSource, -|}>; +type SearchSources = Array<{ + context: Context; + searchSource: SearchSource; +}>; +// TODO: Make underscored props `private` export default class TestPathPatternPrompt extends PatternPrompt { - _searchSources: SearchSources; + _searchSources?: SearchSources; - constructor(pipe: stream$Writable | tty$WriteStream, prompt: Prompt) { + constructor(pipe: NodeJS.WritableStream, prompt: Prompt) { super(pipe, prompt); this._entityName = 'filenames'; } _onChange(pattern: string, options: ScrollOptions) { super._onChange(pattern, options); - this._printPrompt(pattern, options); + this._printPrompt(pattern); } - _printPrompt(pattern: string, options: ScrollOptions) { + _printPrompt(pattern: string) { const pipe = this._pipe; printPatternCaret(pattern, pipe); printRestoredPatternCaret(pattern, this._currentUsageRows, pipe); @@ -50,9 +49,9 @@ export default class TestPathPatternPrompt extends PatternPrompt { regex = new RegExp(pattern, 'i'); } catch (e) {} - let tests = []; - if (regex) { - this._searchSources.forEach(({searchSource, context}) => { + let tests: Array = []; + if (regex && this._searchSources) { + this._searchSources.forEach(({searchSource}) => { tests = tests.concat(searchSource.findMatchingTests(pattern).tests); }); } diff --git a/packages/jest-core/src/TestScheduler.js b/packages/jest-core/src/TestScheduler.ts similarity index 84% rename from packages/jest-core/src/TestScheduler.js rename to packages/jest-core/src/TestScheduler.ts index 3427f60aa576..737241fd4d4b 100644 --- a/packages/jest-core/src/TestScheduler.js +++ b/packages/jest-core/src/TestScheduler.ts @@ -3,56 +3,53 @@ * * 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 {AggregatedResult, TestResult} from 'types/TestResult'; -import type {GlobalConfig, ReporterConfig, Path} from 'types/Config'; -import type {Context} from 'types/Context'; -import type {Reporter, Test} from 'types/TestRunner'; - import chalk from 'chalk'; import {formatExecError} from 'jest-message-util'; -import { - addResult, - buildFailureTestResult, - makeEmptyAggregatedTestResult, -} from './testResultHelpers'; +import {Config, TestResult} from '@jest/types'; +import snapshot from 'jest-snapshot'; +import TestRunner, {Test} from 'jest-runner'; +import {Context} from 'jest-runtime'; import { CoverageReporter, DefaultReporter, NotifyReporter, SummaryReporter, VerboseReporter, + // @ts-ignore: Not migrated to TS } from '@jest/reporters'; import exit from 'exit'; +import { + addResult, + buildFailureTestResult, + makeEmptyAggregatedTestResult, +} from './testResultHelpers'; import ReporterDispatcher from './ReporterDispatcher'; -import snapshot from 'jest-snapshot'; -import TestRunner from 'jest-runner'; import TestWatcher from './TestWatcher'; import {shouldRunInBand} from './testSchedulerHelper'; +import {Reporter} from './types'; // The default jest-runner is required because it is the default test runner // and required implicitly through the `runner` ProjectConfig option. TestRunner; -export type TestSchedulerOptions = {| - startRun: (globalConfig: GlobalConfig) => *, -|}; -export type TestSchedulerContext = {| - firstRun: boolean, - previousSuccess: boolean, - changedFiles?: Set, -|}; +export type TestSchedulerOptions = { + startRun: (globalConfig: Config.GlobalConfig) => void; +}; +export type TestSchedulerContext = { + firstRun: boolean; + previousSuccess: boolean; + changedFiles?: Set; +}; export default class TestScheduler { - _dispatcher: ReporterDispatcher; - _globalConfig: GlobalConfig; - _options: TestSchedulerOptions; - _context: TestSchedulerContext; + private _dispatcher: ReporterDispatcher; + private _globalConfig: Config.GlobalConfig; + private _options: TestSchedulerOptions; + private _context: TestSchedulerContext; constructor( - globalConfig: GlobalConfig, + globalConfig: Config.GlobalConfig, options: TestSchedulerOptions, context: TestSchedulerContext, ) { @@ -73,7 +70,7 @@ export default class TestScheduler { async scheduleTests(tests: Array, watcher: TestWatcher) { const onStart = this._dispatcher.onTestStart.bind(this._dispatcher); - const timings = []; + const timings: Array = []; const contexts = new Set(); tests.forEach(test => { contexts.add(test.context); @@ -94,7 +91,7 @@ export default class TestScheduler { timings, ); - const onResult = async (test: Test, testResult: TestResult) => { + const onResult = async (test: Test, testResult: TestResult.TestResult) => { if (watcher.isInterrupted()) { return Promise.resolve(); } @@ -130,7 +127,10 @@ export default class TestScheduler { return this._bailIfNeeded(contexts, aggregatedResults, watcher); }; - const onFailure = async (test, error) => { + const onFailure = async ( + test: Test, + error: TestResult.SerializableError, + ) => { if (watcher.isInterrupted()) { return; } @@ -173,11 +173,10 @@ export default class TestScheduler { const testRunners = Object.create(null); contexts.forEach(({config}) => { if (!testRunners[config.runner]) { - // $FlowFixMe - testRunners[config.runner] = new (require(config.runner): TestRunner)( - this._globalConfig, - {changedFiles: this._context && this._context.changedFiles}, - ); + const Runner: typeof TestRunner = require(config.runner); + testRunners[config.runner] = new Runner(this._globalConfig, { + changedFiles: this._context && this._context.changedFiles, + }); } }); @@ -223,8 +222,8 @@ export default class TestScheduler { return aggregatedResults; } - _partitionTests( - testRunners: {[key: string]: TestRunner, __proto__: null}, + private _partitionTests( + testRunners: {[key: string]: TestRunner}, tests: Array, ) { if (Object.keys(testRunners).length > 1) { @@ -246,8 +245,8 @@ export default class TestScheduler { } } - _shouldAddDefaultReporters( - reporters?: Array, + private _shouldAddDefaultReporters( + reporters?: Array, ): boolean { return ( !reporters || @@ -257,7 +256,7 @@ export default class TestScheduler { ); } - _setupReporters() { + private _setupReporters() { const {collectCoverage, notify, reporters} = this._globalConfig; const isDefault = this._shouldAddDefaultReporters(reporters); @@ -288,7 +287,7 @@ export default class TestScheduler { } } - _setupDefaultReporters(collectCoverage: boolean) { + private _setupDefaultReporters(collectCoverage: boolean) { this.addReporter( this._globalConfig.verbose ? new VerboseReporter(this._globalConfig) @@ -306,14 +305,15 @@ export default class TestScheduler { this.addReporter(new SummaryReporter(this._globalConfig)); } - _addCustomReporters(reporters: Array) { - reporters.forEach((reporter, index) => { + private _addCustomReporters( + reporters: Array, + ) { + reporters.forEach(reporter => { const {options, path} = this._getReporterProps(reporter); if (path === 'default') return; try { - // $FlowFixMe const Reporter = require(path); this.addReporter(new Reporter(this._globalConfig, options)); } catch (error) { @@ -331,9 +331,9 @@ export default class TestScheduler { * Get properties of a reporter in an object * to make dealing with them less painful. */ - _getReporterProps( - reporter: string | ReporterConfig, - ): {path: string, options?: Object} { + private _getReporterProps( + reporter: string | Config.ReporterConfig, + ): {path: string; options: {[key: string]: unknown}} { if (typeof reporter === 'string') { return {options: this._options, path: reporter}; } else if (Array.isArray(reporter)) { @@ -344,9 +344,9 @@ export default class TestScheduler { throw new Error('Reporter should be either a string or an array'); } - _bailIfNeeded( + private _bailIfNeeded( contexts: Set, - aggregatedResults: AggregatedResult, + aggregatedResults: TestResult.AggregatedResult, watcher: TestWatcher, ): Promise { if ( @@ -376,7 +376,7 @@ const createAggregatedResults = (numTotalTestSuites: number) => { return result; }; -const getEstimatedTime = (timings, workers) => { +const getEstimatedTime = (timings: Array, workers: number) => { if (!timings.length) { return 0; } diff --git a/packages/jest-core/src/TestSequencer.js b/packages/jest-core/src/TestSequencer.ts similarity index 85% rename from packages/jest-core/src/TestSequencer.js rename to packages/jest-core/src/TestSequencer.ts index 0fab2560639c..3928d695fb9d 100644 --- a/packages/jest-core/src/TestSequencer.js +++ b/packages/jest-core/src/TestSequencer.ts @@ -3,26 +3,23 @@ * * 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 {AggregatedResult} from 'types/TestResult'; -import type {Context} from 'types/Context'; -import type {Test} from 'types/TestRunner'; - import fs from 'fs'; +import {TestResult} from '@jest/types'; import {getCacheFilePath} from 'jest-haste-map'; +import {Context} from 'jest-runtime'; +import {Test} from 'jest-runner'; const FAIL = 0; const SUCCESS = 1; type Cache = { - [key: string]: [0 | 1, number], + [key: string]: [0 | 1, number]; }; export default class TestSequencer { - _cache: Map; + private _cache: Map; constructor() { this._cache = new Map(); @@ -65,12 +62,13 @@ export default class TestSequencer { // subsequent runs we use that to run the slowest tests first, yielding the // fastest results. sort(tests: Array): Array { - const stats = {}; - const fileSize = ({path, context: {hasteFS}}) => + const stats: {[path: string]: number} = {}; + const fileSize = ({path, context: {hasteFS}}: Test) => stats[path] || (stats[path] = hasteFS.getSize(path) || 0); - const hasFailed = (cache, test) => + const hasFailed = (cache: Cache, test: Test) => cache[test.path] && cache[test.path][0] === FAIL; - const time = (cache, test) => cache[test.path] && cache[test.path][1]; + const time = (cache: Cache, test: Test) => + cache[test.path] && cache[test.path][1]; tests.forEach(test => (test.duration = time(this._getCache(test), test))); return tests.sort((testA, testB) => { @@ -92,7 +90,7 @@ export default class TestSequencer { }); } - cacheResults(tests: Array, results: AggregatedResult) { + cacheResults(tests: Array, results: TestResult.AggregatedResult) { const map = Object.create(null); tests.forEach(test => (map[test.path] = test)); results.testResults.forEach(testResult => { diff --git a/packages/jest-core/src/TestWatcher.js b/packages/jest-core/src/TestWatcher.ts similarity index 84% rename from packages/jest-core/src/TestWatcher.js rename to packages/jest-core/src/TestWatcher.ts index 9a126b258489..fce64763633a 100644 --- a/packages/jest-core/src/TestWatcher.js +++ b/packages/jest-core/src/TestWatcher.ts @@ -3,19 +3,17 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import EventEmitter from 'events'; +import {EventEmitter} from 'events'; -type State = {| - interrupted: boolean, -|}; +type State = { + interrupted: boolean; +}; export default class TestWatcher extends EventEmitter { state: State; - _isWatchMode: boolean; + private _isWatchMode: boolean; constructor({isWatchMode}: {isWatchMode: boolean}) { super(); diff --git a/packages/jest-core/src/__tests__/SearchSource.test.js b/packages/jest-core/src/__tests__/SearchSource.test.ts similarity index 87% rename from packages/jest-core/src/__tests__/SearchSource.test.js rename to packages/jest-core/src/__tests__/SearchSource.test.ts index d3ed9b7117a0..8f9418274a1f 100644 --- a/packages/jest-core/src/__tests__/SearchSource.test.js +++ b/packages/jest-core/src/__tests__/SearchSource.test.ts @@ -6,9 +6,12 @@ * */ -'use strict'; - import path from 'path'; +import Runtime from 'jest-runtime'; +import {normalize} from 'jest-config'; +import {Test} from 'jest-runner'; +import {Config} from '@jest/types'; +import SearchSource, {SearchResult} from '../SearchSource'; jest.setTimeout(15000); @@ -17,22 +20,13 @@ const testRegex = path.sep + '__testtests__' + path.sep; const testMatch = ['**/__testtests__/**/*']; const maxWorkers = 1; -const toPaths = tests => tests.map(({path}) => path); +const toPaths = (tests: Array) => tests.map(({path}) => path); -let findMatchingTests; -let normalize; +let findMatchingTests: (config: Config.ProjectConfig) => Promise; describe('SearchSource', () => { const name = 'SearchSource'; - let Runtime; - let SearchSource; - let searchSource; - - beforeEach(() => { - Runtime = require('jest-runtime'); - SearchSource = require('../SearchSource').default; - normalize = require('jest-config').normalize; - }); + let searchSource: SearchSource; describe('isTestFilePath', () => { let config; @@ -44,11 +38,13 @@ describe('SearchSource', () => { rootDir: '.', roots: [], }, - {}, + {} as Config.Argv, ).options; - return Runtime.createContext(config, {maxWorkers}).then(context => { - searchSource = new SearchSource(context); - }); + return Runtime.createContext(config, {maxWorkers, watchman: false}).then( + context => { + searchSource = new SearchSource(context); + }, + ); }); // micromatch doesn't support '..' through the globstar ('**') to avoid @@ -60,13 +56,14 @@ describe('SearchSource', () => { name, rootDir: '.', roots: [], - testMatch: null, + testMatch: undefined, testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.jsx?$', }, - {}, + {} as Config.Argv, ).options; return Runtime.createContext(config, { maxWorkers, + watchman: false, }).then(context => { searchSource = new SearchSource(context); @@ -95,9 +92,10 @@ describe('SearchSource', () => { describe('testPathsMatching', () => { beforeEach(() => { - findMatchingTests = config => + findMatchingTests = (config: Config.ProjectConfig) => Runtime.createContext(config, { maxWorkers, + watchman: false, }).then(context => new SearchSource(context).findMatchingTests()); }); @@ -107,10 +105,10 @@ describe('SearchSource', () => { moduleFileExtensions: ['js', 'jsx', 'txt'], name, rootDir, - testMatch: null, + testMatch: undefined, testRegex: 'not-really-a-test', }, - {}, + {} as Config.Argv, ); return findMatchingTests(config).then(data => { const relPaths = toPaths(data.tests) @@ -134,7 +132,7 @@ describe('SearchSource', () => { testMatch: ['**/not-really-a-test.txt', '!**/do-not-match-me.txt'], testRegex: '', }, - {}, + {} as Config.Argv, ); return findMatchingTests(config).then(data => { const relPaths = toPaths(data.tests) @@ -155,10 +153,10 @@ describe('SearchSource', () => { moduleFileExtensions: ['js', 'jsx'], name, rootDir, - testMatch: null, + testMatch: undefined, testRegex: 'test.jsx?', }, - {}, + {} as Config.Argv, ); return findMatchingTests(config).then(data => { const relPaths = toPaths(data.tests).map(absPath => @@ -180,7 +178,7 @@ describe('SearchSource', () => { testMatch: ['**/test.js?(x)'], testRegex: '', }, - {}, + {} as Config.Argv, ); return findMatchingTests(config).then(data => { const relPaths = toPaths(data.tests).map(absPath => @@ -198,10 +196,10 @@ describe('SearchSource', () => { { name, rootDir, - testMatch: null, + testMatch: undefined, testRegex, }, - {}, + {} as Config.Argv, ); return findMatchingTests(config).then(data => { const relPaths = toPaths(data.tests).map(absPath => @@ -222,7 +220,7 @@ describe('SearchSource', () => { testMatch, testRegex: '', }, - {}, + {} as Config.Argv, ); return findMatchingTests(config).then(data => { const relPaths = toPaths(data.tests).map(absPath => @@ -241,9 +239,9 @@ describe('SearchSource', () => { name, rootDir: path.resolve(__dirname, 'test_root_with_(parentheses)'), testMatch: ['**/__testtests__/**/*'], - testRegex: null, + testRegex: undefined, }, - {}, + {} as Config.Argv, ); return findMatchingTests(config).then(data => { const relPaths = toPaths(data.tests).map(absPath => @@ -263,7 +261,7 @@ describe('SearchSource', () => { rootDir, testMatch, }, - {}, + {} as Config.Argv, ); return findMatchingTests(config).then(data => { const relPaths = toPaths(data.tests).map(absPath => @@ -284,7 +282,7 @@ describe('SearchSource', () => { rootDir, testMatch, }, - {}, + {} as Config.Argv, ); return findMatchingTests(config).then(data => { const relPaths = toPaths(data.tests).map(absPath => @@ -305,7 +303,7 @@ describe('SearchSource', () => { rootDir, testMatch, }, - {}, + {} as Config.Argv, ); return findMatchingTests(config).then(data => { const relPaths = toPaths(data.tests).map(absPath => @@ -323,10 +321,10 @@ describe('SearchSource', () => { { name, rootDir, - testMatch: null, + testMatch: undefined, testRegex, }, - {}, + {} as Config.Argv, ); return findMatchingTests(config).then(data => { const relPaths = toPaths(data.tests).map(absPath => @@ -347,7 +345,7 @@ describe('SearchSource', () => { testMatch, testRegex: '', }, - {}, + {} as Config.Argv, ); return findMatchingTests(config).then(data => { const relPaths = toPaths(data.tests).map(absPath => @@ -388,20 +386,23 @@ describe('SearchSource', () => { '__tests__', 'haste_impl.js', ), + providesModuleNodeModules: [], }, name: 'SearchSource-findRelatedTests-tests', rootDir, }, - {}, + {} as Config.Argv, + ); + Runtime.createContext(config, {maxWorkers, watchman: false}).then( + context => { + searchSource = new SearchSource(context); + done(); + }, ); - Runtime.createContext(config, {maxWorkers}).then(context => { - searchSource = new SearchSource(context); - done(); - }); }); it('makes sure a file is related to itself', () => { - const data = searchSource.findRelatedTests(new Set([rootPath])); + const data = searchSource.findRelatedTests(new Set([rootPath]), false); expect(toPaths(data.tests)).toEqual([rootPath]); }); @@ -410,7 +411,7 @@ describe('SearchSource', () => { const file2Path = path.join(rootDir, 'RequireRegularModule.js'); const loggingDep = path.join(rootDir, 'logging.js'); const parentDep = path.join(rootDir, 'ModuleWithSideEffects.js'); - const data = searchSource.findRelatedTests(new Set([filePath])); + const data = searchSource.findRelatedTests(new Set([filePath]), false); expect(toPaths(data.tests).sort()).toEqual([ parentDep, filePath, @@ -429,7 +430,7 @@ describe('SearchSource', () => { new Set([regular, requireRegular, unrelatedFile]), true, ); - expect(Array.from(data.collectCoverageFrom)).toEqual([ + expect(Array.from(data.collectCoverageFrom || [])).toEqual([ 'RegularModule.js', ]); }); @@ -444,35 +445,37 @@ describe('SearchSource', () => { rootDir, testMatch, }, - {}, + {} as Config.Argv, + ); + Runtime.createContext(config, {maxWorkers, watchman: false}).then( + context => { + searchSource = new SearchSource(context); + done(); + }, ); - Runtime.createContext(config, {maxWorkers}).then(context => { - searchSource = new SearchSource(context); - done(); - }); }); it('returns empty search result for empty input', () => { - const input = []; - const data = searchSource.findRelatedTestsFromPattern(input); + const input: Array = []; + const data = searchSource.findRelatedTestsFromPattern(input, false); expect(data.tests).toEqual([]); }); it('returns empty search result for invalid input', () => { const input = ['non-existend.js']; - const data = searchSource.findRelatedTestsFromPattern(input); + const data = searchSource.findRelatedTestsFromPattern(input, false); expect(data.tests).toEqual([]); }); it('returns empty search result if no related tests were found', () => { const input = ['no_tests.js']; - const data = searchSource.findRelatedTestsFromPattern(input); + const data = searchSource.findRelatedTestsFromPattern(input, false); expect(data.tests).toEqual([]); }); it('finds tests for a single file', () => { const input = ['packages/jest-core/src/__tests__/test_root/module.jsx']; - const data = searchSource.findRelatedTestsFromPattern(input); + const data = searchSource.findRelatedTestsFromPattern(input, false); expect(toPaths(data.tests).sort()).toEqual([ path.join(rootDir, '__testtests__', 'test.js'), path.join(rootDir, '__testtests__', 'test.jsx'), @@ -484,7 +487,7 @@ describe('SearchSource', () => { 'packages/jest-core/src/__tests__/test_root/module.jsx', 'packages/jest-core/src/__tests__/test_root/module.foobar', ]; - const data = searchSource.findRelatedTestsFromPattern(input); + const data = searchSource.findRelatedTestsFromPattern(input, false); expect(toPaths(data.tests).sort()).toEqual([ path.join(rootDir, '__testtests__', 'test.foobar'), path.join(rootDir, '__testtests__', 'test.js'), @@ -500,11 +503,11 @@ describe('SearchSource', () => { rootDir: '.', roots: ['/foo/bar/prefix'], }, - {}, + {} as Config.Argv, ).options; searchSource = new SearchSource( - await Runtime.createContext(config, {maxWorkers}), + await Runtime.createContext(config, {maxWorkers, watchman: false}), ); const input = ['/foo/bar/prefix-suffix/__tests__/my-test.test.js']; diff --git a/packages/jest-core/src/__tests__/globals.test.js b/packages/jest-core/src/__tests__/globals.test.ts similarity index 97% rename from packages/jest-core/src/__tests__/globals.test.js rename to packages/jest-core/src/__tests__/globals.test.ts index 15e89bfceafa..7c6b2ca5354d 100644 --- a/packages/jest-core/src/__tests__/globals.test.js +++ b/packages/jest-core/src/__tests__/globals.test.ts @@ -3,9 +3,8 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ + 'use strict'; describe('Common globals', () => { diff --git a/packages/jest-core/src/cli/index.js b/packages/jest-core/src/cli/index.ts similarity index 79% rename from packages/jest-core/src/cli/index.js rename to packages/jest-core/src/cli/index.ts index b71054c167de..a3837305829b 100644 --- a/packages/jest-core/src/cli/index.js +++ b/packages/jest-core/src/cli/index.ts @@ -3,41 +3,43 @@ * * 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 {AggregatedResult} from 'types/TestResult'; -import type {Argv} from 'types/Argv'; -import type {GlobalConfig, Path} from 'types/Config'; - +import {Config, TestResult} from '@jest/types'; import {Console, createDirectory, preRunMessage} from 'jest-util'; import {readConfigs} from 'jest-config'; +import Runtime, {Context} from 'jest-runtime'; +import {ChangedFilesPromise} from 'jest-changed-files'; +import HasteMap from 'jest-haste-map'; import chalk from 'chalk'; -import createContext from '../lib/create_context'; +import rimraf from 'rimraf'; import exit from 'exit'; +import createContext from '../lib/create_context'; import getChangedFilesPromise from '../getChangedFilesPromise'; import {formatHandleErrors} from '../collectHandles'; import handleDeprecationWarnings from '../lib/handle_deprecation_warnings'; import runJest from '../runJest'; -import Runtime from 'jest-runtime'; import TestWatcher from '../TestWatcher'; import watch from '../watch'; import pluralize from '../pluralize'; -import rimraf from 'rimraf'; import logDebugMessages from '../lib/log_debug_messages'; const {print: preRunMessagePrint} = preRunMessage; +type OnCompleteCallback = (results: TestResult.AggregatedResult) => void; + export const runCLI = async ( - argv: Argv, - projects: Array, -): Promise<{results: AggregatedResult, globalConfig: GlobalConfig}> => { + argv: Config.Argv, + projects: Array, +): Promise<{ + results: TestResult.AggregatedResult; + globalConfig: Config.GlobalConfig; +}> => { const realFs = require('fs'); const fs = require('graceful-fs'); fs.gracefulify(realFs); - let results; + let results: TestResult.AggregatedResult | undefined; // If we output a JSON object, we can't write anything to stdout, since // it'll break the JSON structure and it won't be valid. @@ -72,7 +74,7 @@ export const runCLI = async ( configs, hasDeprecationWarnings, outputStream, - (r: AggregatedResult) => (results = r), + r => (results = r), ); if (argv.watch || argv.watchAll) { @@ -107,9 +109,9 @@ export const runCLI = async ( }; const buildContextsAndHasteMaps = async ( - configs, - globalConfig, - outputStream, + configs: Array, + globalConfig: Config.GlobalConfig, + outputStream: NodeJS.WritableStream, ) => { const hasteMapInstances = Array(configs.length); const contexts = await Promise.all( @@ -131,11 +133,11 @@ const buildContextsAndHasteMaps = async ( }; const _run = async ( - globalConfig, - configs, - hasDeprecationWarnings, - outputStream, - onComplete, + globalConfig: Config.GlobalConfig, + configs: Array, + hasDeprecationWarnings: boolean, + outputStream: NodeJS.WriteStream, + onComplete: OnCompleteCallback, ) => { // Queries to hg/git can take a while, so we need to start the process // as soon as possible, so by the time we need the result it's already there. @@ -166,12 +168,12 @@ const _run = async ( }; const runWatch = async ( - contexts, - configs, - hasDeprecationWarnings, - globalConfig, - outputStream, - hasteMapInstances, + contexts: Array, + _configs: Array, + hasDeprecationWarnings: boolean, + globalConfig: Config.GlobalConfig, + outputStream: NodeJS.WriteStream, + hasteMapInstances: Array, ) => { if (hasDeprecationWarnings) { try { @@ -186,20 +188,20 @@ const runWatch = async ( }; const runWithoutWatch = async ( - globalConfig, - contexts, - outputStream, - onComplete, - changedFilesPromise, + globalConfig: Config.GlobalConfig, + contexts: Array, + outputStream: NodeJS.WritableStream, + onComplete: OnCompleteCallback, + changedFilesPromise?: ChangedFilesPromise, ) => { - const startRun = async () => { + const startRun = async (): Promise => { if (!globalConfig.listTests) { preRunMessagePrint(outputStream); } return runJest({ changedFilesPromise, contexts, - failedTestsCache: null, + failedTestsCache: undefined, globalConfig, onComplete, outputStream, diff --git a/packages/jest-core/src/collectHandles.js b/packages/jest-core/src/collectHandles.ts similarity index 79% rename from packages/jest-core/src/collectHandles.js rename to packages/jest-core/src/collectHandles.ts index fcc1f4368ec7..b7653056a6ae 100644 --- a/packages/jest-core/src/collectHandles.js +++ b/packages/jest-core/src/collectHandles.ts @@ -3,17 +3,16 @@ * * 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 {ProjectConfig} from 'types/Config'; - +import {Config} from '@jest/types'; import {formatExecError} from 'jest-message-util'; import {ErrorWithStack} from 'jest-util'; import stripAnsi from 'strip-ansi'; -function stackIsFromUser(stack) { +type AsyncHook = import('async_hooks').AsyncHook; + +function stackIsFromUser(stack: string) { // Either the test file, or something required by it if (stack.includes('Runtime.requireModule')) { return true; @@ -38,29 +37,26 @@ function stackIsFromUser(stack) { // Inspired by https://github.com/mafintosh/why-is-node-running/blob/master/index.js // Extracted as we want to format the result ourselves export default function collectHandles(): () => Array { - const activeHandles: Map = new Map(); - - function initHook(asyncId, type) { - if (type === 'PROMISE' || type === 'TIMERWRAP') { - return; - } - const error = new ErrorWithStack(type, initHook); - - if (stackIsFromUser(error.stack)) { - activeHandles.set(asyncId, error); - } - } + const activeHandles: Map = new Map(); - let hook; + let hook: AsyncHook; try { - // $FlowFixMe: Node core module - const asyncHooks = require('async_hooks'); + const asyncHooks: typeof import('async_hooks') = require('async_hooks'); hook = asyncHooks.createHook({ destroy(asyncId) { activeHandles.delete(asyncId); }, - init: initHook, + init: function initHook(asyncId, type) { + if (type === 'PROMISE' || type === 'TIMERWRAP') { + return; + } + const error = new ErrorWithStack(type, initHook); + + if (stackIsFromUser(error.stack || '')) { + activeHandles.set(asyncId, error); + } + }, }); hook.enable(); @@ -86,7 +82,7 @@ export default function collectHandles(): () => Array { export function formatHandleErrors( errors: Array, - config: ProjectConfig, + config: Config.ProjectConfig, ): Array { const stacks = new Set(); diff --git a/packages/jest-core/src/coverage.template b/packages/jest-core/src/coverage.template deleted file mode 100644 index d20d08eb88a1..000000000000 --- a/packages/jest-core/src/coverage.template +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. - -// Instrumentation Header -{ - var <%= instrumented.names.statement %>; - var <%= instrumented.names.expression %>; - var <%= instrumented.names.block %>; - var nodes = <%= coverageStorageVar %>.nodes = {}; - var blocks = <%= coverageStorageVar %>.blocks = {}; - - <%= instrumented.names.statement %> = function(i) { - var node = nodes[i] = (nodes[i] || {index: i, count:0}) - node.count++; - }; - - <%= instrumented.names.expression %> = function(i) { - var node = nodes[i] = (nodes[i] || {index: i, count:0}) - node.count++; - }; - - <%= instrumented.names.block %> = function(i) { - var block = blocks[i] = (blocks[i] || {index: i, count:0}) - block.count++; - }; -}; -//////////////////////// - -// Instrumented Code -<%= source %> diff --git a/packages/jest-core/src/getChangedFilesPromise.js b/packages/jest-core/src/getChangedFilesPromise.ts similarity index 70% rename from packages/jest-core/src/getChangedFilesPromise.js rename to packages/jest-core/src/getChangedFilesPromise.ts index f7f0d4df4e0c..eec8f482836f 100644 --- a/packages/jest-core/src/getChangedFilesPromise.js +++ b/packages/jest-core/src/getChangedFilesPromise.ts @@ -3,23 +3,20 @@ * * 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 {GlobalConfig, ProjectConfig} from 'types/Config'; -import type {ChangedFilesPromise} from 'types/ChangedFiles'; -import {getChangedFilesForRoots} from 'jest-changed-files'; +import {Config} from '@jest/types'; +import {getChangedFilesForRoots, ChangedFilesPromise} from 'jest-changed-files'; import {formatExecError} from 'jest-message-util'; import chalk from 'chalk'; export default ( - globalConfig: GlobalConfig, - configs: Array, -): ?ChangedFilesPromise => { + globalConfig: Config.GlobalConfig, + configs: Array, +): ChangedFilesPromise | undefined => { if (globalConfig.onlyChanged) { - const allRootsForAllProjects = configs.reduce( - (roots, config) => roots.concat(config.roots || []), + const allRootsForAllProjects = configs.reduce>( + (roots, config) => [...roots, ...(config.roots || [])], [], ); return getChangedFilesForRoots(allRootsForAllProjects, { diff --git a/packages/jest-core/src/getNoTestFound.js b/packages/jest-core/src/getNoTestFound.ts similarity index 84% rename from packages/jest-core/src/getNoTestFound.js rename to packages/jest-core/src/getNoTestFound.ts index bd6ec71b13ac..d1fa85d3ec8e 100644 --- a/packages/jest-core/src/getNoTestFound.js +++ b/packages/jest-core/src/getNoTestFound.ts @@ -3,22 +3,19 @@ * * 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 {GlobalConfig} from 'types/Config'; -import type {TestRunData} from 'types/TestRunner'; - import chalk from 'chalk'; +import {Config} from '@jest/types'; +import {TestRunData} from './types'; import pluralize from './pluralize'; export default function getNoTestFound( testRunData: TestRunData, - globalConfig: GlobalConfig, + globalConfig: Config.GlobalConfig, ): string { const testFiles = testRunData.reduce( - (current, testRun) => current + testRun.matches.total || 0, + (current, testRun) => current + (testRun.matches.total || 0), 0, ); let dataMessage; diff --git a/packages/jest-core/src/getNoTestFoundFailed.js b/packages/jest-core/src/getNoTestFoundFailed.ts similarity index 100% rename from packages/jest-core/src/getNoTestFoundFailed.js rename to packages/jest-core/src/getNoTestFoundFailed.ts diff --git a/packages/jest-core/src/getNoTestFoundRelatedToChangedFiles.js b/packages/jest-core/src/getNoTestFoundRelatedToChangedFiles.ts similarity index 80% rename from packages/jest-core/src/getNoTestFoundRelatedToChangedFiles.js rename to packages/jest-core/src/getNoTestFoundRelatedToChangedFiles.ts index b78468c63cf4..4c3ecb74a56b 100644 --- a/packages/jest-core/src/getNoTestFoundRelatedToChangedFiles.js +++ b/packages/jest-core/src/getNoTestFoundRelatedToChangedFiles.ts @@ -1,9 +1,12 @@ // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. import chalk from 'chalk'; +import {Config} from '@jest/types'; import {isInteractive} from 'jest-util'; -export default function getNoTestFoundRelatedToChangedFiles(globalConfig) { +export default function getNoTestFoundRelatedToChangedFiles( + globalConfig: Config.GlobalConfig, +) { const ref = globalConfig.changedSince ? `"${globalConfig.changedSince}"` : 'last commit'; diff --git a/packages/jest-core/src/getNoTestFoundVerbose.js b/packages/jest-core/src/getNoTestFoundVerbose.ts similarity index 78% rename from packages/jest-core/src/getNoTestFoundVerbose.js rename to packages/jest-core/src/getNoTestFoundVerbose.ts index f0f503954ccd..e1389f7ef423 100644 --- a/packages/jest-core/src/getNoTestFoundVerbose.js +++ b/packages/jest-core/src/getNoTestFoundVerbose.ts @@ -1,24 +1,27 @@ // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. import chalk from 'chalk'; +import {Config} from '@jest/types'; import pluralize from './pluralize'; +import {Stats, TestRunData} from './types'; export default function getNoTestFoundVerbose( - testRunData, - globalConfig, + testRunData: TestRunData, + globalConfig: Config.GlobalConfig, ): string { const individualResults = testRunData.map(testRun => { - const stats = testRun.matches.stats || {}; + const stats = testRun.matches.stats || ({} as Stats); const config = testRun.context.config; - const statsMessage = Object.keys(stats) + const statsMessage = (Object.keys(stats) as Array) .map(key => { if (key === 'roots' && config.roots.length === 1) { return null; } const value = config[key]; if (value) { + const valueAsString = Array.isArray(value) ? value.join(', ') : value; const matches = pluralize('match', stats[key], 'es'); - return ` ${key}: ${chalk.yellow(value)} - ${matches}`; + return ` ${key}: ${chalk.yellow(valueAsString)} - ${matches}`; } return null; }) diff --git a/packages/jest-core/src/getNoTestsFoundMessage.js b/packages/jest-core/src/getNoTestsFoundMessage.ts similarity index 86% rename from packages/jest-core/src/getNoTestsFoundMessage.js rename to packages/jest-core/src/getNoTestsFoundMessage.ts index be2211172597..00b0b5e6148b 100644 --- a/packages/jest-core/src/getNoTestsFoundMessage.js +++ b/packages/jest-core/src/getNoTestsFoundMessage.ts @@ -3,13 +3,10 @@ * * 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 {GlobalConfig} from 'types/Config'; -import type {TestRunData} from 'types/TestRunner'; - +import {Config} from '@jest/types'; +import {TestRunData} from './types'; import getNoTestFound from './getNoTestFound'; import getNoTestFoundRelatedToChangedFiles from './getNoTestFoundRelatedToChangedFiles'; import getNoTestFoundVerbose from './getNoTestFoundVerbose'; @@ -17,7 +14,7 @@ import getNoTestFoundFailed from './getNoTestFoundFailed'; export default function getNoTestsFoundMessage( testRunData: TestRunData, - globalConfig: GlobalConfig, + globalConfig: Config.GlobalConfig, ): string { if (globalConfig.onlyFailures) { return getNoTestFoundFailed(); diff --git a/packages/jest-core/src/jest.js b/packages/jest-core/src/jest.ts similarity index 97% rename from packages/jest-core/src/jest.js rename to packages/jest-core/src/jest.ts index ca6fe2d0d479..87ceab84269f 100644 --- a/packages/jest-core/src/jest.js +++ b/packages/jest-core/src/jest.ts @@ -3,8 +3,6 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ export {default as SearchSource} from './SearchSource'; diff --git a/packages/jest-core/src/lib/__tests__/__snapshots__/log_debug_messages.test.js.snap b/packages/jest-core/src/lib/__tests__/__snapshots__/log_debug_messages.test.js.snap deleted file mode 100644 index 16e1a6040a64..000000000000 --- a/packages/jest-core/src/lib/__tests__/__snapshots__/log_debug_messages.test.js.snap +++ /dev/null @@ -1,45 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`prints the config object 1`] = ` -"{ - \\"configs\\": { - \\"rootDir\\": \\"/path/to/dir\\", - \\"roots\\": [ - \\"path/to/dir/test\\" - ], - \\"testRunner\\": \\"myRunner\\" - }, - \\"globalConfig\\": { - \\"automock\\": false, - \\"watch\\": true - }, - \\"version\\": 123 -} -" -`; - -exports[`prints the jest version 1`] = ` -"{ - \\"configs\\": { - \\"testRunner\\": \\"myRunner\\" - }, - \\"globalConfig\\": { - \\"watch\\": true - }, - \\"version\\": 123 -} -" -`; - -exports[`prints the test framework name 1`] = ` -"{ - \\"configs\\": { - \\"testRunner\\": \\"myRunner\\" - }, - \\"globalConfig\\": { - \\"watch\\": true - }, - \\"version\\": 123 -} -" -`; diff --git a/packages/jest-core/src/lib/__tests__/__snapshots__/log_debug_messages.test.ts.snap b/packages/jest-core/src/lib/__tests__/__snapshots__/log_debug_messages.test.ts.snap new file mode 100644 index 000000000000..fc4ae3ee76e0 --- /dev/null +++ b/packages/jest-core/src/lib/__tests__/__snapshots__/log_debug_messages.test.ts.snap @@ -0,0 +1,126 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`prints the config object 1`] = ` +{ + "configs": { + "automock": false, + "browser": false, + "cache": false, + "cacheDirectory": "/test_cache_dir/", + "clearMocks": false, + "coveragePathIgnorePatterns": [], + "cwd": "/test_root_dir/", + "detectLeaks": false, + "detectOpenHandles": false, + "errorOnDeprecated": false, + "extraGlobals": [], + "filter": null, + "forceCoverageMatch": [], + "globalSetup": null, + "globalTeardown": null, + "globals": {}, + "haste": { + "providesModuleNodeModules": [] + }, + "moduleDirectories": [], + "moduleFileExtensions": [ + "js" + ], + "moduleLoader": "/test_module_loader_path", + "moduleNameMapper": [], + "modulePathIgnorePatterns": [], + "modulePaths": [], + "name": "test_name", + "prettierPath": "prettier", + "resetMocks": false, + "resetModules": false, + "resolver": null, + "restoreMocks": false, + "rootDir": "/path/to/dir", + "roots": [ + "path/to/dir/test" + ], + "runner": "jest-runner", + "setupFiles": [], + "setupFilesAfterEnv": [], + "skipFilter": false, + "skipNodeResolution": false, + "snapshotResolver": null, + "snapshotSerializers": [], + "testEnvironment": "node", + "testEnvironmentOptions": {}, + "testLocationInResults": false, + "testMatch": [], + "testPathIgnorePatterns": [], + "testRegex": [ + "\\\\.test\\\\.js$" + ], + "testRunner": "myRunner", + "testURL": "", + "timers": "real", + "transform": [], + "transformIgnorePatterns": [], + "unmockedModulePathPatterns": null, + "watchPathIgnorePatterns": [] + }, + "globalConfig": { + "bail": 0, + "changedFilesWithAncestor": false, + "changedSince": "", + "collectCoverage": false, + "collectCoverageFrom": [], + "collectCoverageOnlyFrom": null, + "coverageDirectory": "coverage", + "coverageReporters": [], + "coverageThreshold": { + "global": {} + }, + "detectLeaks": false, + "detectOpenHandles": false, + "enabledTestsMap": null, + "errorOnDeprecated": false, + "expand": false, + "extraGlobals": [], + "filter": null, + "findRelatedTests": false, + "forceExit": false, + "globalSetup": null, + "globalTeardown": null, + "json": false, + "lastCommit": false, + "listTests": false, + "logHeapUsage": false, + "maxConcurrency": 5, + "maxWorkers": 2, + "noSCM": null, + "noStackTrace": false, + "nonFlagArgs": [], + "notify": false, + "notifyMode": "failure-change", + "onlyChanged": false, + "onlyFailures": false, + "outputFile": null, + "passWithNoTests": false, + "projects": [], + "replname": null, + "reporters": [], + "rootDir": "/test_root_dir/", + "runTestsByPath": false, + "silent": false, + "skipFilter": false, + "testFailureExitCode": 1, + "testNamePattern": "", + "testPathPattern": "", + "testResultsProcessor": null, + "updateSnapshot": "none", + "useStderr": false, + "verbose": false, + "watch": true, + "watchAll": false, + "watchPlugins": [], + "watchman": false + }, + "version": 123 +} + +`; diff --git a/packages/jest-core/src/lib/__tests__/is_valid_path.test.js b/packages/jest-core/src/lib/__tests__/is_valid_path.test.ts similarity index 97% rename from packages/jest-core/src/lib/__tests__/is_valid_path.test.js rename to packages/jest-core/src/lib/__tests__/is_valid_path.test.ts index 06320576c7c3..a0595df535e1 100644 --- a/packages/jest-core/src/lib/__tests__/is_valid_path.test.js +++ b/packages/jest-core/src/lib/__tests__/is_valid_path.test.ts @@ -3,13 +3,10 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import isValidPath from '../is_valid_path'; import path from 'path'; -//$FlowFixMe: Converted to TS +import isValidPath from '../is_valid_path'; import {makeGlobalConfig} from '../../../../../TestUtils'; const rootDir = path.resolve(path.sep, 'root'); diff --git a/packages/jest-core/src/lib/__tests__/log_debug_messages.test.js b/packages/jest-core/src/lib/__tests__/log_debug_messages.test.js deleted file mode 100644 index 0827f195bd20..000000000000 --- a/packages/jest-core/src/lib/__tests__/log_debug_messages.test.js +++ /dev/null @@ -1,45 +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. - * - */ - -'use strict'; - -import logDebugMessages from '../log_debug_messages'; - -jest.mock('../../../package.json', () => ({version: 123})); - -jest.mock('myRunner', () => ({name: 'My Runner'}), {virtual: true}); - -const getOutputStream = () => ({ - write(message) { - expect(message).toMatchSnapshot(); - }, -}); - -it('prints the jest version', () => { - expect.assertions(1); - logDebugMessages({watch: true}, {testRunner: 'myRunner'}, getOutputStream()); -}); - -it('prints the test framework name', () => { - expect.assertions(1); - logDebugMessages({watch: true}, {testRunner: 'myRunner'}, getOutputStream()); -}); - -it('prints the config object', () => { - expect.assertions(1); - const globalConfig = { - automock: false, - watch: true, - }; - const config = { - rootDir: '/path/to/dir', - roots: ['path/to/dir/test'], - testRunner: 'myRunner', - }; - logDebugMessages(globalConfig, config, getOutputStream()); -}); diff --git a/packages/jest-core/src/lib/__tests__/log_debug_messages.test.ts b/packages/jest-core/src/lib/__tests__/log_debug_messages.test.ts new file mode 100644 index 000000000000..036a1b0f0004 --- /dev/null +++ b/packages/jest-core/src/lib/__tests__/log_debug_messages.test.ts @@ -0,0 +1,65 @@ +/** + * 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 {wrap} from 'jest-snapshot-serializer-raw'; +import logDebugMessages from '../log_debug_messages'; +import {makeGlobalConfig, makeProjectConfig} from '../../../../../TestUtils'; + +jest.mock('../../../package.json', () => ({version: 123})); + +jest.mock('myRunner', () => ({name: 'My Runner'}), {virtual: true}); + +const getOutputStream = (resolve: (message: string) => void) => + ({ + write(message: string) { + resolve(message); + }, + } as NodeJS.WriteStream); + +it('prints the jest version', async () => { + expect.assertions(1); + const message = await new Promise(resolve => { + logDebugMessages( + makeGlobalConfig({watch: true}), + makeProjectConfig({testRunner: 'myRunner'}), + getOutputStream(resolve), + ); + }); + + expect(JSON.parse(message).version).toBe(123); +}); + +it('prints the test framework name', async () => { + expect.assertions(1); + const message = await new Promise(resolve => { + logDebugMessages( + makeGlobalConfig({watch: true}), + makeProjectConfig({testRunner: 'myRunner'}), + getOutputStream(resolve), + ); + }); + + expect(JSON.parse(message).configs.testRunner).toBe('myRunner'); +}); + +it('prints the config object', async () => { + expect.assertions(1); + const globalConfig = makeGlobalConfig({ + watch: true, + }); + const config = makeProjectConfig({ + automock: false, + rootDir: '/path/to/dir', + roots: ['path/to/dir/test'], + testRunner: 'myRunner', + }); + const message = await new Promise(resolve => { + logDebugMessages(globalConfig, config, getOutputStream(resolve)); + }); + expect(wrap(message)).toMatchSnapshot(); +}); diff --git a/packages/jest-core/src/lib/active_filters_message.js b/packages/jest-core/src/lib/active_filters_message.ts similarity index 90% rename from packages/jest-core/src/lib/active_filters_message.js rename to packages/jest-core/src/lib/active_filters_message.ts index b446c551d8c9..240fab05b574 100644 --- a/packages/jest-core/src/lib/active_filters_message.js +++ b/packages/jest-core/src/lib/active_filters_message.ts @@ -3,14 +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 type {GlobalConfig} from 'types/Config'; + import chalk from 'chalk'; +import {Config} from '@jest/types'; const activeFilters = ( - globalConfig: GlobalConfig, + globalConfig: Config.GlobalConfig, delimiter: string = '\n', ) => { const {testNamePattern, testPathPattern} = globalConfig; diff --git a/packages/jest-core/src/lib/create_context.js b/packages/jest-core/src/lib/create_context.ts similarity index 57% rename from packages/jest-core/src/lib/create_context.js rename to packages/jest-core/src/lib/create_context.ts index 8fe14b4683c9..535a9c8e01fd 100644 --- a/packages/jest-core/src/lib/create_context.js +++ b/packages/jest-core/src/lib/create_context.ts @@ -3,19 +3,15 @@ * * 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 {ProjectConfig} from 'types/Config'; -import type {Context} from 'types/Context'; -import type {HasteMap} from 'types/HasteMap'; - -import Runtime from 'jest-runtime'; +import {Config} from '@jest/types'; +import Runtime, {Context} from 'jest-runtime'; +import {HasteMapObject} from 'jest-haste-map'; export default ( - config: ProjectConfig, - {hasteFS, moduleMap}: HasteMap, + config: Config.ProjectConfig, + {hasteFS, moduleMap}: HasteMapObject, ): Context => ({ config, hasteFS, diff --git a/packages/jest-core/src/lib/handle_deprecation_warnings.js b/packages/jest-core/src/lib/handle_deprecation_warnings.ts similarity index 85% rename from packages/jest-core/src/lib/handle_deprecation_warnings.js rename to packages/jest-core/src/lib/handle_deprecation_warnings.ts index e7778707f018..560352d5f23d 100644 --- a/packages/jest-core/src/lib/handle_deprecation_warnings.js +++ b/packages/jest-core/src/lib/handle_deprecation_warnings.ts @@ -3,16 +3,14 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ import chalk from 'chalk'; import {KEYS} from 'jest-watcher'; export default ( - pipe: stream$Writable | tty$WriteStream, - stdin: stream$Readable | tty$ReadStream = process.stdin, + pipe: NodeJS.WriteStream, + stdin: NodeJS.ReadStream = process.stdin, ): Promise => new Promise((resolve, reject) => { if (typeof stdin.setRawMode === 'function') { @@ -24,11 +22,10 @@ export default ( pipe.write(messages.join('\n')); - // $FlowFixMe stdin.setRawMode(true); stdin.resume(); stdin.setEncoding('utf8'); - stdin.on('data', (key: string) => { + stdin.on('data', key => { if (key === KEYS.ENTER) { resolve(); } else if ( diff --git a/packages/jest-core/src/lib/is_valid_path.js b/packages/jest-core/src/lib/is_valid_path.ts similarity index 78% rename from packages/jest-core/src/lib/is_valid_path.js rename to packages/jest-core/src/lib/is_valid_path.ts index ffd14efb8fff..a836154b65e1 100644 --- a/packages/jest-core/src/lib/is_valid_path.js +++ b/packages/jest-core/src/lib/is_valid_path.ts @@ -3,16 +3,14 @@ * * 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 {GlobalConfig} from 'types/Config'; +import {Config} from '@jest/types'; import {isSnapshotPath} from 'jest-snapshot'; export default function isValidPath( - globalConfig: GlobalConfig, - filePath: string, + globalConfig: Config.GlobalConfig, + filePath: Config.Path, ) { return ( !filePath.includes(globalConfig.coverageDirectory) && diff --git a/packages/jest-core/src/lib/log_debug_messages.js b/packages/jest-core/src/lib/log_debug_messages.ts similarity index 62% rename from packages/jest-core/src/lib/log_debug_messages.js rename to packages/jest-core/src/lib/log_debug_messages.ts index d784960476b6..6ae3a51d1d4c 100644 --- a/packages/jest-core/src/lib/log_debug_messages.js +++ b/packages/jest-core/src/lib/log_debug_messages.ts @@ -3,18 +3,16 @@ * * 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 {GlobalConfig, ProjectConfig} from 'types/Config'; +import {Config} from '@jest/types'; -import {version as VERSION} from '../../package.json'; +const VERSION = require('../../package.json').version; export default function logDebugMessages( - globalConfig: GlobalConfig, - configs: Array, - outputStream: stream$Writable | tty$WriteStream, + globalConfig: Config.GlobalConfig, + configs: Array | Config.ProjectConfig, + outputStream: NodeJS.WriteStream, ): void { const output = { configs, diff --git a/packages/jest-core/src/lib/update_global_config.js b/packages/jest-core/src/lib/update_global_config.ts similarity index 66% rename from packages/jest-core/src/lib/update_global_config.js rename to packages/jest-core/src/lib/update_global_config.ts index beee59cd77b5..3a0f2879338c 100644 --- a/packages/jest-core/src/lib/update_global_config.js +++ b/packages/jest-core/src/lib/update_global_config.ts @@ -3,42 +3,21 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ import {replacePathSepForRegex} from 'jest-regex-util'; - -import type {GlobalConfig} from 'types/Config'; - -export type Options = { - bail?: $PropertyType, - changedSince?: $PropertyType, - collectCoverage?: $PropertyType, - collectCoverageFrom?: $PropertyType, - collectCoverageOnlyFrom?: $PropertyType< - GlobalConfig, - 'collectCoverageOnlyFrom', - >, - coverageDirectory?: $PropertyType, - coverageReporters?: $PropertyType, - mode?: 'watch' | 'watchAll', - notify?: $PropertyType, - notifyMode?: $PropertyType, - onlyFailures?: $PropertyType, - reporters?: $PropertyType, - testNamePattern?: $PropertyType, - testPathPattern?: $PropertyType, - updateSnapshot?: $PropertyType, - verbose?: $PropertyType, -}; - -export default (globalConfig: GlobalConfig, options: Options): GlobalConfig => { - const newConfig: GlobalConfig = {...globalConfig}; - - if (!options) { - options = {}; - } +import {Config} from '@jest/types'; +import {AllowedConfigOptions} from 'jest-watcher'; + +type ExtraConfigOptions = Partial< + Pick +>; + +export default ( + globalConfig: Config.GlobalConfig, + options: AllowedConfigOptions & ExtraConfigOptions = {}, +): Config.GlobalConfig => { + const newConfig: Config.GlobalConfig = {...globalConfig}; if (options.mode === 'watch') { newConfig.watch = true; diff --git a/packages/jest-core/src/lib/watch_plugins_helpers.js b/packages/jest-core/src/lib/watch_plugins_helpers.ts similarity index 72% rename from packages/jest-core/src/lib/watch_plugins_helpers.js rename to packages/jest-core/src/lib/watch_plugins_helpers.ts index ad9fa58a9e9e..db43a6655026 100644 --- a/packages/jest-core/src/lib/watch_plugins_helpers.js +++ b/packages/jest-core/src/lib/watch_plugins_helpers.ts @@ -3,33 +3,37 @@ * * 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 {GlobalConfig} from 'types/Config'; -import type {WatchPlugin, UsageData} from '../types'; + +import {Config} from '@jest/types'; +import {WatchPlugin, UsageData} from 'jest-watcher'; export const filterInteractivePlugins = ( watchPlugins: Array, - globalConfig: GlobalConfig, + globalConfig: Config.GlobalConfig, ): Array => { const usageInfos = watchPlugins.map( p => p.getUsageInfo && p.getUsageInfo(globalConfig), ); - return watchPlugins.filter((plugin, i, array) => { - if (usageInfos[i]) { - const {key} = usageInfos[i]; - return !usageInfos.slice(i + 1).some(u => u && key === u.key); + return watchPlugins.filter((_plugin, i) => { + const usageInfo = usageInfos[i]; + if (usageInfo) { + const {key} = usageInfo; + return !usageInfos.slice(i + 1).some(u => !!u && key === u.key); } return false; }); }; +function notEmpty(value: T | null | undefined): value is T { + return value != null; +} + export const getSortedUsageRows = ( watchPlugins: Array, - globalConfig: GlobalConfig, + globalConfig: Config.GlobalConfig, ): Array => filterInteractivePlugins(watchPlugins, globalConfig) .sort((a: WatchPlugin, b: WatchPlugin) => { @@ -52,4 +56,4 @@ export const getSortedUsageRows = ( return 0; }) .map(p => p.getUsageInfo && p.getUsageInfo(globalConfig)) - .filter(Boolean); + .filter(notEmpty); diff --git a/packages/jest-core/src/plugins/quit.js b/packages/jest-core/src/plugins/quit.ts similarity index 83% rename from packages/jest-core/src/plugins/quit.js rename to packages/jest-core/src/plugins/quit.ts index 68a336cf203e..462de025729c 100644 --- a/packages/jest-core/src/plugins/quit.js +++ b/packages/jest-core/src/plugins/quit.ts @@ -3,18 +3,14 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ + import {BaseWatchPlugin} from 'jest-watcher'; class QuitPlugin extends BaseWatchPlugin { isInternal: true; - constructor(options: { - stdin: stream$Readable | tty$ReadStream, - stdout: stream$Writable | tty$WriteStream, - }) { + constructor(options: {stdin: NodeJS.ReadStream; stdout: NodeJS.WriteStream}) { super(options); this.isInternal = true; } diff --git a/packages/jest-core/src/plugins/test_name_pattern.js b/packages/jest-core/src/plugins/test_name_pattern.ts similarity index 78% rename from packages/jest-core/src/plugins/test_name_pattern.js rename to packages/jest-core/src/plugins/test_name_pattern.ts index fa9c496a72f4..b16560337f11 100644 --- a/packages/jest-core/src/plugins/test_name_pattern.js +++ b/packages/jest-core/src/plugins/test_name_pattern.ts @@ -3,11 +3,10 @@ * * 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 {GlobalConfig} from 'types/Config'; -import {BaseWatchPlugin, Prompt} from 'jest-watcher'; + +import {Config} from '@jest/types'; +import {BaseWatchPlugin, Prompt, UpdateConfigCallback} from 'jest-watcher'; import TestNamePatternPrompt from '../TestNamePatternPrompt'; import activeFilters from '../lib/active_filters_message'; @@ -15,10 +14,7 @@ class TestNamePatternPlugin extends BaseWatchPlugin { _prompt: Prompt; isInternal: true; - constructor(options: { - stdin: stream$Readable | tty$ReadStream, - stdout: stream$Writable | tty$WriteStream, - }) { + constructor(options: {stdin: NodeJS.ReadStream; stdout: NodeJS.WriteStream}) { super(options); this._prompt = new Prompt(); this.isInternal = true; @@ -35,7 +31,10 @@ class TestNamePatternPlugin extends BaseWatchPlugin { this._prompt.put(key); } - run(globalConfig: GlobalConfig, updateConfigAndRun: Function): Promise { + run( + globalConfig: Config.GlobalConfig, + updateConfigAndRun: UpdateConfigCallback, + ): Promise { return new Promise((res, rej) => { const testNamePatternPrompt = new TestNamePatternPrompt( this._stdout, diff --git a/packages/jest-core/src/plugins/test_path_pattern.js b/packages/jest-core/src/plugins/test_path_pattern.ts similarity index 76% rename from packages/jest-core/src/plugins/test_path_pattern.js rename to packages/jest-core/src/plugins/test_path_pattern.ts index 8bc9dfab7d96..aa37447fde83 100644 --- a/packages/jest-core/src/plugins/test_path_pattern.js +++ b/packages/jest-core/src/plugins/test_path_pattern.ts @@ -3,23 +3,18 @@ * * 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 {GlobalConfig} from 'types/Config'; -import {BaseWatchPlugin, Prompt} from 'jest-watcher'; +import {Config} from '@jest/types'; +import {BaseWatchPlugin, Prompt, UpdateConfigCallback} from 'jest-watcher'; import TestPathPatternPrompt from '../TestPathPatternPrompt'; import activeFilters from '../lib/active_filters_message'; class TestPathPatternPlugin extends BaseWatchPlugin { - _prompt: Prompt; + private _prompt: Prompt; isInternal: true; - constructor(options: { - stdin: stream$Readable | tty$ReadStream, - stdout: stream$Writable | tty$WriteStream, - }) { + constructor(options: {stdin: NodeJS.ReadStream; stdout: NodeJS.WriteStream}) { super(options); this._prompt = new Prompt(); this.isInternal = true; @@ -36,7 +31,10 @@ class TestPathPatternPlugin extends BaseWatchPlugin { this._prompt.put(key); } - run(globalConfig: GlobalConfig, updateConfigAndRun: Function): Promise { + run( + globalConfig: Config.GlobalConfig, + updateConfigAndRun: UpdateConfigCallback, + ): Promise { return new Promise((res, rej) => { const testPathPatternPrompt = new TestPathPatternPrompt( this._stdout, diff --git a/packages/jest-core/src/plugins/update_snapshots.js b/packages/jest-core/src/plugins/update_snapshots.ts similarity index 65% rename from packages/jest-core/src/plugins/update_snapshots.js rename to packages/jest-core/src/plugins/update_snapshots.ts index eb2fca1577cc..7007ac413c6c 100644 --- a/packages/jest-core/src/plugins/update_snapshots.js +++ b/packages/jest-core/src/plugins/update_snapshots.ts @@ -3,28 +3,28 @@ * * 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 {GlobalConfig} from 'types/Config'; -import type {JestHookSubscriber} from 'types/JestHooks'; -import {BaseWatchPlugin} from 'jest-watcher'; + +import {Config} from '@jest/types'; +import { + BaseWatchPlugin, + JestHookSubscriber, + UpdateConfigCallback, +} from 'jest-watcher'; class UpdateSnapshotsPlugin extends BaseWatchPlugin { - _hasSnapshotFailure: boolean; + private _hasSnapshotFailure: boolean; isInternal: true; - constructor(options: { - stdin: stream$Readable | tty$ReadStream, - stdout: stream$Writable | tty$WriteStream, - }) { + constructor(options: {stdin: NodeJS.ReadStream; stdout: NodeJS.WriteStream}) { super(options); this.isInternal = true; + this._hasSnapshotFailure = false; } run( - globalConfig: GlobalConfig, - updateConfigAndRun: Function, + _globalConfig: Config.GlobalConfig, + updateConfigAndRun: UpdateConfigCallback, ): Promise { updateConfigAndRun({updateSnapshot: 'all'}); return Promise.resolve(false); @@ -36,7 +36,7 @@ class UpdateSnapshotsPlugin extends BaseWatchPlugin { }); } - getUsageInfo(globalConfig: GlobalConfig) { + getUsageInfo() { if (this._hasSnapshotFailure) { return { key: 'u', diff --git a/packages/jest-core/src/plugins/update_snapshots_interactive.js b/packages/jest-core/src/plugins/update_snapshots_interactive.ts similarity index 75% rename from packages/jest-core/src/plugins/update_snapshots_interactive.js rename to packages/jest-core/src/plugins/update_snapshots_interactive.ts index 0a293895e83e..29f2cac10bce 100644 --- a/packages/jest-core/src/plugins/update_snapshots_interactive.js +++ b/packages/jest-core/src/plugins/update_snapshots_interactive.ts @@ -3,25 +3,18 @@ * * 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 {JestHookSubscriber} from 'types/JestHooks'; -import type {GlobalConfig} from 'types/Config'; -import type {AggregatedResult, AssertionLocation} from 'types/TestResult'; -import {BaseWatchPlugin} from 'jest-watcher'; + +import {Config, TestResult} from '@jest/types'; +import {BaseWatchPlugin, JestHookSubscriber} from 'jest-watcher'; import SnapshotInteractiveMode from '../SnapshotInteractiveMode'; class UpdateSnapshotInteractivePlugin extends BaseWatchPlugin { - _snapshotInteractiveMode: SnapshotInteractiveMode; - _failedSnapshotTestPaths: Array<*>; - _failedSnapshotTestAssertions: Array; + private _snapshotInteractiveMode: SnapshotInteractiveMode; + private _failedSnapshotTestAssertions: Array; isInternal: true; - constructor(options: { - stdin: stream$Readable | tty$ReadStream, - stdout: stream$Writable | tty$WriteStream, - }) { + constructor(options: {stdin: NodeJS.ReadStream; stdout: NodeJS.WriteStream}) { super(options); this._failedSnapshotTestAssertions = []; this._snapshotInteractiveMode = new SnapshotInteractiveMode(this._stdout); @@ -29,9 +22,9 @@ class UpdateSnapshotInteractivePlugin extends BaseWatchPlugin { } getFailedSnapshotTestAssertions( - testResults: AggregatedResult, - ): Array { - const failedTestPaths = []; + testResults: TestResult.AggregatedResult, + ): Array { + const failedTestPaths: Array = []; if (testResults.numFailedTests === 0 || !testResults.testResults) { return failedTestPaths; } @@ -69,12 +62,15 @@ class UpdateSnapshotInteractivePlugin extends BaseWatchPlugin { } } - run(globalConfig: GlobalConfig, updateConfigAndRun: Function): Promise { + run( + _globalConfig: Config.GlobalConfig, + updateConfigAndRun: Function, + ): Promise { if (this._failedSnapshotTestAssertions.length) { return new Promise(res => { this._snapshotInteractiveMode.run( this._failedSnapshotTestAssertions, - (assertion: ?AssertionLocation, shouldUpdateSnapshot: boolean) => { + (assertion, shouldUpdateSnapshot) => { updateConfigAndRun({ mode: 'watch', testNamePattern: assertion ? `^${assertion.fullName}$` : '', @@ -93,7 +89,7 @@ class UpdateSnapshotInteractivePlugin extends BaseWatchPlugin { } } - getUsageInfo(globalConfig: GlobalConfig) { + getUsageInfo() { if ( this._failedSnapshotTestAssertions && this._failedSnapshotTestAssertions.length > 0 diff --git a/packages/jest-core/src/pluralize.js b/packages/jest-core/src/pluralize.ts similarity index 100% rename from packages/jest-core/src/pluralize.js rename to packages/jest-core/src/pluralize.ts diff --git a/packages/jest-core/src/runGlobalHook.js b/packages/jest-core/src/runGlobalHook.ts similarity index 82% rename from packages/jest-core/src/runGlobalHook.js rename to packages/jest-core/src/runGlobalHook.ts index 6c89f943f4f0..32ba09112ec7 100644 --- a/packages/jest-core/src/runGlobalHook.js +++ b/packages/jest-core/src/runGlobalHook.ts @@ -3,31 +3,28 @@ * * 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 {GlobalConfig} from 'types/Config'; -import type {Test} from 'types/TestRunner'; - import {extname} from 'path'; import pEachSeries from 'p-each-series'; import {addHook} from 'pirates'; +import {Config} from '@jest/types'; +import {Test} from 'jest-runner'; import {ScriptTransformer} from '@jest/transform'; // copied from https://github.com/babel/babel/blob/56044c7851d583d498f919e9546caddf8f80a72f/packages/babel-helpers/src/helpers.js#L558-L562 -function _interopRequireDefault(obj) { +function _interopRequireDefault(obj: any) { return obj && obj.__esModule ? obj : {default: obj}; } -export default ({ +export default async ({ allTests, globalConfig, moduleName, }: { - allTests: Array, - globalConfig: GlobalConfig, - moduleName: 'globalSetup' | 'globalTeardown', + allTests: Array; + globalConfig: Config.GlobalConfig; + moduleName: 'globalSetup' | 'globalTeardown'; }): Promise => { const globalModulePaths = new Set( allTests.map(test => test.context.config[moduleName]), @@ -38,7 +35,7 @@ export default ({ } if (globalModulePaths.size > 0) { - return pEachSeries(Array.from(globalModulePaths), async modulePath => { + await pEachSeries(Array.from(globalModulePaths), async modulePath => { if (!modulePath) { return; } @@ -63,11 +60,10 @@ export default ({ transformer.transformSource(filename, code, false).code || code, { exts: [extname(modulePath)], - matcher: transformer._shouldTransform.bind(transformer), + matcher: transformer.shouldTransform.bind(transformer), }, ); - // $FlowFixMe const globalModule = _interopRequireDefault(require(modulePath)).default; if (typeof globalModule !== 'function') { diff --git a/packages/jest-core/src/runJest.js b/packages/jest-core/src/runJest.ts similarity index 76% rename from packages/jest-core/src/runJest.js rename to packages/jest-core/src/runJest.ts index a403ac57ca8a..e6f7e16e6d96 100644 --- a/packages/jest-core/src/runJest.js +++ b/packages/jest-core/src/runJest.ts @@ -3,41 +3,36 @@ * * 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 {Context} from 'types/Context'; -import type {ChangedFilesPromise} from 'types/ChangedFiles'; -import type {GlobalConfig} from 'types/Config'; -import type {AggregatedResult} from 'types/TestResult'; -import type {TestRunData} from 'types/TestRunner'; -import type {JestHookEmitter} from 'types/JestHooks'; -import type TestWatcher from './TestWatcher'; -import type {TestSchedulerContext} from './TestScheduler'; - -import chalk from 'chalk'; import path from 'path'; +import chalk from 'chalk'; import {sync as realpath} from 'realpath-native'; import {Console, formatTestResults} from 'jest-util'; import exit from 'exit'; import fs from 'graceful-fs'; +import {JestHook, JestHookEmitter} from 'jest-watcher'; +import {Context} from 'jest-runtime'; +import {Test} from 'jest-runner'; +import {Config, TestResult} from '@jest/types'; +import {ChangedFiles, ChangedFilesPromise} from 'jest-changed-files'; import getNoTestsFoundMessage from './getNoTestsFoundMessage'; import runGlobalHook from './runGlobalHook'; import SearchSource from './SearchSource'; -import TestScheduler from './TestScheduler'; +import TestScheduler, {TestSchedulerContext} from './TestScheduler'; import TestSequencer from './TestSequencer'; import {makeEmptyAggregatedTestResult} from './testResultHelpers'; import FailedTestsCache from './FailedTestsCache'; -import {JestHook} from 'jest-watcher'; import collectNodeHandles from './collectHandles'; +import TestWatcher from './TestWatcher'; +import {TestRunData} from './types'; const getTestPaths = async ( - globalConfig, - context, - outputStream, - changedFiles, - jestHooks, + globalConfig: Config.GlobalConfig, + context: Context, + outputStream: NodeJS.WritableStream, + changedFiles: ChangedFiles | undefined, + jestHooks: JestHookEmitter, ) => { const source = new SearchSource(context); const data = await source.getTestPaths(globalConfig, changedFiles); @@ -62,15 +57,27 @@ const getTestPaths = async ( ), ); - const filteredTests = data.tests.filter((test, i) => shouldTestArray[i]); + const filteredTests = data.tests.filter((_test, i) => shouldTestArray[i]); return {...data, allTests: filteredTests.length, tests: filteredTests}; }; -const processResults = (runResults, options) => { +type ProcessResultOptions = Pick< + Config.GlobalConfig, + 'json' | 'outputFile' | 'testResultsProcessor' +> & { + collectHandles?: () => Array; + onComplete?: (result: TestResult.AggregatedResult) => void; + outputStream: NodeJS.WritableStream; +}; + +const processResults = ( + runResults: TestResult.AggregatedResult, + options: ProcessResultOptions, +) => { const { outputFile, - isJSON, + json: isJSON, onComplete, outputStream, testResultsProcessor, @@ -84,7 +91,6 @@ const processResults = (runResults, options) => { } if (testResultsProcessor) { - /* $FlowFixMe */ runResults = require(testResultsProcessor)(runResults); } if (isJSON) { @@ -120,23 +126,25 @@ export default (async function runJest({ onComplete, failedTestsCache, }: { - globalConfig: GlobalConfig, - contexts: Array, - outputStream: stream$Writable | tty$WriteStream, - testWatcher: TestWatcher, - jestHooks?: JestHookEmitter, - startRun: (globalConfig: GlobalConfig) => *, - changedFilesPromise: ?ChangedFilesPromise, - onComplete: (testResults: AggregatedResult) => any, - failedTestsCache: ?FailedTestsCache, + globalConfig: Config.GlobalConfig; + contexts: Array; + outputStream: NodeJS.WritableStream; + testWatcher: TestWatcher; + jestHooks?: JestHookEmitter; + startRun: (globalConfig: Config.GlobalConfig) => void; + changedFilesPromise?: ChangedFilesPromise; + onComplete: (testResults: TestResult.AggregatedResult) => void; + failedTestsCache?: FailedTestsCache; }) { const sequencer = new TestSequencer(); - let allTests = []; + let allTests: Array = []; if (changedFilesPromise && globalConfig.watch) { const {repos} = await changedFilesPromise; - const noSCM = Object.keys(repos).every(scm => repos[scm].size === 0); + const noSCM = (Object.keys(repos) as Array< + keyof ChangedFiles['repos'] + >).every(scm => repos[scm].size === 0); if (noSCM) { process.stderr.write( '\n' + @@ -207,7 +215,7 @@ export default (async function runJest({ globalConfig.silent !== true && globalConfig.verbose !== false ) { - const newConfig: GlobalConfig = {...globalConfig, verbose: true}; + const newConfig: Config.GlobalConfig = {...globalConfig, verbose: true}; globalConfig = Object.freeze(newConfig); } @@ -227,9 +235,7 @@ export default (async function runJest({ const results = await new TestScheduler( globalConfig, - { - startRun, - }, + {startRun}, testSchedulerContext, ).scheduleTests(allTests, testWatcher); @@ -241,7 +247,7 @@ export default (async function runJest({ return processResults(results, { collectHandles, - isJSON: globalConfig.json, + json: globalConfig.json, onComplete, outputFile: globalConfig.outputFile, outputStream, diff --git a/packages/jest-core/src/testResultHelpers.js b/packages/jest-core/src/testResultHelpers.ts similarity index 92% rename from packages/jest-core/src/testResultHelpers.js rename to packages/jest-core/src/testResultHelpers.ts index cd534c243089..ffbebe101de9 100644 --- a/packages/jest-core/src/testResultHelpers.js +++ b/packages/jest-core/src/testResultHelpers.ts @@ -3,17 +3,11 @@ * * 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 { - AggregatedResult, - SerializableError, - TestResult, -} from 'types/TestResult'; +import {Config, TestResult} from '@jest/types'; -export const makeEmptyAggregatedTestResult = (): AggregatedResult => ({ +export const makeEmptyAggregatedTestResult = (): TestResult.AggregatedResult => ({ numFailedTestSuites: 0, numFailedTests: 0, numPassedTestSuites: 0, @@ -48,9 +42,9 @@ export const makeEmptyAggregatedTestResult = (): AggregatedResult => ({ }); export const buildFailureTestResult = ( - testPath: string, - err: SerializableError, -): TestResult => ({ + testPath: Config.Path, + err: TestResult.SerializableError, +): TestResult.TestResult => ({ console: null, displayName: '', failureMessage: null, @@ -82,8 +76,8 @@ export const buildFailureTestResult = ( // Add individual test result to an aggregated test result export const addResult = ( - aggregatedResults: AggregatedResult, - testResult: TestResult, + aggregatedResults: TestResult.AggregatedResult, + testResult: TestResult.TestResult, ): void => { // `todos` are new as of Jest 24, and not all runners return it. // Set it to `0` to avoid `NaN` diff --git a/packages/jest-core/src/testSchedulerHelper.js b/packages/jest-core/src/testSchedulerHelper.ts similarity index 93% rename from packages/jest-core/src/testSchedulerHelper.js rename to packages/jest-core/src/testSchedulerHelper.ts index 37e22810f945..bb433f1e5367 100644 --- a/packages/jest-core/src/testSchedulerHelper.js +++ b/packages/jest-core/src/testSchedulerHelper.ts @@ -3,11 +3,9 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -'use strict'; -import type {Test} from 'types/TestRunner'; + +import {Test} from 'jest-runner'; const SLOW_TEST_TIME = 1000; @@ -15,7 +13,7 @@ export function shouldRunInBand( tests: Array, isWatchMode: boolean, maxWorkers: number, - timings: number[], + timings: Array, ) { // Run in band if we only have one test or one worker available, unless we // are using the watch mode, in which case the TTY has to be responsive and diff --git a/packages/jest-core/src/types.js b/packages/jest-core/src/types.js deleted file mode 100644 index 35f8bd0ef357..000000000000 --- a/packages/jest-core/src/types.js +++ /dev/null @@ -1,26 +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. - * - * @flow - */ -import type {GlobalConfig} from 'types/Config'; -import type {JestHookSubscriber} from 'types/JestHooks'; - -export type UsageData = { - key: string, - prompt: string, -}; - -export interface WatchPlugin { - +isInternal?: boolean; - +apply?: (hooks: JestHookSubscriber) => void; - +getUsageInfo?: (globalConfig: GlobalConfig) => ?UsageData; - +onKey?: (value: string) => void; - +run?: ( - globalConfig: GlobalConfig, - updateConfigAndRun: Function, - ) => Promise; -} diff --git a/packages/jest-core/src/types.ts b/packages/jest-core/src/types.ts new file mode 100644 index 000000000000..debd9af8d73a --- /dev/null +++ b/packages/jest-core/src/types.ts @@ -0,0 +1,64 @@ +/** + * 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 {Context} from 'jest-runtime'; +import {Test} from 'jest-runner'; +import {Config, TestResult} from '@jest/types'; + +export type TestRunData = Array<{ + context: Context; + matches: { + allTests: number; + tests: Array; + total?: number; + stats?: Stats; + }; +}>; + +type TestPathCaseStats = Record; + +export type TestPathCaseWithPathPatternStats = Record< + keyof (TestPathCasesWithPathPattern), + number +>; + +export type Stats = TestPathCaseStats | TestPathCaseWithPathPatternStats; + +export type TestPathCases = { + roots: (path: Config.Path) => boolean; + testMatch: (path: Config.Path) => boolean; + testPathIgnorePatterns: (path: Config.Path) => boolean; + testRegex: (path: Config.Path) => boolean; +}; + +export type TestPathCasesWithPathPattern = TestPathCases & { + testPathPattern: (path: Config.Path) => boolean; +}; + +// TODO: Obtain this from @jest/reporters once its been migrated +export type ReporterOnStartOptions = { + estimatedTime: number; + showStatus: boolean; +}; + +export type Reporter = { + onTestResult: ( + test: Test, + testResult: TestResult.TestResult, + aggregatedResult: TestResult.AggregatedResult, + ) => Promise; + onRunStart: ( + results: TestResult.AggregatedResult, + options: ReporterOnStartOptions, + ) => Promise; + onTestStart: (test: Test) => Promise; + onRunComplete: ( + contexts: Set, + results: TestResult.AggregatedResult, + ) => Promise; + getLastError: () => Error; +}; diff --git a/packages/jest-core/src/watch.js b/packages/jest-core/src/watch.ts similarity index 85% rename from packages/jest-core/src/watch.js rename to packages/jest-core/src/watch.ts index f630f8b085a4..4aa5da965b59 100644 --- a/packages/jest-core/src/watch.js +++ b/packages/jest-core/src/watch.ts @@ -3,30 +3,32 @@ * * 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 {GlobalConfig} from 'types/Config'; -import type {Context} from 'types/Context'; -import type {WatchPlugin} from './types'; -import type {Options as UpdateGlobalConfigOptions} from './lib/update_global_config'; - import ansiEscapes from 'ansi-escapes'; import chalk from 'chalk'; -import getChangedFilesPromise from './getChangedFilesPromise'; import exit from 'exit'; -import HasteMap from 'jest-haste-map'; +import HasteMap, {HasteChangeEvent} from 'jest-haste-map'; import {formatExecError} from 'jest-message-util'; -import isValidPath from './lib/is_valid_path'; import {isInteractive, preRunMessage, specialChars} from 'jest-util'; +import {ValidationError} from 'jest-validate'; +import {Context} from 'jest-runtime'; +import {Config} from '@jest/types'; +import { + AllowedConfigOptions, + KEYS, + JestHook, + WatchPlugin, + WatchPluginClass, +} from 'jest-watcher'; +import getChangedFilesPromise from './getChangedFilesPromise'; +import isValidPath from './lib/is_valid_path'; import createContext from './lib/create_context'; import runJest from './runJest'; import updateGlobalConfig from './lib/update_global_config'; import SearchSource from './SearchSource'; import TestWatcher from './TestWatcher'; import FailedTestsCache from './FailedTestsCache'; -import {KEYS, JestHook} from 'jest-watcher'; import TestPathPatternPlugin from './plugins/test_path_pattern'; import TestNamePatternPlugin from './plugins/test_name_pattern'; import UpdateSnapshotsPlugin from './plugins/update_snapshots'; @@ -36,9 +38,17 @@ import { getSortedUsageRows, filterInteractivePlugins, } from './lib/watch_plugins_helpers'; -import {ValidationError} from 'jest-validate'; import activeFilters from './lib/active_filters_message'; +type ReservedInfo = { + forbiddenOverwriteMessage?: string; + key?: string; + overwritable: boolean; + plugin: WatchPlugin; +}; + +type WatchPluginKeysMap = Map; + const {print: preRunMessagePrint} = preRunMessage; let hasExitListener = false; @@ -51,7 +61,10 @@ const INTERNAL_PLUGINS = [ QuitPlugin, ]; -const RESERVED_KEY_PLUGINS = new Map([ +const RESERVED_KEY_PLUGINS = new Map< + WatchPluginClass, + Pick +>([ [ UpdateSnapshotsPlugin, {forbiddenOverwriteMessage: 'updating snapshots', key: 'u'}, @@ -64,17 +77,17 @@ const RESERVED_KEY_PLUGINS = new Map([ ]); export default function watch( - initialGlobalConfig: GlobalConfig, + initialGlobalConfig: Config.GlobalConfig, contexts: Array, - outputStream: stream$Writable | tty$WriteStream, + outputStream: NodeJS.WriteStream, hasteMapInstances: Array, - stdin?: stream$Readable | tty$ReadStream = process.stdin, - hooks?: JestHook = new JestHook(), + stdin: NodeJS.ReadStream = process.stdin, + hooks: JestHook = new JestHook(), ): Promise { // `globalConfig` will be constantly updated and reassigned as a result of // watch mode interactions. let globalConfig = initialGlobalConfig; - let activePlugin: ?WatchPlugin; + let activePlugin: WatchPlugin | null; globalConfig = updateGlobalConfig(globalConfig, { mode: globalConfig.watch ? 'watch' : 'watchAll', @@ -98,7 +111,7 @@ export default function watch( testPathPattern, updateSnapshot, verbose, - }: UpdateGlobalConfigOptions = {}) => { + }: AllowedConfigOptions = {}) => { const previousUpdateSnapshot = globalConfig.updateSnapshot; globalConfig = updateGlobalConfig(globalConfig, { bail, @@ -138,9 +151,11 @@ export default function watch( }); if (globalConfig.watchPlugins != null) { - const watchPluginKeys = new Map(); + const watchPluginKeys: WatchPluginKeysMap = new Map(); for (const plugin of watchPlugins) { - const reservedInfo = RESERVED_KEY_PLUGINS.get(plugin.constructor) || {}; + const reservedInfo = + RESERVED_KEY_PLUGINS.get(plugin.constructor as WatchPluginClass) || + ({} as ReservedInfo); const key = reservedInfo.key || getPluginKey(plugin, globalConfig); if (!key) { continue; @@ -154,7 +169,6 @@ export default function watch( } for (const pluginWithConfig of globalConfig.watchPlugins) { - // $FlowFixMe dynamic require const ThirdPartyPlugin = require(pluginWithConfig.path); const plugin: WatchPlugin = new ThirdPartyPlugin({ config: pluginWithConfig.config, @@ -177,7 +191,7 @@ export default function watch( searchSource: new SearchSource(context), })); let isRunning = false; - let testWatcher; + let testWatcher: TestWatcher; let shouldDisplayWatchUsage = true; let isWatchUsageDisplayed = false; @@ -194,46 +208,49 @@ export default function watch( emitFileChange(); hasteMapInstances.forEach((hasteMapInstance, index) => { - hasteMapInstance.on('change', ({eventsQueue, hasteFS, moduleMap}) => { - const validPaths = eventsQueue.filter(({filePath}) => - isValidPath(globalConfig, filePath), - ); - - if (validPaths.length) { - const context = (contexts[index] = createContext( - contexts[index].config, - { - hasteFS, - moduleMap, - }, - )); - - activePlugin = null; + hasteMapInstance.on( + 'change', + ({eventsQueue, hasteFS, moduleMap}: HasteChangeEvent) => { + const validPaths = eventsQueue.filter(({filePath}) => + isValidPath(globalConfig, filePath), + ); - searchSources = searchSources.slice(); - searchSources[index] = { - context, - searchSource: new SearchSource(context), - }; - emitFileChange(); - startRun(globalConfig); - } - }); + if (validPaths.length) { + const context = (contexts[index] = createContext( + contexts[index].config, + {hasteFS, moduleMap}, + )); + + activePlugin = null; + + searchSources = searchSources.slice(); + searchSources[index] = { + context, + searchSource: new SearchSource(context), + }; + emitFileChange(); + startRun(globalConfig); + } + }, + ); }); if (!hasExitListener) { hasExitListener = true; process.on('exit', () => { if (activePlugin) { + // @ts-ignore: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/33423 outputStream.write(ansiEscapes.cursorDown()); outputStream.write(ansiEscapes.eraseDown); } }); } - const startRun = (globalConfig: GlobalConfig) => { + const startRun = ( + globalConfig: Config.GlobalConfig, + ): Promise => { if (isRunning) { - return null; + return Promise.resolve(null); } testWatcher = new TestWatcher({isWatchMode: true}); @@ -292,7 +309,6 @@ export default function watch( const onKeypress = (key: string) => { if (key === KEYS.CONTROL_C || key === KEYS.CONTROL_D) { if (typeof stdin.setRawMode === 'function') { - // $FlowFixMe stdin.setRawMode(false); } outputStream.write('\n'); @@ -388,6 +404,7 @@ export default function watch( break; case 'w': if (!shouldDisplayWatchUsage && !isWatchUsageDisplayed) { + // @ts-ignore: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/33423 outputStream.write(ansiEscapes.cursorUp()); outputStream.write(ansiEscapes.eraseDown); outputStream.write(usage(globalConfig, watchPlugins)); @@ -406,7 +423,6 @@ export default function watch( }; if (typeof stdin.setRawMode === 'function') { - // $FlowFixMe stdin.setRawMode(true); stdin.resume(); stdin.setEncoding('utf8'); @@ -417,7 +433,11 @@ export default function watch( return Promise.resolve(); } -const checkForConflicts = (watchPluginKeys, plugin, globalConfig) => { +const checkForConflicts = ( + watchPluginKeys: WatchPluginKeysMap, + plugin: WatchPlugin, + globalConfig: Config.GlobalConfig, +) => { const key = getPluginKey(plugin, globalConfig); if (!key) { return; @@ -456,24 +476,27 @@ const checkForConflicts = (watchPluginKeys, plugin, globalConfig) => { throw new ValidationError('Watch plugin configuration error', error); }; -const getPluginIdentifier = plugin => +const getPluginIdentifier = (plugin: WatchPlugin) => // This breaks as `displayName` is not defined as a static, but since // WatchPlugin is an interface, and it is my understanding interface // static fields are not definable anymore, no idea how to circumvent // this :-( - // $FlowFixMe: leave `displayName` be. + // @ts-ignore: leave `displayName` be. plugin.constructor.displayName || plugin.constructor.name; -const getPluginKey = (plugin, globalConfig) => { +const getPluginKey = ( + plugin: WatchPlugin, + globalConfig: Config.GlobalConfig, +) => { if (typeof plugin.getUsageInfo === 'function') { - return (plugin.getUsageInfo(globalConfig) || {}).key; + return (plugin.getUsageInfo(globalConfig) || {key: null}).key; } return null; }; const usage = ( - globalConfig, + globalConfig: Config.GlobalConfig, watchPlugins: Array, delimiter = '\n', ) => { diff --git a/packages/jest-core/tsconfig.json b/packages/jest-core/tsconfig.json new file mode 100644 index 000000000000..3e44249a9879 --- /dev/null +++ b/packages/jest-core/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build" + }, + // TODO: This is missing `@jest/reporters` + "references": [ + {"path": "../jest-changed-files"}, + {"path": "../jest-config"}, + {"path": "../jest-haste-map"}, + {"path": "../jest-message-util"}, + {"path": "../jest-regex-util"}, + {"path": "../jest-resolve-dependencies"}, + {"path": "../jest-runner"}, + {"path": "../jest-runtime"}, + {"path": "../jest-snapshot"}, + {"path": "../jest-types"}, + {"path": "../jest-transform"}, + {"path": "../jest-util"}, + {"path": "../jest-validate"}, + {"path": "../jest-watcher"} + ] +} diff --git a/packages/jest-haste-map/src/index.ts b/packages/jest-haste-map/src/index.ts index e4410350efa9..88a0aa893d00 100644 --- a/packages/jest-haste-map/src/index.ts +++ b/packages/jest-haste-map/src/index.ts @@ -31,8 +31,10 @@ import watchmanCrawl from './crawlers/watchman'; import WatchmanWatcher from './lib/WatchmanWatcher'; import * as fastPath from './lib/fast_path'; import { + ChangeEvent, + EventsQueue, FileMetaData, - HasteMap as HasteMapObject, + HasteMap as InternalHasteMapObject, HasteRegExp, InternalHasteMap, Mapper, @@ -105,6 +107,8 @@ namespace HasteMap { export type ModuleMap = HasteModuleMap; export type SerializableModuleMap = HasteSerializableModuleMap; export type FS = HasteFS; + export type HasteMapObject = InternalHasteMapObject; + export type HasteChangeEvent = ChangeEvent; } const CHANGE_INTERVAL = 30; @@ -226,7 +230,7 @@ const getWhiteList = (list: Array | undefined): RegExp | null => { */ /* eslint-disable-next-line no-redeclare */ class HasteMap extends EventEmitter { - private _buildPromise: Promise | null; + private _buildPromise: Promise | null; private _cachePath: Config.Path; private _changeInterval?: NodeJS.Timeout; private _console: Console; @@ -331,7 +335,7 @@ class HasteMap extends EventEmitter { return this._cachePath; } - build(): Promise { + build(): Promise { if (!this._buildPromise) { this._buildPromise = this._buildFileMap() .then(data => this._buildHasteMap(data)) @@ -785,11 +789,7 @@ class HasteMap extends EventEmitter { const rootDir = this._options.rootDir; let changeQueue: Promise = Promise.resolve(); - let eventsQueue: Array<{ - filePath: Config.Path; - stat: fs.Stats | undefined; - type: string; - }> = []; + let eventsQueue: EventsQueue = []; // We only need to copy the entire haste map once on every "frame". let mustCopy = true; @@ -818,7 +818,7 @@ class HasteMap extends EventEmitter { const emitChange = () => { if (eventsQueue.length) { mustCopy = true; - this.emit('change', { + const changeEvent: ChangeEvent = { eventsQueue, hasteFS: new HasteFS({ files: hasteMap.files, @@ -830,7 +830,8 @@ class HasteMap extends EventEmitter { mocks: hasteMap.mocks, rootDir, }), - }); + }; + this.emit('change', changeEvent); eventsQueue = []; } }; diff --git a/packages/jest-haste-map/src/types.ts b/packages/jest-haste-map/src/types.ts index c5e85fc8d9b9..59d2f8022330 100644 --- a/packages/jest-haste-map/src/types.ts +++ b/packages/jest-haste-map/src/types.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import fs from 'fs'; import {Config} from '@jest/types'; import ModuleMap from './ModuleMap'; import HasteFS from './HasteFS'; @@ -102,3 +103,15 @@ export type HType = { }; export type HTypeValue = HType[keyof HType]; + +export type EventsQueue = Array<{ + filePath: Config.Path; + stat: fs.Stats | undefined; + type: string; +}>; + +export type ChangeEvent = { + eventsQueue: EventsQueue; + hasteFS: HasteFS; + moduleMap: ModuleMap; +}; diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index e50e94fcf8e3..1fe4c0eee6a8 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -15,7 +15,7 @@ import { OnTestFailure, OnTestStart, OnTestSuccess, - Test, + Test as JestTest, TestRunnerContext, TestRunnerOptions, TestWatcher, @@ -28,6 +28,11 @@ interface WorkerInterface extends Worker { worker: typeof worker; } +namespace TestRunner { + export type Test = JestTest; +} + +/* eslint-disable-next-line no-redeclare */ class TestRunner { private _globalConfig: Config.GlobalConfig; private _context: TestRunnerContext; @@ -38,7 +43,7 @@ class TestRunner { } async runTests( - tests: Array, + tests: Array, watcher: TestWatcher, onStart: OnTestStart, onResult: OnTestSuccess, @@ -57,7 +62,7 @@ class TestRunner { } private async _createInBandTestRun( - tests: Array, + tests: Array, watcher: TestWatcher, onStart: OnTestStart, onResult: OnTestSuccess, @@ -91,7 +96,7 @@ class TestRunner { } private async _createParallelTestRun( - tests: Array, + tests: Array, watcher: TestWatcher, onStart: OnTestStart, onResult: OnTestSuccess, @@ -111,7 +116,7 @@ class TestRunner { // Send test suites to workers continuously instead of all at once to track // the start time of individual tests. - const runTestInWorker = (test: Test) => + const runTestInWorker = (test: JestTest) => mutex(async () => { if (watcher.isInterrupted()) { return Promise.reject(); @@ -130,7 +135,10 @@ class TestRunner { }); }); - const onError = async (err: TestResult.SerializableError, test: Test) => { + const onError = async ( + err: TestResult.SerializableError, + test: JestTest, + ) => { await onFailure(test, err); if (err.type === 'ProcessTerminatedError') { console.error( diff --git a/packages/jest-runner/src/types.ts b/packages/jest-runner/src/types.ts index 86f26d086fa2..78fb71d00d95 100644 --- a/packages/jest-runner/src/types.ts +++ b/packages/jest-runner/src/types.ts @@ -26,12 +26,6 @@ export type Context = { resolver: HasteResolver; }; -// TODO: Obtain this from @jest/reporters once its been migrated -type ReporterOnStartOptions = { - estimatedTime: number; - showStatus: boolean; -}; - export type OnTestStart = (test: Test) => Promise; export type OnTestFailure = ( test: Test, @@ -42,24 +36,6 @@ export type OnTestSuccess = ( testResult: TestResult.TestResult, ) => Promise; -export type Reporter = { - onTestResult: ( - test: Test, - testResult: TestResult.TestResult, - aggregatedResult: TestResult.AggregatedResult, - ) => Promise; - onRunStart: ( - results: TestResult.AggregatedResult, - options: ReporterOnStartOptions, - ) => Promise; - onTestStart: (test: Test) => Promise; - onRunComplete: ( - contexts: Set, - results: TestResult.AggregatedResult, - ) => Promise; - getLastError: () => Error; -}; - export type TestFramework = ( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, @@ -76,11 +52,6 @@ export type TestRunnerContext = { changedFiles?: Set; }; -export type TestRunData = Array<{ - context: Context; - matches: {allTests: number; tests: Array; total: number}; -}>; - // TODO: Should live in `@jest/core` or `jest-watcher` export type WatcherState = { interrupted: boolean; diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 0cae4501c33b..e6e4fbaae8fa 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -30,7 +30,7 @@ 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'; +import {Context as JestContext} from './types'; type HasteMapOptions = { console?: Console; @@ -52,6 +52,10 @@ type ResolveOptions = Parameters[1]; type BooleanObject = {[key: string]: boolean}; type CacheFS = {[path: string]: string}; +namespace Runtime { + export type Context = JestContext; +} + const testTimeoutSymbol = Symbol.for('TEST_TIMEOUT_SYMBOL'); const retryTimesSymbol = Symbol.for('RETRY_TIMES'); @@ -72,6 +76,7 @@ const getModuleNameMapper = (config: Config.ProjectConfig) => { const unmockRegExpCache = new WeakMap(); +/* eslint-disable-next-line no-redeclare */ class Runtime { static ScriptTransformer: typeof ScriptTransformer; @@ -188,7 +193,7 @@ class Runtime { watch?: boolean; watchman: boolean; }, - ): Promise { + ): Promise { createDirectory(config.cacheDirectory); const instance = Runtime.createHasteMap(config, { console: options.console, diff --git a/packages/jest-transform/src/ScriptTransformer.ts b/packages/jest-transform/src/ScriptTransformer.ts index 2fbf03a78ecf..b8d0c5507b2e 100644 --- a/packages/jest-transform/src/ScriptTransformer.ts +++ b/packages/jest-transform/src/ScriptTransformer.ts @@ -223,7 +223,7 @@ export default class ScriptTransformer { // Ignore cache if `config.cache` is set (--no-cache) let code = this._config.cache ? readCodeCacheFile(cacheFilePath) : null; - const shouldCallTransform = transform && this._shouldTransform(filename); + const shouldCallTransform = transform && this.shouldTransform(filename); // That means that the transform has a custom instrumentation // logic and will handle it based on `config.collectCoverage` option @@ -322,7 +322,7 @@ export default class ScriptTransformer { const willTransform = !isInternalModule && !isCoreModule && - (this._shouldTransform(filename) || instrument); + (this.shouldTransform(filename) || instrument); try { const extraGlobals = (options && options.extraGlobals) || []; @@ -399,7 +399,15 @@ export default class ScriptTransformer { return result; } + /** + * @deprecated use `this.shouldTransform` instead + */ + // @ts-ignore: Unused and private - remove in Jest 25 private _shouldTransform(filename: Config.Path): boolean { + return this.shouldTransform(filename); + } + + shouldTransform(filename: Config.Path): boolean { const ignoreRegexp = this._cache.ignorePatternsRegExp; const isIgnored = ignoreRegexp ? ignoreRegexp.test(filename) : false; diff --git a/packages/jest-types/src/Config.ts b/packages/jest-types/src/Config.ts index bdd9c64efc39..c2c70c829be9 100644 --- a/packages/jest-types/src/Config.ts +++ b/packages/jest-types/src/Config.ts @@ -19,7 +19,7 @@ export type HasteConfig = { providesModuleNodeModules: Array; }; -export type ReporterConfig = [string, Object]; +export type ReporterConfig = [string, {[key: string]: unknown}]; export type ConfigGlobals = Object; diff --git a/packages/jest-watcher/src/BaseWatchPlugin.ts b/packages/jest-watcher/src/BaseWatchPlugin.ts index 3570559bcab7..2e7386ae3f8c 100644 --- a/packages/jest-watcher/src/BaseWatchPlugin.ts +++ b/packages/jest-watcher/src/BaseWatchPlugin.ts @@ -5,32 +5,41 @@ * LICENSE file in the root directory of this source tree. */ -import {WatchPlugin} from './types'; +import {Config} from '@jest/types'; +import { + JestHookSubscriber, + UpdateConfigCallback, + UsageData, + WatchPlugin, +} from './types'; class BaseWatchPlugin implements WatchPlugin { - protected _stdin: NodeJS.ReadableStream; - protected _stdout: NodeJS.WritableStream; + protected _stdin: NodeJS.ReadStream; + protected _stdout: NodeJS.WriteStream; constructor({ stdin, stdout, }: { - stdin: NodeJS.ReadableStream; - stdout: NodeJS.WritableStream; + stdin: NodeJS.ReadStream; + stdout: NodeJS.WriteStream; }) { this._stdin = stdin; this._stdout = stdout; } - apply() {} + apply(_hooks: JestHookSubscriber) {} - getUsageInfo() { + getUsageInfo(_globalConfig: Config.GlobalConfig): UsageData | null { return null; } - onKey() {} + onKey(_key: string) {} - run() { + run( + _globalConfig: Config.GlobalConfig, + _updateConfigAndRun: UpdateConfigCallback, + ): Promise { return Promise.resolve(); } } diff --git a/packages/jest-watcher/src/PatternPrompt.ts b/packages/jest-watcher/src/PatternPrompt.ts index 8663932f2b69..2490d9943e16 100644 --- a/packages/jest-watcher/src/PatternPrompt.ts +++ b/packages/jest-watcher/src/PatternPrompt.ts @@ -9,6 +9,7 @@ import chalk from 'chalk'; import ansiEscapes from 'ansi-escapes'; import {specialChars} from 'jest-util'; import Prompt from './lib/Prompt'; +import {ScrollOptions} from './types'; const {CLEAR} = specialChars; @@ -35,7 +36,11 @@ export default class PatternPrompt { this._currentUsageRows = usageRows; } - run(onSuccess: () => void, onCancel: () => void, options?: {header: string}) { + run( + onSuccess: (value: string) => void, + onCancel: () => void, + options?: {header: string}, + ) { this._pipe.write(ansiEscapes.cursorHide); this._pipe.write(CLEAR); @@ -52,7 +57,7 @@ export default class PatternPrompt { this._prompt.enter(this._onChange.bind(this), onSuccess, onCancel); } - protected _onChange() { + protected _onChange(_pattern: string, _options: ScrollOptions) { this._pipe.write(ansiEscapes.eraseLine); this._pipe.write(ansiEscapes.cursorLeft); } diff --git a/packages/jest-watcher/src/index.ts b/packages/jest-watcher/src/index.ts index 766fba239f10..1ccf49f523e9 100644 --- a/packages/jest-watcher/src/index.ts +++ b/packages/jest-watcher/src/index.ts @@ -9,5 +9,15 @@ export {default as BaseWatchPlugin} from './BaseWatchPlugin'; export {default as JestHook} from './JestHooks'; export {default as PatternPrompt} from './PatternPrompt'; export * from './constants'; +export { + AllowedConfigOptions, + JestHookEmitter, + JestHookSubscriber, + ScrollOptions, + UpdateConfigCallback, + UsageData, + WatchPlugin, + WatchPluginClass, +} from './types'; export {default as Prompt} from './lib/Prompt'; export * from './lib/patternModeHelpers'; diff --git a/packages/jest-watcher/src/lib/Prompt.ts b/packages/jest-watcher/src/lib/Prompt.ts index c3e26c233e87..46612eb60302 100644 --- a/packages/jest-watcher/src/lib/Prompt.ts +++ b/packages/jest-watcher/src/lib/Prompt.ts @@ -12,8 +12,8 @@ export default class Prompt { private _entering: boolean; private _value: string; private _onChange: () => void; - private _onSuccess: (value?: string) => void; - private _onCancel: (value?: string) => void; + private _onSuccess: (value: string) => void; + private _onCancel: (value: string) => void; private _offset: number; private _promptLength: number; private _selection: string | null; @@ -39,7 +39,7 @@ export default class Prompt { enter( onChange: (pattern: string, options: ScrollOptions) => void, - onSuccess: () => void, + onSuccess: (pattern: string) => void, onCancel: () => void, ) { this._entering = true; diff --git a/packages/jest-watcher/src/types.ts b/packages/jest-watcher/src/types.ts index 8886c011cd1f..e8c5bb128d20 100644 --- a/packages/jest-watcher/src/types.ts +++ b/packages/jest-watcher/src/types.ts @@ -64,18 +64,24 @@ export type AllowedConfigOptions = Partial< > & {mode: 'watch' | 'watchAll'} >; +export type UpdateConfigCallback = (config?: AllowedConfigOptions) => void; + export interface WatchPlugin { isInternal?: boolean; apply?: (hooks: JestHookSubscriber) => void; - getUsageInfo?: ( - globalConfig: Config.GlobalConfig, - ) => UsageData | undefined | null; + getUsageInfo?: (globalConfig: Config.GlobalConfig) => UsageData | null; onKey?: (value: string) => void; run?: ( globalConfig: Config.GlobalConfig, - updateConfigAndRun: (config?: AllowedConfigOptions) => void, + updateConfigAndRun: UpdateConfigCallback, ) => Promise; } +export interface WatchPluginClass { + new (options: { + stdin: NodeJS.ReadStream; + stdout: NodeJS.WriteStream; + }): WatchPlugin; +} export type ScrollOptions = { offset: number; diff --git a/website/versioned_docs/version-23.x/WatchPlugins.md b/website/versioned_docs/version-23.x/WatchPlugins.md index 6f830989149c..56a2208d2e59 100644 --- a/website/versioned_docs/version-23.x/WatchPlugins.md +++ b/website/versioned_docs/version-23.x/WatchPlugins.md @@ -165,6 +165,7 @@ For stability and safety reasons, only part of the global configuration keys can - [`notify`](configuration.html#notify-boolean) - [`notifyMode`](configuration.html#notifymode-string) - [`onlyFailures`](configuration.html#onlyfailures-boolean) +- [`passWithNoTests`](cli.html#passwithnotests) - [`reporters`](configuration.html#reporters-array-modulename-modulename-options) - [`testNamePattern`](cli.html#testnamepattern-regex) - [`testPathPattern`](cli.html#testpathpattern-regex) diff --git a/yarn.lock b/yarn.lock index ea115684f057..d7670b5c202f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10102,7 +10102,7 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= -pirates@^4.0.0: +pirates@^4.0.0, pirates@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==