Skip to content

Commit

Permalink
fix: transform js ESM file from node_modules
Browse files Browse the repository at this point in the history
`ts.LanguageService` somehow can't transform `js` file which has content in ESM.

When dealing with those files, we simply transform them with `ts.transpileModule` API without applying any AST transformers. We don't apply type-check on these files either since they are prebuilt. This should benefit the performance and help users to work easier with ESM packages when running Jest in CJS mode.

Fixes #2913
  • Loading branch information
ahnpnl committed Feb 21, 2025
1 parent bc78441 commit b2b3934
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 3 deletions.
2 changes: 2 additions & 0 deletions e2e/process-js-packages/__tests__/process-js-packages.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import camelCase from 'lodash-es/camelCase';
import { union } from 'set-utilities';
import { __assign } from 'tslib';

test('should pass', () => {
expect(camelCase('foo-bar')).toBe('fooBar');
expect(typeof __assign).toBe('function');
expect(union(new Set([1, 2, 3]), new Set([4, 5, 6]))).toStrictEqual(new Set([1, 2, 3, 4, 5, 6]));
});
2 changes: 1 addition & 1 deletion e2e/process-js-packages/jest-cjs.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const config: JestConfigWithTsJest = {
},
],
},
transformIgnorePatterns: ['node_modules/(?!lodash-es)'],
transformIgnorePatterns: ['node_modules/(?!lodash-es|set-utilities)'],
};

export default config;
2 changes: 1 addition & 1 deletion e2e/process-js-packages/jest-transpile-cjs.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const config: JestConfigWithTsJest = {
},
],
},
transformIgnorePatterns: ['node_modules/(?!lodash-es)'],
transformIgnorePatterns: ['node_modules/(?!lodash-es|set-utilities)'],
};

export default config;
3 changes: 2 additions & 1 deletion e2e/process-js-packages/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"private": true,
"devDependencies": {
"@types/lodash-es": "^4.17.12",
"lodash-es": "^4.17.21"
"lodash-es": "^4.17.21",
"set-utilities": "^1.5.7"
}
}
8 changes: 8 additions & 0 deletions e2e/process-js-packages/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,13 @@ __metadata:
dependencies:
"@types/lodash-es": "npm:^4.17.12"
lodash-es: "npm:^4.17.21"
set-utilities: "npm:^1.5.7"
languageName: unknown
linkType: soft

"set-utilities@npm:^1.5.7":
version: 1.5.7
resolution: "set-utilities@npm:1.5.7"
checksum: 10/d36f10778cb31bd2e6e5521473dbe9df1dd8e7ff86300910134aa0c7397da4845a4d058ffb773a1079b2ed2f9b85b76a5880921588cf211430e930eda171cfc5
languageName: node
linkType: hard
35 changes: 35 additions & 0 deletions src/ng-jest-transformer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { transformSync } from 'esbuild';
import { TsJestTransformer } from 'ts-jest';
import { transpileModule } from 'typescript';

import packageJson from '../package.json';
import { NgJestCompiler } from './compiler/ng-jest-compiler';
Expand All @@ -15,11 +16,21 @@ jest.mock('esbuild', () => {
};
});
const mockedTransformSync = jest.mocked(transformSync);
jest.mock('typescript', () => {
return {
...jest.requireActual('typescript'),
transpileModule: jest.fn().mockReturnValue({
outputText: '',
}),
};
});
const mockTranspileModule = jest.mocked(transpileModule);

describe('NgJestTransformer', () => {
beforeEach(() => {
// @ts-expect-error testing purpose
TsJestTransformer._cachedConfigSets = [];
mockTranspileModule.mockClear();
});

test('should create NgJestCompiler and NgJestConfig instances', () => {
Expand Down Expand Up @@ -148,6 +159,30 @@ describe('NgJestTransformer', () => {
mockedTransformSync.mockClear();
});

it('should use "transpileModule" to process `node_modules` js file', () => {
const transformCfg = {
cacheFS: new Map(),
config: {
cwd: process.cwd(),
extensionsToTreatAsEsm: [],
testMatch: [],
testRegex: [],
},
} as any; // eslint-disable-line @typescript-eslint/no-explicit-any
const tr = new NgJestTransformer({});
tr.process(
`
const pi = parseFloat(3.124);
export { pi };
`,
'node_modules/random-package/foo.js',
transformCfg,
);

expect(mockTranspileModule.mock.calls[0][1].fileName).toBe('node_modules/random-package/foo.js');
});

test.each([
{
tsconfig: {
Expand Down
23 changes: 23 additions & 0 deletions src/ng-jest-transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type { TransformedSource } from '@jest/transform';
import { LogContexts, LogLevels, type Logger, createLogger } from 'bs-logger';
import { transformSync } from 'esbuild';
import { type TsJestTransformerOptions, ConfigSet, TsJestTransformer, type TsJestTransformOptions } from 'ts-jest';
import { updateOutput } from 'ts-jest/dist/legacy/compiler/compiler-utils';
import type { TranspileOutput } from 'typescript';

import { NgJestCompiler } from './compiler/ng-jest-compiler';
import { NgJestConfig } from './config/ng-jest-config';
Expand Down Expand Up @@ -93,6 +95,27 @@ export class NgJestTransformer extends TsJestTransformer {
map,
};
} else {
if (filePath.includes('node_modules') && filePath.endsWith('.js')) {
/**
* Simply transform the file without applying any extra AST transformers. We might consider to support using AST transformers on `node_modules` files when there are requests.
* Since the files in `node_modules` are prebuilt, we don't need to perform type check on these files which should benefit the performance.
*/
const result: TranspileOutput = configSet.compilerModule.transpileModule(fileContent, {
compilerOptions: {
...configSet.parsedTsConfig.options,
module:
transformOptions.supportsStaticESM && configSet.useESM
? configSet.parsedTsConfig.options.module
: configSet.compilerModule.ModuleKind.CommonJS,
},
fileName: filePath,
});

return {
code: updateOutput(result.outputText, filePath, result.sourceMapText),
};
}

return super.process(fileContent, filePath, transformOptions);
}
}
Expand Down

0 comments on commit b2b3934

Please sign in to comment.