在 nx monorepo 中运行 Jest 时出错:SyntaxError:意外的标记“导出”

Fah*_*qri 10 typescript jestjs nrwl-nx

背景

\n

我有一个使用Nx构建的 monorepo 项目。该存储库包含我的后端项目的几个可重用库。这些包是从多个项目中收集的,以创建可重用的库。

\n

我使用 Jest 创建并运行我的 monorepo 中使用的单元测试。

\n

问题

\n

当我运行 jest 时,在某些测试中,它会抛出有关无法导入 .js 文件的错误export

\n

奇怪的是这些模块有一个 commonjs 版本,我可以在我的其他项目中毫无问题地模拟这些包,而无需 monorepo 结构。但是当我在 monorepo 项目中使用相同的代码时(我想让代码可重用),jest 错误地导入了 ESM 版本的包而不是 CJS 版本。

\n

使用案例:

\n
    \n
  • 我有一个内部使用的 blob 存储库ali-oss
  • \n
  • ali-oss将 CJS 和 ESM 分发到同一个包中,我可以在我的其他项目中毫无问题地模拟它(没有 monorepo)
  • \n
  • 当我将相同的库复制到新的 monorepo 中时,Jest 会抱怨export以下ali-oss源之一中的令牌node_modules
  • \n
\n

为什么 Jest 在 monorepo 与普通 repo 中的行为不同?如何解决这个奇怪的笑话模块分辨率?

\n

文件

\n

tsconfig.json:

\n
{\n  "compilerOptions": {\n    "module": "commonjs",\n    "forceConsistentCasingInFileNames": true,\n    "strict": false,\n    "noImplicitOverride": true,\n    "noPropertyAccessFromIndexSignature": true,\n    "noImplicitReturns": true,\n    "noFallthroughCasesInSwitch": true\n  },\n  "files": [],\n  "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

笑话.config.ts:

\n
const nxPreset = require("@nrwl/jest/preset").default;\n\nexport default {\n  ...nxPreset,\n  clearMocks: true,\n  coverageReporters: ["lcov", "text", "text-summary", "json-summary"],\n  displayName: "kafka",\n  globals: {\n    "ts-jest": {\n      tsconfig: "<rootDir>/tsconfig.spec.json",\n    },\n  },\n  testEnvironment: "node",\n  transform: {\n    "^.+\\\\.[tj]s$": "ts-jest"\n  },\n  moduleFileExtensions: ["ts", "js"],\n  coverageDirectory: "../../coverage/packages/kafka",\n};\n\n
Run Code Online (Sandbox Code Playgroud)\n

单元测试:

\n
import Bull from "bull";\n\nimport * as dlq from "../src/dlq";\nimport { ModuleContext} from "./context";\n\njest.mock("bull");\n\ndescribe(ModuleContext.Root, () => {\n  describe(ModuleContext.Runner, () => {\n    it("success", () => {\n      expect(true).toBe(true);\n    })\n    describe(dlq.initialize.name, () => {\n      it("should return success", () => {\n        const createSpy = jest\n          .spyOn(Bull.prototype, "process")\n          .mockResolvedValue(null);\n\n        dlq.initialize();\n        expect(createSpy).toBeCalled();\n      });\n    });\n  });\n});\n\n
Run Code Online (Sandbox Code Playgroud)\n

笑话输出:

\n
 FAIL   kafka  packages/kafka/test/dlq.spec.ts\n  \xe2\x97\x8f Test suite failed to run\n\n    Jest encountered an unexpected token\n\n    Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.\n\n    Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.\n\n    By default "node_modules" folder is ignored by transformers.\n\n    Here\'s what you can do:\n     \xe2\x80\xa2 If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.\n     \xe2\x80\xa2 If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript\n     \xe2\x80\xa2 To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.\n     \xe2\x80\xa2 If you need a custom transformation specify a "transform" option in your config.\n     \xe2\x80\xa2 If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.\n\n    You\'ll find more details and examples of these config options in the docs:\n    https://jestjs.io/docs/configuration\n    For information about custom transformations, see:\n    https://jestjs.io/docs/code-transformation\n\n    Details:\n\n    /home/fahmi/logee/logee-ct/logeect-libraries-monorepo/node_modules/.pnpm/msgpackr@1.6.2/node_modules/msgpackr/index.js:1\n    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export { Packr, Encoder, addExtension, pack, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT, REUSE_BUFFER_MODE } from \'./pack.js\'\n                                                                                      ^^^^^^\n\n    SyntaxError: Unexpected token \'export\'\n\n      at Runtime.createScriptFromCode (../../node_modules/.pnpm/jest-runtime@28.1.3/node_modules/jest-runtime/build/index.js:1796:14)\n      at Object.<anonymous> (../../node_modules/.pnpm/bull@4.8.5/node_modules/bull/lib/scripts.js:8:18)\n
Run Code Online (Sandbox Code Playgroud)\n

小智 3

按照此处描述的 Nx 迁移步骤,我可以成功绕过该错误。

npx nx migrate latest
npx nx migrate --run-migrations
Run Code Online (Sandbox Code Playgroud)

您可以在更新的文件中看到,Nx 使用以下转换字段自动更新您的笑话配置:

  transform: {
    '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest', // My config from before
    '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/react/babel'] }], // Added by Nx under the migration
  },
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助。