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

I have created a package named @packagetest. When imported to a new, empty React typescript app works

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 monJS 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 piled an ES modules package version, it causes Jest to throw

export * from './mon';
^^^^^^
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",
  "pilerOptions": { "outDir": "./dist", "rootDir": "./src", "posite": true },
  "references": [],
  "include": ["src"],
  "exclude": ["src/**/*.spec.*", "dist", "node_modules"]
}
/* tsconfig.packages.json */
{
  "extends": "../tsconfig.base.json",
  "pilerOptions": {
    "module": "es2020",
    "lib": ["es5", "es2015", "es2020", "dom"]
  }
}
/* tsconfig.base.json */
{
  "pileOnSave": false,
  "pilerOptions": {
    "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 */
{
  "pilerOptions": {
    "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 monJS, but no effect.

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 monJS 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 piled an ES modules package version, it causes Jest to throw

export * from './mon';
^^^^^^
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",
  "pilerOptions": { "outDir": "./dist", "rootDir": "./src", "posite": true },
  "references": [],
  "include": ["src"],
  "exclude": ["src/**/*.spec.*", "dist", "node_modules"]
}
/* tsconfig.packages.json */
{
  "extends": "../tsconfig.base.json",
  "pilerOptions": {
    "module": "es2020",
    "lib": ["es5", "es2015", "es2020", "dom"]
  }
}
/* tsconfig.base.json */
{
  "pileOnSave": false,
  "pilerOptions": {
    "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 */
{
  "pilerOptions": {
    "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 monJS, but no effect.

Share Improve this question edited Apr 8, 2021 at 13:50 Triti asked Apr 8, 2021 at 9:47 TritiTriti 1511 silver badge8 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 4

The problem was way more plex 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-monjs as dev dependencies.
  • Register the plugin in Babel's config:
env: {
    test: {
      plugins: ['@babel/plugin-transform-modules-monjs'],
    },
}
  • Register required transformIgnorePatterns in Jest config
  • Add this to the transform section in Jest config: "^.+\\.js$": "babel-jest"

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744327794a4568735.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信