Jest: Cannot read property of undefined when importing from own package - javascript

I have created a package named #package/test. When imported to a new, empty React typescript app works perfectly. Problems start in Jest tests suites.
The commonJS package version cause Jest to throw:
Test suite failed to run. TypeError:Cannot read property 'getSelectors' of undefined
import { Test } from `#package/test
const selectors = Test.getSelectors(...); //error here indicating that Test is undefined
When I compiled an ES modules package version, it causes Jest to throw
export * from './common';
^^^^^^
SyntaxError: Unexpected token export
which is the first line of my src/index.ts inside my package.
I have tested many solutions e.g.:
Defining transformIgnorePatterns for Jest
Searching for circular dependencies using eslint plugins and Madge
Tested on Node.js versions: 10.20.0, 12.21.0, 15.12.0
Tested on typescript versions: 3.7.5, 4.1.2
Some details about the package:
/* package.json */
{
"name": "#package/test",
"version": "2.4.0",
"main": "./dist/index.js",
"scripts": {
"build": "tsc -b ./tsconfig.package.json"
},
"typings": "./dist/index.d.ts",
"files": [
"dist"
],
"dependencies": {...},
"peerDependencies": {...},
"sideEffects": "false"
}
/* tsconfig.package.json */
{
"extends": "../../tsconfig.packages.json",
"compilerOptions": { "outDir": "./dist", "rootDir": "./src", "composite": true },
"references": [],
"include": ["src"],
"exclude": ["src/**/*.spec.*", "dist", "node_modules"]
}
/* tsconfig.packages.json */
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"module": "es2020",
"lib": ["es5", "es2015", "es2020", "dom"]
}
}
/* tsconfig.base.json */
{
"compileOnSave": false,
"compilerOptions": {
"declaration": true,
"sourceMap": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"downlevelIteration": true,
"skipLibCheck": true,
"jsx": "react",
"strict": true,
"target": "es5"
}
}
How Test is exported:
import * as actions from './actions';
import reducer, { Action, RootState} from './reducer';
import getSelectors from './getSelectors';
export const Test = {
actions,
reducer,
getSelectors,
};
export { Action, RootState};
export * from './types';
export * from './helpers';
How getSelectors is exported:
export default function getSelectors<S>(selectNavigation: Selector<S, RootState>) {
const getInitialized = createSelector(selectNavigation, (s) => s.initialized);
...
return { getInitialized, ... };
}
React test application details
/* package.json */
{
"name": "jest-verify",
"version": "0.1.0",
"private": true,
"dependencies": {
"#package/test": "2.4.0",
"#testing-library/jest-dom": "^5.11.4",
"#testing-library/react": "^11.1.0",
"#testing-library/user-event": "^12.1.10",
"#types/jest": "^26.0.15",
"#types/node": "^12.0.0",
"#types/react": "^17.0.0",
"#types/react-dom": "^17.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"typescript": "^4.1.2",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
}
/* tsconfig.json */
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}
EDIT:
I managed to make it work in my test React app with transformIgnorePatterns, but unfortunately it does not work in my Angular 1.6 (webpack, babel) app. Added also some babel plugins to transform package into commonJS, but no effect.

The problem was way more complex than it appeared.
Extra issue:
Jest was not respecting Babel config in json file. I had to transform it to js.
Solution no. 1:
Install #babel/preset-env as a dev dependency.
Register it as a preset in Babel's config:
env: {
test: {
presets: ['#babel/preset-env'],
},
}
Register required transformIgnorePatterns in Jest config
Add this to the transform section in Jest config: "^.+\\.js$": "babel-jest"
Solutions no. 2:
Install babel-jest and #babel/plugin-transform-modules-commonjs as dev dependencies.
Register the plugin in Babel's config:
env: {
test: {
plugins: ['#babel/plugin-transform-modules-commonjs'],
},
}
Register required transformIgnorePatterns in Jest config
Add this to the transform section in Jest config: "^.+\\.js$": "babel-jest"

Related

Cannot get the absolute paths working in typescript nodejs project

I am trying to setup a simple typescript, node environment with absolute paths instead of relative paths.
I followed the video here: but can't get the absolute imports to resolve properly when I run npm run start:dev. The VSCode intellisense is able to resolve the absolute import paths fine, but when I compile, I get compilation error.
Note: relative paths are compiling and working fine. But absolute paths are giving compilation error.
Here's my .nvmrc:
v16.15.1
Here is my code structure:
Here's my simple code:
src/index.ts:
import add from '#src/math/add';
console.log(add(2, 1));
Here #src/math/add is giving compilation error. ./math/add compiles fine.
src/math/add.ts:
import force from '#src/science/physics';
const add = (a: number, b: number): number => {
console.log(`force:${force(5, 3)}`);
return a + b;
};
export default add;
Here #src/science/physics is giving compilation error. ../science/physics compiles fine.
src/physics/force.ts:
const force = (mass: number, accelaration: number): number => mass * accelaration;
export default force;
Here is my tsconfig.json
{
"ts-node": {
"require": ["tsconfig-paths/register"],
"esm": true,
"experimentalSpecifierResolution": "node"
},
"exclude": ["node_modules", "dist", "coverage"],
"include": ["src"],
"compilerOptions": {
"target": "ES2020",
"lib": ["DOM", "ESNext"],
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
/* JavaScript Support */
"allowJs": true,
/* Emit */
"outDir": "dist",
"removeComments": true,
/* Type Checking */
"strict": true,
"noImplicitAny": true,
/* Modules */
"module": "ES2020",
"moduleResolution": "node",
"rootDir": "." /*meaning wherever is this tsconfig.json file, that is the root directory*/,
"baseUrl": ".",
"paths": {
"#src/*": ["src/*"]
},
/* Interop Constraints */
"isolatedModules": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
/* Completeness */
"skipLibCheck": true
}
}
Here is my package.json:
{
"type": "module",
"name": "express-proj-setup-tut",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"start:dev": "ts-node -r tsconfig-paths/register ./src/index.ts",
"start:prod": "node -r ts-node/register/transpile-only -r tsconfig-paths/register ./dist/src/index.ts",
"build": "tsc"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"#types/node": "^18.7.9",
"#typescript-eslint/eslint-plugin": "^5.33.1",
"#typescript-eslint/parser": "^5.33.1",
"eslint": "^8.22.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.4.2",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "^2.7.1",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.1.0",
"typescript": "^4.7.4"
}
}
Finally, here's the error message in terminal:
I would greatly appreciate if someone can help me out getting the absolute paths working.
thanks
I was unable to solve your issue with your configuration of module in package.json and module in tsconfig.json but if you remove "type": "module" from package.json and change to "module": "CommonJS" in your tsconfig.json you will be able to run "start:dev": "ts-node -r tsconfig-paths/register src/index.ts".
For me output was
force:15
3
Related question: Can't run my Node.js Typescript project TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /app/src/App.ts
Check if your node.js version is higher than 14.6.0
Having ./src folder with ts code, ./dist folder as tsc output folder write following to map ./src as #root global path:
// tsconfig.json
{
"compilerOptions": {
...
"baseUrl": "./src",
"paths": {
"#root/*": [
"./*"
]
}
}
}
// package.json
{
...
"imports": {
"#root/*": "./dist/*"
},
}
Such aliases should start with # symbol.
Useful links:
https://nodejs.org/api/packages.html#subpath-imports
https://www.typescriptlang.org/tsconfig#paths
In your tsconfig.json, you need change
"paths": {
"#src/*": ["src/*"]
},
for this:
"paths": {
"#/*": [
"src/*"
]
},
And in include, you need add all paths that include ts files, like this:
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
I hope that solve that compilation error :-)

Typescript with mocha - Cannot use import statement outside a module

I'm trying to make a simple test to get to know unit tests using mocha.
Folder Structure
node_modules
package.json
package-lock.json
testA.ts
testA.spec.ts
tsconfig.json
tsconfig.json
{
"compilerOptions": {
"target": "ES2019",
"module": "commonjs",
"rootDir": "./",
"moduleResolution": "node",
"allowJs": false,
"declaration": false,
"outDir": "./dist",
"esModuleInterop": false,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitAny": false,
"noImplicitThis": true,
"alwaysStrict": true,
"skipLibCheck": true
},
"exclude": [
"node_modules"
]
}
package.json
{
"name": "unittest",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"test": "mocha",
"build": "rm -rf dist && tsc"
},
"author": "",
"license": "ISC",
"devDependencies": {
"#types/chai": "^4.2.22",
"#types/jest": "^27.0.3",
"#types/mocha": "^9.0.0",
"#types/sinon": "^10.0.6",
"chai": "^4.3.4",
"mocha": "^9.1.3",
"nyc": "^15.1.0",
"sinon": "^12.0.1",
"typescript": "^4.5.2",
"ts-node": "^10.4.0"
},
"mocha": {
"check-leaks": true,
"globals": [
"crypto"
],
"recursive": true,
"spec": [
"./*.ts"
]
}
}
testA.spec.ts
import * as chai from 'chai'
const expect = chai.expect
describe('First Test', () => {
it('should run the test', () => {
const a = 12
expect(a).to.be.equal(12)
})
})
When I run npm test, I get the follow error.
/home/user/dev/unitTest/node_modules/#babel/core/src/config/files/index-browser.ts:1
import type { Handler } from "gensync";
^^^^^^
SyntaxError: Cannot use import statement outside a module
Tried everything I could find searching on the internet but still unable to solve this one.
I found the solution. Inside package.json I added the require for mocha:
"devDependencies":{...},
"mocha": {
"require": [
"support/ts-node-register.js"
],
ts-node-register.js
const tsNode = require('ts-node');
tsNode.register({
files: true,
});

Require paths are not proper after typescript file was transpiled by babel

Problem
When I run a nodemon with npm run start, I get Error: Cannot find module 'Test', and When I build files with npm run build and run ./dist/index.js, I get the same error.
As you can see, a require path on ./dist/index.js is not recognized properly.
I don't know which configuration have to be changed, so I questioned.
If you know about that, Please reply back to me with your asnwer. Thanks :)
Source Code
./src/index.ts
import Test from 'Test';
const test = new Test();
./src/Test/index.ts
export default class Test {
constructor () {
console.log('Test');
}
}
./dist/index.js
"use strict";
var _Test = _interopRequireDefault(require("Test"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var test = new _Test.default();
./package.json
{
"version": "1.0.0",
"description": "",
"scripts": {
"build": "babel ./src --extensions .ts,.js --out-dir ./dist",
"start": "nodemon ./src --exec babel-node --extensions .ts,.js"
},
"author": "",
"license": "ISC",
"devDependencies": {
"#babel/cli": "^7.0.0-beta.47",
"#babel/core": "^7.0.0-beta.47",
"#babel/node": "^7.0.0-beta.47",
"#babel/plugin-proposal-class-properties": "^7.0.0-beta.47",
"#babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.47",
"#babel/polyfill": "^7.0.0-beta.47",
"#babel/preset-env": "^7.0.0-beta.47",
"#babel/preset-typescript": "^7.0.0-beta.47",
"cross-env": "^5.1.5",
"nodemon": "^1.17.4"
}
}
./tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"baseUrl": ".",
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"lib": ["ES2015", "ES2017", "DOM"],
"noEmit": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"module": "esnext",
"moduleResolution": "node",
"paths": { "*":["node_modules/*", "src/*"] },
"pretty": true,
"strictNullChecks": true,
"target": "es5",
"typeRoots": ["./node_modules/#types"]
}
}
./.babelrc
{
presets: ['#babel/preset-env', '#babel/preset-typescript'],
plugins: ['#babel/plugin-proposal-class-properties', '#babel/plugin-proposal-object-rest-spread']
}
Try import Test from './Test'; in your ./src/index.ts. Because without relative path typescript looks for the global module Test. When you want to use local module you should use relative path to your module.

Unexpected token for private variables in TypeScript 2.9.1

I am currently working with VueJS and TypeScript 2.9.1. I am creating a library and converted it to typescript later on.
When building the lib with vue-cli the typescript linter says the following error message:
WARNING Compiled with 1 warnings 5:57:15 PM
error: Parsing error: Unexpected token
36 |
37 | export default class Graph {
> 38 | private _nodes: GraphNodeList = {}
| ^
39 | private _edges: EdgeList = {}
40 |
41 | layout: Layout | undefined at src/Graph.ts:38:11:
If I delete the 'private' keyword the errors are gone. But I know that the private keyword is allowed in typescript. They also write it like this in the documentation.
Does anyone know why this happens? Would be cool to use private variables in the future.
tslint.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"node",
"jest"
],
"paths": {
"#/*": [
"src/*"
]
},
"lib": [
"es2017",
"es2015",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
Package.json (reduced)
{
...
"scripts": {
"build": "vue-cli-service build --target lib src/main.ts",
"dev": "vue-cli-service build --mode development --name vue-flowy --watch --target lib src/main.ts",
},
"dependencies": {
"d3": "^5.4.0",
"dagre-d3-renderer": "^0.5.8",
"graphlibrary": "^2.2.0",
"vue-class-component": "^6.0.0",
"vue-property-decorator": "^6.0.0"
},
"devDependencies": {
"#types/debug": "^0.0.30",
"#types/jest": "^22.0.1",
"#vue/cli-plugin-e2e-cypress": "^3.0.0-beta.11",
"#vue/cli-plugin-eslint": "^3.0.0-beta.11",
"#vue/cli-plugin-typescript": "^3.0.0-beta.15",
"#vue/cli-plugin-unit-jest": "^3.0.0-beta.11",
"#vue/cli-service": "^3.0.0-beta.11",
"#vue/eslint-config-prettier": "^3.0.0-beta.11",
"#vue/eslint-config-typescript": "^3.0.0-beta.11",
"#vue/test-utils": "^1.0.0-beta.16",
"debug": "^3.1.0",
"jest": "^22.4.3",
"node-sass": "^4.9.0",
"prettier-eslint-cli": "^4.7.1",
"sass-loader": "^7.0.1",
"ts-jest": "^22.4.6",
"typescript": "^2.8.3",
"vue": "^2.5.16",
"vue-eslint-parser": "^2.0.3"
},
"module": "dist/vue-flowy.es.js",
"repository": {
"type": "git",
"url": "git+https://github.com/Patcher56/vue-flowy.git"
},
"types": "types/index.d.ts",
"files": [
"dist",
"src"
],
"main": "dist/vue-flowy.umd.js",
...
"peerDependencies": {
"vue": "^2.5.16"
},
...
}
vue.config.js
module.exports = {
css: {
extract: false
}
}
build/index.ts
'use strict'
// Template version: 1.2.7
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
module.exports = {
dev: {
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
host: 'localhost',
port: 8080,
autoOpenBrowser: true,
errorOverlay: true,
notifyOnErrors: true,
poll: false,
useEslint: true,
showEslintErrorsInOverlay: true,
devtool: '#source-map',
cacheBusting: true,
cssSourceMap: false
},
bundle: {
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/',
productionSourceMap: false,
devtool: '#source-map',
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
bundleAnalyzerReport: process.env.npm_config_report
},
docs: {
index: path.resolve(__dirname, '../docs/index.html'),
assetsRoot: path.resolve(__dirname, '../docs'),
assetsPublicPath: '',
devtool: '#source-map',
productionSourceMap: false
}
}
Link to whole Repository:
https://github.com/Patcher56/vue-flowy/tree/02c6861e58ffe9ed2f38282e457e7524b8f4cbe8
You can either stick to conventions that says that private variables shouldn't have a leading underscore, or, if you insist on using it, put this in your tslint.json
"variable-name": [true, "allow-leading-underscore"]
Sidenote:
I don't find a explicit vue styleguide for typescript, but the angular equivalent is found here: Angular styleguide
I cleaned up my code a lot and removed some unused dependencies.
I also cleaned up my tslint.json. The problem is gone now.
I think the problem was that there were too many dependencies blocking each other.
Sorry for the time invested by everyone answered this question.

undefined is not a function(evaluating properties[typeof Symbol === "function"?Symbol.iterator:"##iterator"]()') React Native

It used to work well but this error suddenly occurred after updating some project dependencies. It comes from a component that render slate.js object (I'm not rendering the editor but the text). I read that this error can be solved by updating babel-preset-react-native, but mine is already the most updated. I've also import babel-polyfill in the entry file.
I've found quite a few issue like this in github but doesn't find a solution for me.
package.json
{
"name": "mobile",
"version": "0.0.1",
"dependencies": {
"antd-mobile": "^2.1.6",
"babel-polyfill": "^6.26.0",
"react": "16.2.0",
"react-native": "^0.49.0",
"react-native-navigation": "^1.1.375",
"slate": "^0.32.4"
},
"devDependencies": {
"babel-jest": "^22.2.2",
"babel-plugin-import": "^1.6.3",
"babel-preset-react-native": "^4.0.0",
"jest": "^22.2.2",
"react-native-dotenv": "^0.1.1",
"react-test-renderer": "^16.2.0"
},
"jest": {
"preset": "react-native"
}
}
{
"presets": ["react-native","react-native-dotenv"],
"plugins": [["import", { "libraryName": "antd-mobile" }]]
}
I use typescript for the app, here's the tsconfig.json
{
"compilerOptions": {
"module": "es2015",
"target": "es2015",
"moduleResolution": "node",
"outDir": "./src",
"experimentalDecorators": true,
"noLib": false,
"declaration": false,
"emitDecoratorMetadata": true,
"lib": ["es6", "dom"],
"types": ["system","node"],
"jsx": "react"
},
"exclude": [
"node_modules"
]
}

Categories