javascript - Jest: לא ניתן לקרוא מאפיין של לא מוגדר בעת ייבוא מחבילה שלי


יצרתי חבילה בשם @package/test. כאשר היא מיובאת לאפליקציית React TypeScript חדשה וריקה היא עובדת בצורה מושלמת. הבעיות מתחילות בערכות המבחנים של Jest.

גרסת החבילה commonJS גורמת ל-Jest להתרסק:

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

כאשר אני מכין גרסת חבילת ES modules, זה גורם ל-Jest להתרסק

export * from './common';
^^^^^^
SyntaxError: Unexpected token export

שזו השורה הראשונה של src/index.ts שלי בתוך החבילה שלי.

ניסיתי פתרונות רבים לדוגמה:

  • הגדרת transformIgnorePatterns עבור Jest
  • חיפוש תלות מעגלית באמצעות תוספי eslint ו-Madge
  • נבדק על גרסאות Node.js: 10.20.0, 12.21.0, 15.12.0
  • נבדק על גרסאות TypeScript: 3.7.5, 4.1.2

כמה פרטים על החבילה:

/* 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"
  }
}

איך Test מיוצא:

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';

איך getSelectors מיוצא:

export default function getSelectors<S>(selectNavigation: Selector<S, RootState>) {
  const getInitialized = createSelector(selectNavigation, (s) => s.initialized);
    ...
  return { getInitialized, ... };
}

פרטי אפליקציית הבדיקה של React

/* 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"
  ]
}

עריכה: הצלחתי לגרום לזה לעבוד באפליקציית React שלי לניסיון עם transformIgnorePatterns, אבל למרבה הצער זה לא עובד באפליקציית Angular 1.6 שלי (webpack, babel). הוספתי גם כמה פלאגינים של babel כדי להפוך את החבילה ל-commonJS, אבל ללא השפעה.

תשובה #1

הבעיה הייתה הרבה יותר מורכבת ממה שנראה.

בעיה נוספת:

Jest לא כיבד את הגדרת Babel בקובץ json. נאלצתי להמיר אותו ל-js.

פתרון מס' 1:

  • התקן את @babel/preset-env כתלות לפיתוח.
  • רשום זאת כברירת מחדל בקונפיגורציה של Babel:
env: {
    test: {
      presets: ['@babel/preset-env'],
    },
}
  • יש לרשום את transformIgnorePatterns בקונפיגורציה של Jest
  • הוסף את זה לקטע transform בקונפיגורציית Jest: "^.+\\.js$": "babel-jest"

פתרונות מס' 2:

  • התקן את babel-jest ואת @babel/plugin-transform-modules-commonjs כתלויות פיתוח.
  • רשום את התוסף בקובץ ההגדרות של Babel:
env: {
    test: {
      plugins: ['@babel/plugin-transform-modules-commonjs'],
    },
}
  • יש לרשום את transformIgnorePatterns בהגדרות Jest
  • הוסף את זה לקטע transform בקונפיגורציית Jest: "^.+\\.js$": "babel-jest"