Fix Jest config file imports for Jest v30 ESM compatibility#551
Fix Jest config file imports for Jest v30 ESM compatibility#551kapral18 wants to merge 3 commits intosorenlouv:mainfrom
Conversation
|
When I run: yarn run v1.22.22
$ jest --config ./jest.config.private.ts --runInBand --listTests
Error: Jest: Failed to parse the TypeScript config file /Users/sorenlouv/dev/backport/jest.config.private.ts
TSError: ⨯ Unable to compile TypeScript:
jest.config.private.ts:2:24 - error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled.
2 import baseConfig from './jest.config.ts';
~~~~~~~~~~~~~~~~~~
at readConfigFileAndSetRootDir (/Users/sorenlouv/dev/backport/node_modules/@jest/core/node_modules/jest-config/build/index.js:2242:13)
at async readInitialOptions (/Users/sorenlouv/dev/backport/node_modules/@jest/core/node_modules/jest-config/build/index.js:1140:15)
at async readConfig (/Users/sorenlouv/dev/backport/node_modules/@jest/core/node_modules/jest-config/build/index.js:918:7)
at async readConfigs (/Users/sorenlouv/dev/backport/node_modules/@jest/core/node_modules/jest-config/build/index.js:1168:26)
at async runCLI (/Users/sorenlouv/dev/backport/node_modules/@jest/core/build/index.js:1393:7)
at async Object.run (/Users/sorenlouv/dev/backport/node_modules/jest-cli/build/index.js:656:9)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command. |
d365b21 to
8836ab4
Compare
|
Thanks for testing this! I've identified and fixed the issue. Root CauseThe error you encountered is due to a difference in Node.js versions:
Node 22.18.0 introduced native TypeScript support with type stripping, which allows Node to natively handle How Jest v30 Loads TypeScript Config FilesWhen Jest v30 encounters a TypeScript config file, it uses ts-node internally to compile it. The issue is that ts-node is registered with these default options: tsLoader.register({
compilerOptions: {
module: 'CommonJS'
},
moduleTypes: {
'**': 'cjs'
}
})This forces CommonJS mode, which doesn't allow The FixJest supports passing custom options to ts-node via the /**
* @jest-config-loader-options {"compilerOptions":{"allowImportingTsExtensions":true}}
*/
import baseConfig from './jest.config.ts';This tells ts-node to enable TestingI've verified this fix works with both:
All test commands now work correctly: yarn test-all --listTests # ✅ Works
yarn test-mutation --listTests # ✅ Works
yarn test-private --listTests # ✅ WorksThe solution ensures compatibility across all Node 22.x versions without requiring a minimum version bump. |
| { | ||
| "references": [ | ||
| { "path": "./tsconfig.jest-config.json" } | ||
| ], |
There was a problem hiding this comment.
Why use project references for jest configs? Why not have a separate tsconfig, like the one for eslint https://github.com/sorenlouv/backport/blob/main/tsconfig.eslint.json?
There was a problem hiding this comment.
tsconfig.jest-config.json is not a standard path for tsconfig lsps to pickup. So IDEs and editors just don't see it. With eslint config it consumes the custom path of tsconfig directly but with these custom jest-config ts files there is nowhere to link the two together. So reference paths is a natural way to split it while exposing a single entry point for discovery by whatever client.
Jest v30 switched to using Node's native ESM loader for config files, which requires explicit file extensions in imports. This change adds support for .ts extensions in Jest config file imports while maintaining proper TypeScript and ESLint integration. Changes: - Created tsconfig.jest-config.json: Separate TypeScript config for Jest config files that enables allowImportingTsExtensions - Updated tsconfig.json: Added project reference to tsconfig.jest-config.json and excluded jest.config*.ts files to prevent overlap - Updated jest.config.*.ts: Changed imports to use explicit .ts extensions (e.g., import from './jest.config.ts') - Updated eslint.config.js: Added specific configuration for Jest config files to use the correct tsconfig and ignore build artifacts - Updated .gitignore: Added .tsbuildinfo/ to ignore TypeScript build output Benefits: - IDE support: IDEs automatically use the correct tsconfig via project references - Clean imports: No @ts-ignore hacks needed - Full type checking: All files properly type-checked - All test scripts work: test-all, test-mutation, test-private Technical details: - Uses TypeScript composite projects with emitDeclarationOnly to satisfy both the composite requirement and allowImportingTsExtensions constraint - Jest config files loaded by Node ESM require .ts extensions - Test files continue to use traditional imports (handled by ts-jest)
Add @jest-config-loader-options docblock pragma to Jest config files that import other .ts files. This ensures ts-node compiles these files with allowImportingTsExtensions enabled, which is required for .ts extension imports to work. The issue occurs because Jest v30 uses ts-node to compile TypeScript config files, and ts-node registers with module: 'CommonJS' by default, which doesn't allow .ts extensions in imports. The docblock pragma passes compiler options to ts-node, enabling the required setting. This fix ensures compatibility across all Node 22.x versions, including versions prior to 22.18.0 which don't have native TypeScript support. Tested with Node 22.17.1 and 22.20.0.
954c7c8 to
f51dbaa
Compare
Summary
Fixes Jest config file imports to work with Jest v30's ESM requirements. Jest v30 switched to using Node's native ESM loader for config files, which requires explicit file extensions in imports.
The Problem
The
test-all,test-mutation, andtest-privatescripts were failing with:Jest v30 config files are now loaded by Node's ESM loader, which requires explicit
.tsextensions, but TypeScript doesn't allow.tsextensions in imports by default.The Solution
How Jest v30 Loads TypeScript Config Files
When Jest v30 encounters a TypeScript config file (e.g.,
jest.config.private.ts), it uses ts-node internally to compile it. However, ts-node is registered with these default options:This forces all files to be treated as CommonJS, which doesn't allow
.tsextensions in imports withoutallowImportingTsExtensionsenabled.The Fix: Jest Docblock Pragma
Jest supports passing custom options to ts-node via the
@jest-config-loader-optionsdocblock pragma. By adding this to config files that import other.tsfiles:This tells ts-node to enable
allowImportingTsExtensionswhen compiling these specific config files, allowing the.tsextension imports to work correctly.Why This Works Across All Node Versions
Changes
@jest-config-loader-optionsdocblock pragma tojest.config.all.ts,jest.config.mutation.ts, andjest.config.private.ts.tsextensions in importstsconfig.jest-config.jsonfor IDE support (TypeScript project references).tsbuildinfo/to.gitignoreBenefits
test-all,test-mutation,test-privateTechnical Notes
.tsextensions (not test files - those use ts-jest)tsconfig.jest-config.jsonprovides IDE support but isn't used by Jest at runtimeTesting
Tested with: