TS-JEST Mongoose/MongoDB incompatibility with ESM - node.js

I am trying to get Node Express/Typescript app that uses Mongoose (which drags in Mongodb) to work with Jest. I know what the error is, I just can't find the correct configuration to get jest and mongodb to play nicely.
No matter what I try I either get:
chart-review-server2.0/node_modules/mongodb/src/bson.ts:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import type {
^^^^^^
SyntaxError: Cannot use import statement outside a module
or if I try to exclude it from the config using transformIgnorePatterns in my jest.config.js configuration like this: transformIgnorePatterns: ['node_modules/(?!(mongodb))'], I get:
RangeError: Maximum call stack size exceeded
at Object.get [as ObjectId] (node_modules/mongodb/src/bson.ts:38:3)
at Object.get [as ObjectId] (node_modules/mongodb/src/bson.ts:38:3)...
My jest.config.js file looks like this:
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
transformIgnorePatterns: [`node_modules/(?!(mongodb))`],
transform: {
'^.+\\.ts?$': 'ts-jest'
},
moduleDirectories: [ "node_modules", "src", "test"],
verbose: true,
testMatch: ["<rootDir>/test/*(*.)+(test).+(ts)"],
setupFiles: [
'dotenv/config'
],
};
my tsconfig.json looks like this:
{
"compilerOptions": {
"lib": [
"es6"
],
"module": "commonjs",
"target": "es5",
"rootDirs": [
"./src"
],
"outDir": "./dist",
"baseUrl": "./src",
"moduleResolution": "node",
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"allowJs": true,
"downlevelIteration": true,
"isolatedModules": false,
"noEmit": true
},
"include": [
"src/**/*.ts",
"test/**/*.ts"
],
"exclude": [
"node_modules"
],
"types": [
"node"
],
"typeRoots": [
"node_modules/#types"
]
}
Thanks in advance for any replies, and for reading this.

Commenting out moduleDirectories on jest.config.js solved the issue for me. All credits to #jimmythecode, see his answer.

Related

How to use paths with ts-node?

