I developed a module with Typescipt and ESM ("type": "module"
in package.json
).
I also use some path aliases, this is the tsconfig.json
{
"compilerOptions": {
"moduleResolution": "Node16",
"module": "Node16",
"target": "ES2015",
"lib": [
"ES2022"
],
"resolveJsonModule": true,
"strictNullChecks": true,
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"esModuleInterop": true,
"baseUrl": ".",
"paths": {
"@/*": [
"./source/*"
],
"@": [
"./source"
],
"@src/*": [
"./source/*"
],
"@src": [
"./source"
],
"@test/*": [
"./test/*"
],
"@test": [
"./test"
]
},
"outDir": "./dist"
},
"include": [
"source",
"test"
]
}
And this is the jest.config.ts
import type { Config } from '@jest/types';
import { pathsToModuleNameMapper } from 'ts-jest';
import tsconfigJson from './tsconfig.json';
const config: Config.InitialOptions = {
preset: 'ts-jest/presets/default-esm',
testEnvironment: 'node',
verbose: true,
globals: {
'ts-jest': {
tsconfig: './tsconfig.json',
useESM: true
}
},
moduleNameMapper: pathsToModuleNameMapper(tsconfigJson.compilerOptions.paths, { prefix: '<rootDir>/' }),
transformIgnorePatterns: ['<rootDir>/node_modules/']
};
export default config;
The problem is that, because of ESM, the modules do not work with the aliases:
FAIL test/suites/modules/mangleTypes.test.ts
● Test suite failed to run
Configuration error:
Could not locate module @src/modules/mangleTypes.js mapped as:
/home/euber/Github/lifeware-java-mangler/source/$1.
Please check your configuration for these entries:
{
"moduleNameMapper": {
"/^@src\/(.*)$/": "/home/euber/Github/lifeware-java-mangler/source/$1"
},
"resolver": undefined
}
> 1 | import { mangleType, PrimitiveType } from '@src/modules/mangleTypes.js';
| ^
2 |
3 | describe('Test @/modules/mangleTypes', function () {
4 | describe('Primitive types', function () {
at createNoMappedModuleFoundError (node_modules/jest-resolve/build/resolver.js:900:17)
at Object.<anonymous> (test/suites/modules/mangleTypes.test.ts:1:1)
I referenced this as a solution, but it does not work.
UPDATE I tried also like this, but it does not work
Eventually I managed to make it work by mixing the two solutions:
import type { Config } from '@jest/types';
import { pathsToModuleNameMapper } from 'ts-jest';
import tsconfigJson from './tsconfig.json';
function manageKey(key: string): string {
return key.includes('(.*)') ? key.slice(0, -1) + '\\.js$' : key;
}
function manageMapper(mapper: Record<string, string>): Record<string, string> {
const newMapper: Record<string, string> = {};
for (const key in mapper) {
newMapper[manageKey(key)] = mapper[key];
}
newMapper['^\.\/(.*)\\.js$'] = './$1';
return newMapper;
}
const config: Config.InitialOptions = {
preset: 'ts-jest/presets/default-esm',
testEnvironment: 'node',
verbose: true,
globals: {
'ts-jest': {
tsconfig: './tsconfig.json',
useESM: true
}
},
moduleNameMapper: manageMapper(pathsToModuleNameMapper(tsconfigJson.compilerOptions.paths, { prefix: '<rootDir>/' }) as Record<string, string>),
transformIgnorePatterns: ['<rootDir>/node_modules/']
};
export default config;
UPDATE:
newMapper['^\.\/(.*)\\.js$'] = './$1';
does not work in cases like ../utils/index.js
. To replace the .js
with everything, the regex should be changed with something like newMapper['^(.*).js$'] = '$1';
.
The total code would be:
import type { Config } from '@jest/types';
import { pathsToModuleNameMapper } from 'ts-jest';
import tsconfigJson from './tsconfig.json';
function manageKey(key: string): string {
return key.includes('(.*)') ? key.slice(0, -1) + '\\.js$' : key;
}
function manageMapper(mapper: Record<string, string>): Record<string, string> {
const newMapper: Record<string, string> = {};
for (const key in mapper) {
newMapper[manageKey(key)] = mapper[key];
}
newMapper['^(.*).js$'] = '$1';
return newMapper;
}
const config: Config.InitialOptions = {
preset: 'ts-jest/presets/default-esm',
testEnvironment: 'node',
verbose: true,
globals: {
'ts-jest': {
tsconfig: './tsconfig.json',
useESM: true
}
},
coverageProvider: 'v8',
moduleNameMapper: manageMapper(pathsToModuleNameMapper(tsconfigJson.compilerOptions.paths, { prefix: '<rootDir>/' }) as Record<string, string>),
transformIgnorePatterns: ['<rootDir>/node_modules/']
};
export default config;