diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fa1ba83f5c8..b3f28d53b1c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ - `[jest-core]` Improve performance of SearchSource.findMatchingTests by 15% ([#8184](https://github.com/facebook/jest/pull/8184)) - `[jest-resolve]` Optimize internal cache lookup performance ([#8183](https://github.com/facebook/jest/pull/8183)) - `[jest-core]` Dramatically improve watch mode performance ([#8201](https://github.com/facebook/jest/pull/8201)) +- `[jest-core]` Fix memory leak of source map info and minor performance improvements ([#8234](https://github.com/facebook/jest/pull/8234)) - `[jest-console]` Fix memory leak by releasing console output reference when printed to stdout ([#8233](https://github.com/facebook/jest/pull/8233)) - `[jest-runtime]` Use `Map` instead of `Object` for module registry ([#8232](https://github.com/facebook/jest/pull/8232)) diff --git a/packages/jest-core/src/ReporterDispatcher.ts b/packages/jest-core/src/ReporterDispatcher.ts index 32102ed4751c..e76caf596919 100644 --- a/packages/jest-core/src/ReporterDispatcher.ts +++ b/packages/jest-core/src/ReporterDispatcher.ts @@ -38,6 +38,8 @@ export default class ReporterDispatcher { } // Release memory if unused later. + testResult.sourceMaps = undefined; + testResult.coverage = undefined; testResult.console = undefined; } diff --git a/packages/jest-reporters/src/coverage_reporter.ts b/packages/jest-reporters/src/coverage_reporter.ts index bb761944b417..c0832f4daab6 100644 --- a/packages/jest-reporters/src/coverage_reporter.ts +++ b/packages/jest-reporters/src/coverage_reporter.ts @@ -55,23 +55,24 @@ export default class CoverageReporter extends BaseReporter { ) { if (testResult.coverage) { this._coverageMap.merge(testResult.coverage); - // Remove coverage data to free up some memory. - delete testResult.coverage; + } - Object.keys(testResult.sourceMaps).forEach(sourcePath => { + const sourceMaps = testResult.sourceMaps; + if (sourceMaps) { + Object.keys(sourceMaps).forEach(sourcePath => { let inputSourceMap: RawSourceMap | undefined; try { const coverage: FileCoverage = this._coverageMap.fileCoverageFor( sourcePath, ); - ({inputSourceMap} = coverage.toJSON() as any); + inputSourceMap = (coverage.toJSON() as any).inputSourceMap; } finally { if (inputSourceMap) { this._sourceMapStore.registerMap(sourcePath, inputSourceMap); } else { this._sourceMapStore.registerURL( sourcePath, - testResult.sourceMaps[sourcePath], + sourceMaps[sourcePath], ); } } diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index 27eac4a7e75d..18da0d5de17b 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -253,14 +253,19 @@ async function runTestInternal( result.perfStats = {end: Date.now(), start}; result.testFilePath = path; - result.coverage = runtime.getAllCoverageInfoCopy(); - result.sourceMaps = runtime.getSourceMapInfo( - new Set(Object.keys(result.coverage || {})), - ); result.console = testConsole.getBuffer(); result.skipped = testCount === result.numPendingTests; result.displayName = config.displayName; + const coverage = runtime.getAllCoverageInfoCopy(); + if (coverage) { + const coverageKeys = Object.keys(coverage); + if (coverageKeys.length) { + result.coverage = coverage; + result.sourceMaps = runtime.getSourceMapInfo(new Set(coverageKeys)); + } + } + if (globalConfig.logHeapUsage) { if (global.gc) { global.gc(); diff --git a/packages/jest-test-result/src/formatTestResults.ts b/packages/jest-test-result/src/formatTestResults.ts index 161937b7c1dc..47720db16a29 100644 --- a/packages/jest-test-result/src/formatTestResults.ts +++ b/packages/jest-test-result/src/formatTestResults.ts @@ -16,41 +16,41 @@ import { TestResult, } from './types'; -const formatResult = ( +const formatTestResult = ( testResult: TestResult, - codeCoverageFormatter: CodeCoverageFormatter, - reporter: CodeCoverageReporter, + codeCoverageFormatter?: CodeCoverageFormatter, + reporter?: CodeCoverageReporter, ): FormattedTestResult => { - const now = Date.now(); - const output: FormattedTestResult = { - assertionResults: [], - coverage: {}, - endTime: now, - message: '', - name: testResult.testFilePath, - startTime: now, - status: 'failed', - summary: '', - }; - + const assertionResults = testResult.testResults.map(formatTestAssertion); if (testResult.testExecError) { - output.message = testResult.testExecError.message; - output.coverage = {}; + const now = Date.now(); + return { + assertionResults, + coverage: {}, + endTime: now, + message: testResult.failureMessage + ? testResult.failureMessage + : testResult.testExecError.message, + name: testResult.testFilePath, + startTime: now, + status: 'failed', + summary: '', + }; } else { const allTestsPassed = testResult.numFailingTests === 0; - output.status = allTestsPassed ? 'passed' : 'failed'; - output.startTime = testResult.perfStats.start; - output.endTime = testResult.perfStats.end; - output.coverage = codeCoverageFormatter(testResult.coverage, reporter); - } - - output.assertionResults = testResult.testResults.map(formatTestAssertion); - - if (testResult.failureMessage) { - output.message = testResult.failureMessage; + return { + assertionResults, + coverage: codeCoverageFormatter + ? codeCoverageFormatter(testResult.coverage, reporter) + : testResult.coverage, + endTime: testResult.perfStats.end, + message: testResult.failureMessage || '', + name: testResult.testFilePath, + startTime: testResult.perfStats.start, + status: allTestsPassed ? 'passed' : 'failed', + summary: '', + }; } - - return output; }; function formatTestAssertion( @@ -72,13 +72,11 @@ function formatTestAssertion( export default function formatTestResults( results: AggregatedResult, - codeCoverageFormatter?: CodeCoverageFormatter | null, + codeCoverageFormatter?: CodeCoverageFormatter, reporter?: CodeCoverageReporter, ): FormattedTestResults { - const formatter = codeCoverageFormatter || (coverage => coverage); - const testResults = results.testResults.map(testResult => - formatResult(testResult, formatter, reporter), + formatTestResult(testResult, codeCoverageFormatter, reporter), ); return {...results, testResults}; diff --git a/packages/jest-test-result/src/types.ts b/packages/jest-test-result/src/types.ts index 99c5503fb21b..e9acdc40fc86 100644 --- a/packages/jest-test-result/src/types.ts +++ b/packages/jest-test-result/src/types.ts @@ -126,7 +126,7 @@ export type TestResult = { unmatched: number; updated: number; }; - sourceMaps: { + sourceMaps?: { [sourcePath: string]: string; }; testExecError?: SerializableError;