I have this project structure:
How to configure tsconfig.json for using paths like #app/, #server/.
I try this:
{
"compilerOptions": {
"module": "CommonJS",
"target": "es5",
"lib": [
"esnext",
"dom"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": false,
"baseUrl": "..",
"paths": {
"#app/*": [
"app/*"
],
"#server/*": [
"server/*"
]
}
},
"include": [
"."
]
}
Same config works with webpack and ts-loader, but when i run npx ts-node server/index.ts i got error:
npx ts-node server/index.ts
Error: Cannot find module '#server/a'
server/index.ts :
import a from '#server/a'
console.log('This is index.ts')
a()
Your config works for webpack because you run webpack from the project root. It does not work for server.ts because the path is relative to its directory. Try:
"paths": {
"#app/*": [
"../app/*"
],
"#server/*": [
"../server/*"
]
}
If you need to do it for both, you need two different tsconfig.json - one in the root and one in app or server.
Take a look at my project: https://github.com/mmomtchev/rlayers
It uses this feature a lot.

serverless framework not recognizing tsconfig's paths

I'm trying to deploy my Node.js app to Lambda using Serverless framework, however, my Node code uses paths from tsconfig.json for referencing imports but the Serverless deploy process fails. How do you wire up serverless.yml to acknowledge and use paths defined in tsconfig.json?
I've installed serverless-plugin-typescript, but it does not seem to recognize paths from tsconfig.
serverless.yml
service:
name: app-name
custom:
webpack:
webpackConfig: ./webpack.config.js
includeModules: true
plugins:
- serverless-webpack
- serverless-plugin-typescript
...
tsconfig.ts
{
"compileOnSave": true,
"compilerOptions": {
"lib": [
"es2017"
],
"baseUrl": "./src",
"declaration": true,
"downlevelIteration": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"module": "commonjs",
"moduleResolution": "node",
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "./dist",
"paths": {
"#config/*": [
"config/*"
],
"#core/*": [
"core/*"
],
"#infra/*": [
"infra/*"
],
"#modules/*": [
"modules/*"
],
"#shared/*": [
"shared/*"
]
},
"preserveConstEnums": true,
"removeComments": true,
"rootDir": "./src",
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"strictNullChecks": false,
"target": "es2017",
"typeRoots": [
"node_modules/#types"
],
"types": [
"node"
]
},
"include": [
"./**/*.ts"
],
"exclude": [
"node_modules/**/*",
".serverless/**/*",
".webpack/**/*",
"_warmup/**/*",
".vscode/**/*"
]
}
I found an answer. Turns out you need to install tsconfig-paths-webpack-plugin. Then in webpack.config.js you add the following:
npm install --save-dev tsconfig-paths-webpack-plugin
inside webpack.config.js:
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
module.exports = {
...
resolve: {
plugins: [new TsconfigPathsPlugin({ configFile: "./tsconfig.json" })]
},
...
};
NOTE: be sure to use the plugins inside the resolve section. There is a plugins a the root, however, TsconfigPathsPlugin only works in resolve/plugins.
I hope this helps you if you experience this same issue.

Angular 7: adding local module with npm link

I've created a package with a module outside of folder with an appication that should contain the module to test it. Then I've added package with npm link #scope/module-name. After that I've added paths to root tsconfig.json.
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"module": "es2015",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "es5",
"typeRoots": [
"node_modules/#types"
],
"lib": [
"es2018",
"dom"
],
"paths": {
"#scope/module-name": [
"node_modules/#scope/module-name"
],
"#scope/module-name/*": [
"node_modules/#scope/module-name/*"
]
}
}
}
I've also added package to include in tsconfig.app.json
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"types": []
},
"include": [
"**/*.ts",
"../node_modules/#scope/**/*.ts",
],
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}
And yes, I've added "preserveSymlinks": true in angular.json as it's said in similar questions on SO.
In app.module.ts I'm doing
import { DispRegistryModule } from "#scope/module-name/public_api.d.ts";
But still I'm gettig an error
ERROR in ./node_modules/#scope/module-name/public_api.d.ts Module
build failed (from ./node_modules/#ngtools/webpack/src/index.js):
Error:
D:\internal\test-app\node_modules#scope\module-name\public_api.d.ts
is missing from the TypeScript compilation. Please make sure it is in
your tsconfig via the 'files' or 'include' property.
How can I fix the error?

can't transform a folder inside node_modules with ts-jest

I'm writing tests in typescript, and i've got private dependencies in node_modules/#my-modules folder. I'm using ts-jest compiler and jest still complains about esnext modules in node_modules folder.
package versions:
"#types/jest": "^23.3.12",
"jest": "^23.6.0",
"ts-jest": "^23.10.5",
tsconfig.json:
{
"compilerOptions": {
"baseUrl": "./src",
"outDir": "build/dist",
"module": "commonjs",
"target": "es5",
"lib": ["es5", "es6", "dom", "esnext"],
"sourceMap": true,
"allowJs": true,
"jsx": "react",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": false,
"strict": false,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
}
}
jest.config.js:
module.exports = {
globals: {
"ts-jest": {
diagnostics: true,
tsConfig: "<rootDir>/tsconfig.json",
},
},
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json"],
preset: "ts-jest",
roots: ["<rootDir>/src/"],
setupTestFrameworkScriptFile: "<rootDir>/src/setupEnzyme.ts",
snapshotSerializers: ["enzyme-to-json/serializer"],
testEnvironment: "jest-environment-jsdom",
transformIgnorePatterns: [
"node_modules/(?!(#my-modules)/)",
]
};
exact error when running jest:
Details:
/sites/frontend/node_modules/#my-modules/ui-components/.dist/src/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){export { default as Calendar } from './components/calendar';
^^^^^^
SyntaxError: Unexpected token export
What is the proper way to transpile files in #my-modules for jest?
The config that works for me right now
package versions:
"#types/jest": "^24.0.17",
"jest": "^24.8.0",
"ts-jest": "^23.10.5",
tsconfig.json:
{
"compilerOptions": {
"baseUrl": ".",
"outDir": "build/dist",
"lib": ["es5", "es6", "dom", "esnext"],
"module": "esnext",
"moduleResolution": "node",
"target": "es5",
"sourceMap": true,
"allowJs": true,
"jsx": "react",
"rootDir": "src",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
},
"exclude": [
"node_modules",
"build",
"dist"
]
}
jest.config.js:
module.exports = {
globals: {
"ts-jest": {
diagnostics: true,
tsConfig: "<rootDir>/tsconfig.json",
},
},
moduleDirectories: [
"node_modules",
"utils",
__dirname,
],
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json"],
moduleNameMapper: {
"\\.(css|less)$": "identity-obj-proxy",
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
"<rootDir>/config/jest/fileMock.js",
},
preset: "ts-jest",
roots: ["<rootDir>/src/"],
setupFilesAfterEnv: ["<rootDir>/config/jest/setupJest.ts"],
snapshotSerializers: ["enzyme-to-json/serializer"],
testEnvironment: "jest-environment-jsdom",
transform: {
"^.+\\.jsx?$": "babel-jest",
"^.+\\.tsx?$": "ts-jest",
},
transformIgnorePatterns: [
"node_modules/(?!(#my-modules)/)",
],
};
config/jest/fileMock.js:
module.exports = 'test-file-stub';
I followed the tuto here and worked like a charm
npm install --save-dev jest typescript ts-jest #types/jest
npx ts-jest config:init
Another solution for me was to update the jest.config.ts so it contains the following setting
transform: {
//"^.+\\.(ts|tsx)$": "ts-jest",
},

Typescript: Unexpected token import

Just started working with typescript. Unfortunately when I try to build for production it fails.
Firstly I run
tsc
This passes without any error, but when I try to run the build file I get import errors
node build/index.js
The error I get is below:
[0] (function (exports, require, module, __filename, __dirname) { import {
[0] ^^^^^^
[0]
[0] SyntaxError: Unexpected token import
[0] at createScript (vm.js:80:10)
[0] at Object.runInThisContext (vm.js:139:10)
Below is my tsconfig
{
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
],
"compilerOptions": {
"lib": [
"es5",
"es6",
],
"pretty": true,
"target": "es5",
"module": "commonjs",
"outDir": "./build",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true
}
}
I am using node v8.9.3
If you use TypeORM there can be a problem with your ormconfig. Your configuration file probably contains path like src/entities/*.ts in the entity section. So it causes requiring *.ts files from your src folder, not from dist folder.
When working with NodeJs, your tsconfig.json should look like this:
{
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
],
"compilerOptions": {
"lib": ["es6"], // No need for "es5" if you have "es6"
"types": ["node"], // When you code for nodejs
"target": "es6", // NodeJs v8.9.3 supports most of the es6 features
"pretty": true,
"module": "commonjs",
"outDir": "./build",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true
}
}

Resources