You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
By clicking “Sign up for GitHub”, you agree to our
terms of service
and
privacy statement
. We’ll occasionally send you account related emails.
Already on GitHub?
Sign in
to your account
Issue :
TypeScript files using web-compatible ES6 imports cause Jest to throw an error about not being able to find the module. This error comes from
jest-resolve/build/index.js:229
and happens regardless of the module type specified in ts-jest (commonjs, amd, ES6, etc.)
Expected behavior :
TypeScript
supports adding a
.js
extension to import statements
for web-compatibility (since imports require a full path, including the extension).
I would expect ts-jest to allow TypeScript to handle this and convert it to commonjs before it gets passed to jest.
Minimal repo :
/* user.ts */
export class User {
public name : string;
constructor(name : string) {
this.name = name;
/* user.spec.ts */
import { User } from './user.js';
describe('User', function() {
});
gabrielbrieva, jsejcksn, thiagodp, shrujalshah28, benkroeger, MichaelSitter, ottokruse, jonahsnider, DavidPeicho, Vinnl, and 22 more reacted with thumbs up emoji
davidkhala reacted with eyes emoji
All reactions
gabrielbrieva, RealShadowNova, shrujalshah28, niemyjski, dpickett, aleessandrohr, holtwick, jhnns, pelletier197, theoludwig, and 13 more reacted with thumbs up emoji
atyrian and edgarrobledos reacted with hooray emoji
jonnyarnold, jsejcksn, RealShadowNova, jccr, aleessandrohr, SanjoSolutions, MattRiddell, holtwick, smikitky, jhnns, and 10 more reacted with heart emoji
jsejcksn, aleessandrohr, limulus, and atyrian reacted with rocket emoji
brainkim, theoludwig, and Nevah5 reacted with eyes emoji
All reactions
@kulshekhar this has been closed for awhile but the issue still happen in ts-jest 26.5.4
.
Since handling ".js" extensions in import statement is standard in TypeScript (and will become increasingly needed as Node.js moves towards ES modules), shouldn't ts-jest resolve this correctly without the need for @dpogue custom resolver?
Which error do you get, TypeScript type checking or Jest runtime errors? ts-jest
transforms ts
to js
and throws type checking errors but not runtime errors.
I have modified a bit the e2e test https://github.com/ahnpnl/ts-jest/blob/test-test/e2e/__cases__/allow-js/bar.spec.ts and CI still passes https://github.com/ahnpnl/ts-jest/runs/2155197218?check_suite_focus=true (Run tests with coverage)
at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:306:11)
at Object.<anonymous> (src/index.ts:1:1)
importing
./types.js
(
./src/types.ts
file exporting some types/enums declarations) from
./src/index.ts
.
This is Jest runtime error, not
ts-jest
type checking error. There are a few things to check:
Make sure the file has
module.exports
Make sure
allowJs
is true.
Make sure jest config
transform
value specifying
js
processed by
ts-jest
When transforming
ts
to
js
, the code
from "./types.js";
becomes
require(“./types.js”)
, which is a valid syntax. However, Jest resolver doesn’t understand, probably because missing
module.exports
Thanks for the pointers!
"./types"
doesn't have
module.exports
as it is a full ES modules codebase (allowJs is true and the transform is
"^.+\\.(t|j)s$": "ts-jest"
so no problem here).
Using on "jest-ts-webcompat-resolver", it rewrites
'./types.js'
to
'./types.ts'
so I guess that's enough for jest-resolve to understand where to look (although it still seems a bit hacky).
I set up a custom resolver and just published it to npm:
jest-ts-webcompat-resolver
Won't work for TSX files, but changing a bit the code to also tries resolving path replacing
.js
to
.tsx
seems to work fine.
function getResolver() {
try {
return require('jest-resolve/build/defaultResolver').default;
} catch (_) {
return require('jest-resolve/build/default_resolver').default;
const JAVASCRIPT_EXTENSION = /\.js$/i;
function resolverTSAndTSX(path, options) {
const resolver = options.defaultResolver || getResolver();
try {
return resolver(path, options);
} catch (error) {
if (!JAVASCRIPT_EXTENSION.test(path)) throw error;
try {
return resolver(path.replace(JAVASCRIPT_EXTENSION, '.ts'), options);
} catch (_) {
return resolver(path.replace(JAVASCRIPT_EXTENSION, '.tsx'), options);
module.exports = resolverTSAndTSX;
I'll made a PR tomorrow, but this should be included in ts-jest for sure.
EDIT: I've create a package to resolve imports same way TS does with import paths that has ".js" extension.
https://github.com/VitorLuizC/ts-jest-resolver
custom resolver doesn't belong to
ts-jest
.
ts-jest
is just a Jest transformer to transform
ts
to
js
and it doesn't do anything with the way how Jest resolves a file.
ts-jest
can add a section to documentation regarding to this error but natively, it is not
ts-jest
issue so the resolver should stay on its own, not included in
ts-jest
The issue is mainly caused by when using
js
extension, Node treats it as CommonJS, if you don't have
module.exports
it is not a valid
js
to Node to import.
It is important to distinguish between runtime error vs type checking error. Runtime errors are from Jest and type checking errors are from
ts-jest
.
ts-jest
doesn't do anything with Jest module resolution. The job of
ts-jest
is transforming
ts
to
js
. Transforming means compiling. Compiling process doesn't trigger the codes itself.
The output of
import { MyType } from "./types.js";
is
var globals_1 = require(\\"./types.js\\");
This is a correct js
compiling. However, how that require(\\"./types.js\\")
executes depending on Jest.
As I said above, ts-jest
is a Jest transformer, please check https://jestjs.io/docs/next/code-transformation to understand more.
Actually, the preset means "A Jest configuration". This preset includes a transformer, which compiles ts
into js
. I know it's a bit hard to understand what's going on in internal ts-jest
.
What tsc
does is actually compiling ts
into js
, but if you need to execute js
, tsc
won't do it for you. This is the same like Jest + ts-jest
. ts-jest
takes care of compiling ts
into js
and gives the compiled js
back to Jest. After that, Jest will execute the compiled js
using V8 VM.
It supports all features of TypeScript including type-checking
this means TypeScript language features, something like decorators (which is ECMA proposal stage 2), etc... This makes sure that the output js
is understandable to V8 VM. See more at https://kulshekhar.github.io/ts-jest/docs/next/processing
This involved adding a jest-ts-webcompat-resolver, because
jest's resolver doesn't like importing ".js" files that are
actually ".ts" files unlike tsc, which is fine with it.
See kulshekhar/ts-jest#1057
In order to support ESM, files need to be imported and exported with file extenstions.
While Jest seems to support ESM via hack config, we are using ts-jest, so in order to make file extensions to work, we need a moduleNameMapper configuration that allows to remove the file extension, so jest can resolve properly.
Related links:
kulshekhar/ts-jest#2475
kulshekhar/ts-jest#1057
https://dev.to/antongolub/ts-and-ts-jest-meet-type-module-5chc
In order to support ESM, files need to be imported and exported with file extenstions.
While Jest seems to support ESM via hack config, we are using ts-jest, so in order to make file extensions to work, we need a moduleNameMapper configuration that allows to remove the file extension, so jest can resolve properly.
Related links:
kulshekhar/ts-jest#2475
kulshekhar/ts-jest#1057
https://dev.to/antongolub/ts-and-ts-jest-meet-type-module-5chc
In order to support ESM, files need to be imported and exported with file extenstions.
While Jest seems to support ESM via hack config, we are using ts-jest, so in order to make file extensions to work, we need a moduleNameMapper configuration that allows to remove the file extension, so jest can resolve properly.
Related links:
kulshekhar/ts-jest#2475
kulshekhar/ts-jest#1057
https://dev.to/antongolub/ts-and-ts-jest-meet-type-module-5chc
In order to support ESM, files need to be imported and exported with file extenstions.
While Jest seems to support ESM via hack config, we are using ts-jest, so in order to make file extensions to work, we need a moduleNameMapper configuration that allows to remove the file extension, so jest can resolve properly.
Related links:
kulshekhar/ts-jest#2475
kulshekhar/ts-jest#1057
https://dev.to/antongolub/ts-and-ts-jest-meet-type-module-5chc
Adds instructions for how to resolve "Cannot find module ./<module name>.js
from ./<module_name>.spec.ts
"
#3219
I got things working with .js
extensions in typescript imports with the following jest.config.js:
/** @type {import('@jest/types').Config.ProjectConfig} */
const config = {
transform: {
"\\.[jt]sx?$": "ts-jest",
"globals": {
"ts-jest": {
"useESM": true
moduleNameMapper: {
"(.+)\\.js": "$1"
extensionsToTreatAsEsm: [".ts"],
export default config;
VitorLuizC, jericirenej, LabEG, AxelEriksson0, jmeischner, ascott18, simonhammes, Serzhul, samijaber, cef62, and 56 more reacted with thumbs up emoji
GA1, langarus, oleglegun, trusktr, nicholasgalante1997, vitorbribas, dabigjoe6, jtlapp, alanbacon, creativesully, and 3 more reacted with hooray emoji
fibo, wtto00, KhYulian, daniloarcidiacono, GA1, langarus, alanbacon, Gioee, phynam, and marcelinorc reacted with rocket emoji
All reactions
I noticed our unit tests were failing because Jest couldn't
resolve files with a .js extension. This is a known issue
documented here [1] and this PR updates our jest config
to fix it.
1: kulshekhar/ts-jest#1057
TEST=auto
Ran unit tests.
I noticed our unit tests were failing because Jest couldn't
resolve files with a .js extension. This is a known issue
documented here [1] and this PR updates our jest config
to fix it.
1: kulshekhar/ts-jest#1057
TEST=auto
Ran unit tests.
* npm run release && npm run fmt
* Update packages/yext-sites-scripts/package.json
Co-authored-by: Justin Mancusi <[email protected]>
Co-authored-by: Justin Mancusi <[email protected]>
When importing a cross-referenced file, a line like this is generated:
import { MyMessage } from '../myother/myother'
.. assuming there's a proto at ../myother/myother.proto
But if we add the suffix '.pb.ts' to the generated files:
import { MyMessage } from '../myother/myother.pb'
Is not recognized as a TypeScript import by tsc because of the .pb suffix.
To fix this, we can just add .js, and the TypeScript compiler recognizes that we actually mean the .ts file:
import { MyMessage } from '../myother/myother.pb.js'
Fixes stephenh#601
Fix the resolution in ts-jest with the jest-ts-webcompat-resolver:
See: kulshekhar/ts-jest#1057 (comment)
Signed-off-by: Christian Stewart <[email protected]>
When importing a cross-referenced file, a line like this is generated:
import { MyMessage } from '../myother/myother'
.. assuming there's a proto at ../myother/myother.proto
But if we add the suffix '.pb.ts' to the generated files:
import { MyMessage } from '../myother/myother.pb'
Is not recognized as a TypeScript import by tsc because of the .pb suffix.
To fix this, we can just add .js, and the TypeScript compiler recognizes that we actually mean the .ts file:
import { MyMessage } from '../myother/myother.pb.js'
Fixes stephenh#601
Fix the resolution in ts-jest with the jest-ts-webcompat-resolver:
See: kulshekhar/ts-jest#1057 (comment)
Signed-off-by: Christian Stewart <[email protected]>
When importing a cross-referenced file, a line like this is generated:
import { MyMessage } from '../myother/myother'
.. assuming there's a proto at ../myother/myother.proto
But if we add the suffix '.pb.ts' to the generated files:
import { MyMessage } from '../myother/myother.pb'
Is not recognized as a TypeScript import by tsc because of the .pb suffix.
To fix this, we can just add .js, and the TypeScript compiler recognizes that we actually mean the .ts file:
import { MyMessage } from '../myother/myother.pb.js'
Fixes stephenh#601
Fix the resolution in ts-jest with the jest-ts-webcompat-resolver:
See: kulshekhar/ts-jest#1057 (comment)
Signed-off-by: Christian Stewart <[email protected]>
Related issue at Storybook:
storybookjs/storybook#15962
Both Jest and Storybook need to build code from sources, but might encounter index.ts "barrel files" exporting files using .js extension when a librairy is meant to be exposed as ESM.
When not using
ts-jest
, this issue could help:
swc-project/jest#64 (comment)
Hello,
I want to share my config as well as far as the
solution
from above didn't work out for me.
I'm using nodejs v18.12.0, jest 29.2.2 and ts-jest 29.0.3, typescript 4.8.4.
I have
"type": "module",
in my
package.json
.
My
tsconfig.json
looks like this:
"compilerOptions"
: {
"outDir"
:
"
./lib/
"
,
"inlineSourceMap"
:
true
,
"target"
:
"
es2022
"
,
"lib"
: [
"
ES2022
"
],
"module"
:
"
ESNext
"
,
"moduleResolution"
:
"
NodeNext
"
,
"esModuleInterop"
:
true
,
// "allowSyntheticDefaultImports": true, // this one along with allowJs are not required in my project
"noImplicitAny"
:
true
,
"strict"
:
true
,
"forceConsistentCasingInFileNames"
:
true
"include"
: [
"
./test/**/*.ts
"
,
"
./src/**/*.ts
"
]
Jest config file
jest.config.cjs
looks like this:
/** @type {import('ts-jest').JestConfigWithTsJest} */
const jestConfig = {
testMatch: ['<rootDir>/test/?(*.)+(spec|test).ts'],
transform: { '\\.[jt]s?$': ['ts-jest', { tsconfig: { allowJs: true } }] }, // allowJs is required for get-port
transformIgnorePatterns: ['node_modules/(?!get-port/.*)'], // you might need to ignore some packages
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.[jt]s$': '$1',
// ...
module.exports = jestConfig
larsenwork, joeskeen, borisdiakur, SmartArray, taorepoara, Greygooo, JungleDruid, and lanhhoang reacted with thumbs up emoji
dabigjoe6, jtlapp, samydevv, and Neversate reacted with heart emoji
All reactions
This comment
started me on the right path, but for my project, the solution is simpler: make sure the
moduleNameMapper
only maps the '.ts' files that you refer to as
.js
in your imports elsewhere
. In my case, those were the
./[filename].ts
files, which are imported as
./[filename].js
but for jest need to be imported as
./[filename]
.
In
jest.config.json syntax
:
"moduleNameMapper": {
"^(\\.\\/.+)\\.js$": "$1"
I tweaked the above version to allow ../
relative imports also:
"moduleNameMapper: {
"^(\.\.?\/.+)\.jsx?$": "$1"
@justrhysism you must double the backslashes:
"moduleNameMapper: {
"^(\\.\\.?\\/.+)\\.jsx?$": "$1"
oleglegun, ChrisLFieldsII, magiclen, tonisives, kloben, robvanderleek, taorepoara, thejohnfreeman, dreamingkills, tran-simon, and 7 more reacted with thumbs up emoji
qoomon reacted with rocket emoji
All reactions
custom resolver doesn't belong to ts-jest
.
@ahnpnl In my very humble opinion, if someone gives a Jest plugin for people to write .test.ts
files instead of .test.js
files, but it doesn't work with default functionality of TypeScript, then that's the plugin author's problem, not Jest's.
.js
extensions for module specifiers are a default out-of-the-box feature of TypeScript.
`"type": "module"` in `package.json` necessitates including the `.js`
file extension in file `import` statements. Details in [TypeScript docs:
`type` in
`package.json`](https://www.typescriptlang.org/docs/handbook/esm-node.html#type-in-packagejson-and-new-extensions).
Then, to fix `npm test`, I added the `moduleNameMapper` from
kulshekhar/ts-jest#1057 (comment)
(fixing the quotes).
the "cannot find module *.js from *.spec.ts" is a known Typescript
+ Node + Jest combination issue.
Refer the following for more info:
https://stackoverflow.com/questions/73735202/typescript-jest-imports-with-js-extension-cause-error-cannot-find-module
kulshekhar/ts-jest#1057 (comment)
the "cannot find module *.js from *.spec.ts" is a known Typescript
+ Node + Jest combination issue.
Refer the following for more info:
https://stackoverflow.com/questions/73735202/typescript-jest-imports-with-js-extension-cause-error-cannot-find-module
kulshekhar/ts-jest#1057 (comment)
As part of looking into #887 I
ran into a ton of difficulty getting `ts-jest` to work with ESM, with
one of the main issues being related to importing `./utils.js` style
files.
This seems to be an issue with `ts-jest` (or at least the interplay
between `ts-jest` and Jest) and from what I could tell in the issues and
code, this isn't solved yet. The solution to the underlying issue was "fixed"
by suggesting the use of a custom resolver, which is not part of the main
`ts-jest` package (see kulshekhar/ts-jest#1057).
While checking types in the test code is useful, it's not that important
since the actual code is type checked separately (both with the linter
and the compilation steps), and so instead of trying to fix `ts-jest`
and use the custom resolver, I opt for using `@swc/jest` which instead
removes the types entirely.
As part of looking into #887 I
ran into a ton of difficulty getting `ts-jest` to work with ESM, with
one of the main issues being related to importing `./utils.js` style
files.
This seems to be an issue with TypeScript + Jest combination when using
ESM, and the `ts-jest` preset hasn't "fixed" this yet (by doing
something like the `moduleNameMapper` approach mentioned in [comments like this]
(kulshekhar/ts-jest#1057 (comment)). Has
there not been any PR from someone?
In any case, it's a bit frustrating that there wasn't a mention of this
in the troubleshooting docs as the issue above was pretty well
trafficked and commented on, and while there was a PR, it was closed and
there was no follow up. What's worse is that this issue has been known
for at least 4 years. There really should have been a troubleshooting
section added here even without a community contributed PR, and so I
don't have faith that either an additon to the preset or a mention in
the troubleshooting docs will happen anytime soon, at least before I
want to get Stylelint 16 in main.
While checking types in the test code is useful, it's not that important
since the actual code is type checked separately (both with the linter
and the compilation steps), and so instead of trying to fix `ts-jest`
and use the custom resolver, I opt for using `@swc/jest` which instead
removes the types entirely when compiling TS to JS. It has the added
benefit of being simpler, being only used in the `transform` config
rather than as a preset.
If at some point type checking the tests becomes important the
lint:types task can be updated to check test code too.
As part of looking into #887 I
ran into a ton of difficulty getting `ts-jest` to work with ESM, with
one of the main issues being related to importing `./utils.js` style
files.
This seems to be an issue with the combination of TypeScript + Jest when using
ESM, and the `ts-jest` preset hasn't "fixed" this yet (by doing
something like the `moduleNameMapper` approach mentioned in [comments like this]
(kulshekhar/ts-jest#1057 (comment)). Has
there not been any PR from someone?
In any case, it's a bit frustrating that there wasn't a mention of this
in the troubleshooting docs as the issue above was pretty well
trafficked and commented on, and while there was a PR, it was closed and
there was no follow up. What's worse is that this issue has been known
for at least 4 years. There really should have been a troubleshooting
section added here even without a community contributed PR, and so I
don't have faith that either an additon to the preset or a mention in
the troubleshooting docs will happen anytime soon, at least before I
want to get Stylelint 16 in main.
While checking types in the test code is useful, it's not that important
since the actual code is type checked separately (both with the linter
and the compilation steps), and so instead of trying to fix `ts-jest`
and use the custom resolver, I opt for using `@swc/jest` which instead
removes the types entirely when compiling TS to JS. It has the added
benefit of being simpler, being only used in the `transform` config
rather than as a preset.
If at some point type checking the tests becomes important the
lint:types task can be updated to check test code too.
As part of looking into #887 I
ran into a ton of difficulty getting `ts-jest` to work with ESM, with
one of the main issues being related to importing `./utils.js` style
files.
This seems to be an issue with the combination of TypeScript + Jest when using
ESM, and the `ts-jest` preset hasn't "fixed" this yet (by doing
something like the `moduleNameMapper` approach mentioned in
[comments like this](kulshekhar/ts-jest#1057 (comment)). Has
there not been any PR from someone?
In any case, it's a bit frustrating that there wasn't a mention of this
in the troubleshooting docs as the issue above was pretty well
trafficked and commented on, and while there was a PR, it was closed and
there was no follow up. What's worse is that this issue has been known
for at least 4 years. There really should have been a troubleshooting
section added here even without a community contributed PR, and so I
don't have faith that either an additon to the preset or a mention in
the troubleshooting docs will happen anytime soon, at least before I
want to get Stylelint 16 in main.
While checking types in the test code is useful, it's not that important
since the actual code is type checked separately (both with the linter
and the compilation steps), and so instead of trying to fix `ts-jest`
and use the custom resolver, I opt for using `@swc/jest` which instead
removes the types entirely when compiling TS to JS. It has the added
benefit of being simpler, being only used in the `transform` config
rather than as a preset.
If at some point type checking the tests becomes important the
lint:types task can be updated to check test code too.
As part of looking into #887 I
ran into a ton of difficulty getting `ts-jest` to work with ESM, with
one of the main issues being related to importing `./utils.js` style
files.
This seems to be an issue with the combination of TypeScript + Jest when using
ESM, and the `ts-jest` preset hasn't "fixed" this yet (by doing
something like the `moduleNameMapper` approach mentioned in
[comments like this](kulshekhar/ts-jest#1057 (comment)). Has
there not been any PR from someone?
In any case, it's a bit frustrating that there wasn't a mention of this
in the troubleshooting docs as the issue above was pretty well
trafficked and commented on, and while there was a PR, it was closed and
there was no follow up. What's worse is that this issue has been known
for at least 4 years. There really should have been a troubleshooting
section added here even without a community contributed PR, and so I
don't have faith that either an additon to the preset or a mention in
the troubleshooting docs will happen anytime soon, at least before I
want to get Stylelint 16 in main.
While checking types in the test code is useful, it's not that important
since the actual code is type checked separately (both with the linter
and the compilation steps), and since `@swc/jest` is simpler and
hopefully doesn't have the above frustration factor, I've decided to
migrate from `ts-jest` to `@swc/jest`.
If at some point type checking the tests becomes important the
lint:types task can be updated to check test code too.
I got things working with .js
extensions in typescript imports with the following jest.config.js:
/** @type {import('@jest/types').Config.ProjectConfig} */
const config = {
transform: {
"\\.[jt]sx?$": "ts-jest",
"globals": {
"ts-jest": {
"useESM": true
moduleNameMapper: {
"(.+)\\.js": "$1"
extensionsToTreatAsEsm: [".ts"],
export default config;
Since the global ts-jest config is considered as deprecated.
I adjust the good tips by this way
"transform": {
"\\.[jt]s?$": [
"ts-jest",
"useESM": true
"moduleNameMapper": {
"(.+)\\.js": "$1"
"extensionsToTreatAsEsm": [
".ts"
mgrybyk, algebra2boy, paralin, qoomon, dsitum, CameronAM, and peferb-bonnier reacted with thumbs up emoji
peferb-bonnier reacted with hooray emoji
All reactions
The below works for me in my Node.js backend project. The rule applies to relative imports starting with a period (.) or double periods (..)
kulshekhar/ts-jest#1057
TLDR: The Jest resolver needs a little extra information/tweak to the
config so that it can correctly handle the .js imports.
Specifically this comment provided the solution which I made here:
kulshekhar/ts-jest#1057 (comment)
Fixes #3254
Signed-off-by: Peter Somogyvari <[email protected]>