diff --git a/packages/jest-transform/src/ScriptTransformer.ts b/packages/jest-transform/src/ScriptTransformer.ts index df93b3f877ca..147c1f66230c 100644 --- a/packages/jest-transform/src/ScriptTransformer.ts +++ b/packages/jest-transform/src/ScriptTransformer.ts @@ -271,7 +271,7 @@ export default class ScriptTransformer { return transformer; } - transform = await import(transformPath); + transform = await import(transformPath).catch(console.log); if (!transform) { throw new TypeError('Jest: a transform must export something.'); @@ -672,7 +672,7 @@ export default class ScriptTransformer { instrument, supportsDynamicImport, supportsStaticESM, - ); + ).catch(console.log); code = transformedSource.code; sourceMapPath = transformedSource.sourceMapPath; @@ -684,6 +684,7 @@ export default class ScriptTransformer { sourceMapPath, }; } catch (e) { + console.log({error: e}); throw handlePotentialSyntaxError(e); } } @@ -755,18 +756,20 @@ export default class ScriptTransformer { } } - const result = await this._transformAndBuildScriptAsync( - filename, - options, - instrument, - fileSource, - ); - - if (scriptCacheKey) { - this._cache.transformedFiles.set(scriptCacheKey, result); - } + const result = await this._transformAndBuildScriptAsync( + filename, + options, + instrument, + fileSource, + ).catch(e=>{ + console.log({eno: e}); + }); - return result; + if (scriptCacheKey) { + this._cache.transformedFiles.set(scriptCacheKey, result); + } + + return result; } transform( diff --git a/packages/jest-transform/src/__tests__/__snapshots__/script_transformer.test.js.snap b/packages/jest-transform/src/__tests__/__snapshots__/script_transformer.test.js.snap index 6114987506eb..09aaf3866791 100644 --- a/packages/jest-transform/src/__tests__/__snapshots__/script_transformer.test.js.snap +++ b/packages/jest-transform/src/__tests__/__snapshots__/script_transformer.test.js.snap @@ -73,6 +73,158 @@ Object { } `; +exports[`ScriptTransformer transforms a file async properly 1`] = ` +/* istanbul ignore next */ +function cov_25u22311x4() { + var path = "/fruits/banana.js"; + var hash = "3f8e915bed83285455a8a16aa04dc0cf5242d755"; + var global = new Function("return this")(); + var gcv = "__coverage__"; + var coverageData = { + path: "/fruits/banana.js", + statementMap: { + "0": { + start: { + line: 1, + column: 0 + }, + end: { + line: 1, + column: 26 + } + } + }, + fnMap: {}, + branchMap: {}, + s: { + "0": 0 + }, + f: {}, + b: {}, + inputSourceMap: null, + _coverageSchema: "1a1c01bbd47fc00a2c39e90264f33305004495a9", + hash: "3f8e915bed83285455a8a16aa04dc0cf5242d755" + }; + var coverage = global[gcv] || (global[gcv] = {}); + + if (!coverage[path] || coverage[path].hash !== hash) { + coverage[path] = coverageData; + } + + var actualCoverage = coverage[path]; + { + // @ts-ignore + cov_25u22311x4 = function () { + return actualCoverage; + }; + } + return actualCoverage; +} + +cov_25u22311x4(); +cov_25u22311x4().s[0]++; +module.exports = "banana"; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImJhbmFuYS5qcyJdLCJuYW1lcyI6WyJtb2R1bGUiLCJleHBvcnRzIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFlWTs7Ozs7Ozs7OztBQWZaQSxNQUFNLENBQUNDLE9BQVAsR0FBaUIsUUFBakIiLCJzb3VyY2VzQ29udGVudCI6WyJtb2R1bGUuZXhwb3J0cyA9IFwiYmFuYW5hXCI7Il19 +`; + +exports[`ScriptTransformer transforms a file async properly 2`] = ` +/* istanbul ignore next */ +function cov_23yvu8etmu() { + var path = "/fruits/kiwi.js"; + var hash = "8b5afd38d79008f13ebc229b89ef82b12ee9447a"; + var global = new Function("return this")(); + var gcv = "__coverage__"; + var coverageData = { + path: "/fruits/kiwi.js", + statementMap: { + "0": { + start: { + line: 1, + column: 0 + }, + end: { + line: 1, + column: 30 + } + }, + "1": { + start: { + line: 1, + column: 23 + }, + end: { + line: 1, + column: 29 + } + } + }, + fnMap: { + "0": { + name: "(anonymous_0)", + decl: { + start: { + line: 1, + column: 17 + }, + end: { + line: 1, + column: 18 + } + }, + loc: { + start: { + line: 1, + column: 23 + }, + end: { + line: 1, + column: 29 + } + }, + line: 1 + } + }, + branchMap: {}, + s: { + "0": 0, + "1": 0 + }, + f: { + "0": 0 + }, + b: {}, + inputSourceMap: null, + _coverageSchema: "1a1c01bbd47fc00a2c39e90264f33305004495a9", + hash: "8b5afd38d79008f13ebc229b89ef82b12ee9447a" + }; + var coverage = global[gcv] || (global[gcv] = {}); + + if (!coverage[path] || coverage[path].hash !== hash) { + coverage[path] = coverageData; + } + + var actualCoverage = coverage[path]; + { + // @ts-ignore + cov_23yvu8etmu = function () { + return actualCoverage; + }; + } + return actualCoverage; +} + +cov_23yvu8etmu(); +cov_23yvu8etmu().s[0]++; + +module.exports = () => { + /* istanbul ignore next */ + cov_23yvu8etmu().f[0]++; + cov_23yvu8etmu().s[1]++; + return "kiwi"; +}; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImtpd2kuanMiXSwibmFtZXMiOlsibW9kdWxlIiwiZXhwb3J0cyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFlWTs7Ozs7Ozs7Ozs7QUFmWkEsTUFBTSxDQUFDQyxPQUFQLEdBQWlCLE1BQU07QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFNLENBQTdCIiwic291cmNlc0NvbnRlbnQiOlsibW9kdWxlLmV4cG9ydHMgPSAoKSA9PiBcImtpd2lcIjsiXX0= +`; + exports[`ScriptTransformer transforms a file properly 1`] = ` /* istanbul ignore next */ function cov_25u22311x4() { diff --git a/packages/jest-transform/src/__tests__/script_transformer.test.js b/packages/jest-transform/src/__tests__/script_transformer.test.js index fd8c31d2b007..4676b9db865a 100644 --- a/packages/jest-transform/src/__tests__/script_transformer.test.js +++ b/packages/jest-transform/src/__tests__/script_transformer.test.js @@ -104,6 +104,14 @@ jest.mock( {virtual: true}, ); +jest.mock( + 'passthrough-async-preprocessor', + () => ({ + processAsync: jest.fn(), + }), + {virtual: true}, +); + // Bad preprocessor jest.mock('skipped-required-props-preprocessor', () => ({}), {virtual: true}); @@ -256,6 +264,50 @@ describe('ScriptTransformer', () => { ); }); + it('transforms a file async properly', async () => { + const scriptTransformer = new ScriptTransformer(config); + const transformedBananaWithCoverage = await scriptTransformer.transformAsync( + '/fruits/banana.js', + makeGlobalConfig({collectCoverage: true}), + ); + + expect(wrap(transformedBananaWithCoverage.code)).toMatchSnapshot(); + + // no-cache case + expect(fs.readFileSync).toHaveBeenCalledTimes(1); + expect(fs.readFileSync).toBeCalledWith('/fruits/banana.js', 'utf8'); + + // in-memory cache + const transformedBananaWithCoverageAgain = await scriptTransformer.transformAsync( + '/fruits/banana.js', + makeGlobalConfig({collectCoverage: true}), + ); + expect(transformedBananaWithCoverageAgain).toBe( + transformedBananaWithCoverage, + ); + + const transformedKiwiWithCoverage = await scriptTransformer.transformAsync( + '/fruits/kiwi.js', + makeGlobalConfig({collectCoverage: true}), + ); + expect(wrap(transformedKiwiWithCoverage.code)).toMatchSnapshot(); + + expect(transformedBananaWithCoverage.code).not.toEqual( + transformedKiwiWithCoverage.code, + ); + expect(transformedBananaWithCoverage.code).not.toMatch(/instrumented kiwi/); + + // If we disable coverage, we get a different result. + const transformedKiwiWithoutCoverage = await scriptTransformer.transformAsync( + '/fruits/kiwi.js', + makeGlobalConfig({collectCoverage: false}), + ); + + expect(transformedKiwiWithoutCoverage.code).not.toEqual( + transformedKiwiWithCoverage.code, + ); + }); + it('does not transform Node core modules', () => { jest.mock('../shouldInstrument'); @@ -275,6 +327,25 @@ describe('ScriptTransformer', () => { expect(shouldInstrument).toHaveBeenCalledTimes(0); }); + it('does not transform Node core modules when async transforming', async () => { + jest.mock('../shouldInstrument'); + + const shouldInstrument = require('../shouldInstrument').default; + const scriptTransformer = new ScriptTransformer(config); + const fsSourceCode = process.binding('natives').fs; + + const response = await scriptTransformer.transformAsync( + 'fs', + {isCoreModule: true}, + fsSourceCode, + ); + + expect(response.code).toEqual(fsSourceCode); + + // Native files should never be transformed. + expect(shouldInstrument).toHaveBeenCalledTimes(0); + }); + it( "throws an error if `process` doesn't return a string or an object" + 'containing `code` key with processed string', @@ -314,6 +385,52 @@ describe('ScriptTransformer', () => { }, ); + it( + "throws an error if `processAsync` doesn't return a promise of string or" + + 'object containing `code` key with processed string', + () => { + config = { + ...config, + transform: [['^.+\\.js$', 'passthrough-async-preprocessor']], + }; + const scriptTransformer = new ScriptTransformer(config); + + const incorrectReturnValues = [ + [undefined, '/fruits/banana.js'], + [{a: 'a'}, '/fruits/kiwi.js'], + [[], '/fruits/grapefruit.js'], + ]; + + incorrectReturnValues.forEach(async ([returnValue, filePath]) => { + require('passthrough-async-preprocessor').processAsync + .mockImplementation((returnValue)=> { + console.log({"inside_processAsync": returnValue}); + return Promise.resolve(returnValue); + } + + ); + await scriptTransformer.transformAsync(filePath, {}) + .catch((e)=>{ + expect(e.message).toMatch('error'); + }); + }); +/* + const correctReturnValues = [ + ['code', '/fruits/banana.js'], + [{code: 'code'}, '/fruits/kiwi.js'], + ]; + + correctReturnValues.forEach(async ([returnValue, filePath]) => { + require('passthrough-preprocessor').process.mockReturnValue( + returnValue, + ); + await expect(() => scriptTransformer.transformAsync(filePath, {})) + .resolves; + }); + */ + } + ); + it("throws an error if `process` doesn't defined", () => { config = { ...config,