diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f8139630c88..67d7fd147a47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - `[jest-snapshot]` Remove only the added newlines in multiline snapshots ([#8859](https://github.com/facebook/jest/pull/8859)) - `[jest-snapshot]` Distinguish empty string from external snapshot not written ([#8880](https://github.com/facebook/jest/pull/8880)) - `[jest-snapshot]` [**BREAKING**] Distinguish empty string from internal snapshot not written ([#8898](https://github.com/facebook/jest/pull/8898)) +- `[jest-transform]` Properly cache transformed files across tests ([#8890](https://github.com/facebook/jest/pull/8890)) ### Chore & Maintenance diff --git a/e2e/__tests__/transform.test.ts b/e2e/__tests__/transform.test.ts index a62524d3640a..d00f6189af49 100644 --- a/e2e/__tests__/transform.test.ts +++ b/e2e/__tests__/transform.test.ts @@ -185,3 +185,23 @@ describe('transformer-config', () => { expect(stdout).toMatchSnapshot(); }); }); + +describe('transformer caching', () => { + const dir = path.resolve(__dirname, '../transform/cache'); + const transformedFile = path.resolve(dir, './common-file.js'); + + it('does not rerun transform within worker', () => { + // --no-cache because babel can cache stuff and result in false green + const {stdout} = runJest(dir, ['--no-cache', '-w=2']); + + const loggedFiles = stdout.split('\n'); + + // Verify any lines logged are _just_ the file we care about + loggedFiles.forEach(line => { + expect(line).toBe(transformedFile); + }); + + // We run with 2 workers, so the file should be transformed twice + expect(loggedFiles).toHaveLength(2); + }); +}); diff --git a/e2e/transform/cache/__tests__/aTests.js b/e2e/transform/cache/__tests__/aTests.js new file mode 100644 index 000000000000..2f8f32a8b022 --- /dev/null +++ b/e2e/transform/cache/__tests__/aTests.js @@ -0,0 +1,12 @@ +/** + * 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. + */ + +const phrase = require('../common-file'); + +test('A', () => { + expect(phrase).toBe('hello'); +}); diff --git a/e2e/transform/cache/__tests__/bTests.js b/e2e/transform/cache/__tests__/bTests.js new file mode 100644 index 000000000000..c896f74c4967 --- /dev/null +++ b/e2e/transform/cache/__tests__/bTests.js @@ -0,0 +1,12 @@ +/** + * 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. + */ + +const phrase = require('../common-file'); + +test('B', () => { + expect(phrase).toBe('hello'); +}); diff --git a/e2e/transform/cache/__tests__/cTests.js b/e2e/transform/cache/__tests__/cTests.js new file mode 100644 index 000000000000..55827295d0af --- /dev/null +++ b/e2e/transform/cache/__tests__/cTests.js @@ -0,0 +1,12 @@ +/** + * 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. + */ + +const phrase = require('../common-file'); + +test('C', () => { + expect(phrase).toBe('hello'); +}); diff --git a/e2e/transform/cache/__tests__/dTests.js b/e2e/transform/cache/__tests__/dTests.js new file mode 100644 index 000000000000..74716a8e9aa3 --- /dev/null +++ b/e2e/transform/cache/__tests__/dTests.js @@ -0,0 +1,12 @@ +/** + * 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. + */ + +const phrase = require('../common-file'); + +test('D', () => { + expect(phrase).toBe('hello'); +}); diff --git a/e2e/transform/cache/common-file.js b/e2e/transform/cache/common-file.js new file mode 100644 index 000000000000..798c701db1fa --- /dev/null +++ b/e2e/transform/cache/common-file.js @@ -0,0 +1,8 @@ +/** + * 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. + */ + +module.exports = 'hello'; diff --git a/e2e/transform/cache/package.json b/e2e/transform/cache/package.json new file mode 100644 index 000000000000..d75bca46c3ba --- /dev/null +++ b/e2e/transform/cache/package.json @@ -0,0 +1,10 @@ +{ + "name": "cache", + "version": "1.0.0", + "jest": { + "testEnvironment": "node", + "transform": { + "^.+\\.js$": "/transformer.js" + } + } +} diff --git a/e2e/transform/cache/transformer.js b/e2e/transform/cache/transformer.js new file mode 100644 index 000000000000..10d02e637f80 --- /dev/null +++ b/e2e/transform/cache/transformer.js @@ -0,0 +1,16 @@ +/** + * 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. + */ + +module.exports = { + process(src, path) { + if (path.includes('common')) { + console.log(path); + } + + return src; + }, +}; diff --git a/packages/jest-transform/src/ScriptTransformer.ts b/packages/jest-transform/src/ScriptTransformer.ts index 3057dbe6586e..9079e9f90efd 100644 --- a/packages/jest-transform/src/ScriptTransformer.ts +++ b/packages/jest-transform/src/ScriptTransformer.ts @@ -43,10 +43,7 @@ const {version: VERSION} = require('../package.json'); // This data structure is used to avoid recalculating some data every time that // we need to transform a file. Since ScriptTransformer is instantiated for each // file we need to keep this object in the local scope of this module. -const projectCaches: WeakMap< - Config.ProjectConfig, - ProjectCache -> = new WeakMap(); +const projectCaches = new Map(); // To reset the cache for specific changesets (rather than package version). const CACHE_VERSION = '1'; @@ -74,17 +71,18 @@ export default class ScriptTransformer { this._transformCache = new Map(); this._transformConfigCache = new Map(); - let projectCache = projectCaches.get(config); + const configString = stableStringify(this._config); + let projectCache = projectCaches.get(configString); if (!projectCache) { projectCache = { - configString: stableStringify(this._config), + configString, ignorePatternsRegExp: calcIgnorePatternRegExp(this._config), transformRegExp: calcTransformRegExp(this._config), transformedFiles: new Map(), }; - projectCaches.set(config, projectCache); + projectCaches.set(configString, projectCache); } this._cache = projectCache;