玩笑+打字稿+绝对路径(baseUrl)提供错误:找不到模块

The*_*oul 13 absolute-path typescript jestjs visual-studio-code create-react-app

我正在设置配置以在create-react-app + typescript应用程序(我从中弹出)中运行测试。我正在使用笑话+酶。我在tsconfig.json中进行了设置,baseUrl='./src'以便在导入模块时可以使用绝对路径。例如,这是我的一个文件中的典型import语句:

import LayoutFlexBoxItem from 'framework/components/ui/LayoutFlexBoxItem';
Run Code Online (Sandbox Code Playgroud)

您可以看到该路径是绝对路径(来自/ src文件夹),而不是相对路径。当我在调试模式(yarn start)中运行时,效果很好

但是当我运行测试(yarn test)时,出现以下错误:

 Cannot find module 'framework/components/Navigation' from 'index.tsx'
Run Code Online (Sandbox Code Playgroud)

因此,尽管我在tsconfig.json中进行了设置,但看起来jest无法解析此绝对路径。这是我的tsconfig.json:

{
  "compilerOptions": {
    "outDir": "dist",
    "module": "esnext",
    "target": "es5",
    "lib": ["es6", "dom"],
    "sourceMap": true,
    "allowJs": true,
    "jsx": "react",
    "moduleResolution": "node",
    "rootDir": "src",
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": true,
    "baseUrl": "./src"    
  },
  "exclude": [
    "node_modules",
    "build",
    "dist",
    "config",    
    "scripts",
    "acceptance-tests",
    "webpack",
    "jest",
    "src/setupTests.ts"
  ]
}
Run Code Online (Sandbox Code Playgroud)

现在,我可以看到tsconfig.test.json在项目的根目录下有一个生成的。这是用于测试的ts配置。其内容如下:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs"
  }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,“模块”位于commonjs此处,而在默认配置中为esnext。这可能是原因之一吗?

有没有人能够用Jest和绝对路径对他的打字稿项目进行单元测试?还是这是一个已知的错误?由于我已从默认配置退出,因此我的webpack配置中是否有一些设置可以放置?

感谢您的输入和建议。

Tim*_*hiy 43

正如这里的许多人所指出的moduleNameMapperjest.config.js需要定义tsconfig.json. 例如,如果你有tsconfig.json如下定义的路径

// tsconfig.json
{
 ...
 "baseUrl": "src",
 "paths": {
    "@alias/*": [ 'path/to/alias/*' ]
 }
 ...
}
Run Code Online (Sandbox Code Playgroud)

那么您jest.config.js需要以moduleNameMapper以下格式提供这些路径:

// jest.config.js
module.exports = {
    'roots': [
        '<rootDir>/src'
    ],
    'transform': {
        '^.+\\.tsx?$': 'ts-jest'
    },
    'moduleNameMapper': {
         '@alias/(.*)': '<rootDir>/src/path/to/alias/$1'
    }
};
Run Code Online (Sandbox Code Playgroud)

有了它,我们可以改进我们jest.config.jstsconfig.json自动转换路径。这是一个Gist 代码片段

// jest.config.js

function makeModuleNameMapper(srcPath, tsconfigPath) {
    // Get paths from tsconfig
    const {paths} = require(tsconfigPath).compilerOptions;

    const aliases = {};

    // Iterate over paths and convert them into moduleNameMapper format
    Object.keys(paths).forEach((item) => {
        const key = item.replace('/*', '/(.*)');
        const path = paths[item][0].replace('/*', '/$1');
        aliases[key] = srcPath + '/' + path;
    });
    return aliases;
}

const TS_CONFIG_PATH = './tsconfig.json';
const SRC_PATH = '<rootDir>/src';

module.exports = {
    'roots': [
        SRC_PATH
    ],
    'transform': {
        '^.+\\.tsx?$': 'ts-jest'
    },
    'moduleNameMapper': makeModuleNameMapper(SRC_PATH, TS_CONFIG_PATH)
};
Run Code Online (Sandbox Code Playgroud)

  • 太感谢了!我已经为此苦苦挣扎了几个小时 (2认同)

use*_*925 29

对我来说,我只需要添加

\n
"modulePaths": ["<rootDir>/src"],\n
Run Code Online (Sandbox Code Playgroud)\n

到我的jest.config.js文件。

\n

以下答案修改moduleDirectories导致此错误:

\n
Jest encountered an unexpected token\n\nJest 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\nOut of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.\n\nBy default "node_modules" folder is ignored by transformers.\n\nHere\'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 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\nYou\'ll find more details and examples of these config options in the docs:\nhttps://jestjs.io/docs/configuration\nFor information about custom transformations, see:\nhttps://jestjs.io/docs/code-transformation\n
Run Code Online (Sandbox Code Playgroud)\n

使用:

\n
modulePaths: ["node_modules", "<rootDir>/src"],\n
Run Code Online (Sandbox Code Playgroud)\n

从阅读文档看来,这是一个附加目录的列表,因此node_modules是不必要的。

\n

  • 不确定为什么这个答案被否决了 - 这是一个干净的答案,至少可以与较新版本的 jest 完美配合(我在这里使用 v27+),并且是文档本身中针对此问题的推荐解决方案。唯一的事情是,在大多数情况下,当你的笑话配置位于项目根目录时,你实际上并不需要“&lt;rootDir&gt;”部分,“src”也可以正常工作。 (3认同)

Nec*_*ttn 25

在 package.json 中添加以下部分。进行更改后,不要忘记重新启动测试观察者。

  "jest": {
    "moduleDirectories": [
      "node_modules",
      "src"
    ],
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "roots": [
      "src"
    ],
    "testRegex": ".spec.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "coverageDirectory": "../coverage",
    "testEnvironment": "node",
    "moduleNameMapper": {
      "src/(.*)": "<rootDir>/src/$1"
    }
  }
Run Code Online (Sandbox Code Playgroud)

  • 当我在 Nestjs 框架中遇到这个问题时,它为我工作。我对 package.json 进行了编辑,现在可以使用绝对路径运行我的测试。 (5认同)

Yog*_*ity 12

使用最佳实践的解决方案

import出现此错误的原因是在使用 Jest 时在 TypeScript/Nest.js/Angular 项目的语句中使用了绝对路径。使用moduleDirectoriesmoduleNameMapper选项修复它可能会暂时解决您的问题,但它会产生其他包的问题,​​例如此TypeORM 问题。此外,Nest.js 框架的创建者在这里这里建议使用绝对路径是一种不好的做法。TypeScript 的官方文档建议我们自己的模块使用相对路径。


绝对路径与相对路径

import带有绝对路径的语句如下所示:

import { AuthService } from 'src/auth/auth.service'
Run Code Online (Sandbox Code Playgroud)

import带有相对路径的语句如下所示:

import { AuthService } from '../auth/auth.service'
Run Code Online (Sandbox Code Playgroud)

VS代码设置

Command当我们使用代码完成或/ Ctrl+自动导入时,VS Code 默认使用绝对路径,如上所示.。我们需要更改此默认设置以使用相对路径。

转到 VS Code 设置并搜索设置:Import Module Specifier。将其从 更改shortestrelative

现在从现在开始,VS Code 将使用相对路径自动导入。


修复项目中的导入

现在,在项目文件中,查找导入中与上面示例类似的绝对路径并将其删除。您将看到已删除的包的错误。只需使用自动导入建议并将其导入回来即可。这次将使用相对路径导入它们。根据项目的大小,此步骤可能会很乏味,但从长远来看是值得的。


希望能成功!干杯!


小智 11

我在同一个问题上苦苦挣扎,实际上事实证明,简单的更改似乎可以解决问题。

我刚刚更新的moduleDirectories领域jest.config.js

之前

moduleDirectories: ['node_modules']
Run Code Online (Sandbox Code Playgroud)

moduleDirectories: ['node_modules', 'src']
Run Code Online (Sandbox Code Playgroud)

希望能有所帮助,
安托万

  • 这可能是显而易见的,但如果您在导入中包含 src 路径,例如“... from 'src/...'”,请添加:`moduleDirectories: ['node_modules', '.']`。 (33认同)
  • 我将其添加到 package.json 中的 `jest` 下。 (4认同)

jez*_*nag 7

这是我如何使moduleNameMapper工作的。

在我的tsconfig中使用以下配置:

    "paths": {
      "@App/*": [
        "src/*"
      ],
      "@Shared/*": [
        "src/Shared/*"
      ]
    },
Run Code Online (Sandbox Code Playgroud)

这是moduleNameMapper:

"moduleNameMapper": {
  "@App/(.*)": "<rootDir>/src/$1",
  "@Shared/(.*)": "<rootDir>/src/Shared/$1"
}
Run Code Online (Sandbox Code Playgroud)


小智 6

ts-jest可以完美解决这个问题!
https://kulshekhar.github.io/ts-jest/docs/getting-started/paths-mapping#jest-config-with-helper
只需修改 jest.config.js 如下:

    const { pathsToModuleNameMapper } = require('ts-jest/utils');
    const { compilerOptions } = require('./tsconfig.json');
    module.exports = {
        // preset is optional, you don't need it in case you use babel preset typescript
        preset: 'ts-jest',
        // note this prefix option
        moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, /* { prefix: '<rootDir>/' } */)
    }
Run Code Online (Sandbox Code Playgroud)


Nat*_*han 6

对于那些使用绝对路径但不使用命名映射的人,这对我有用:

# jsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
  }
}
Run Code Online (Sandbox Code Playgroud)

# jest.config.js
const config = {
  moduleDirectories: ['node_modules', '<rootDir>'],
};
Run Code Online (Sandbox Code Playgroud)


lue*_*rro 5

这对我有用:

npm i -D jest typescript
npm i -D ts-jest @types/jest
npx ts-jest config:init
Run Code Online (Sandbox Code Playgroud)

然后在 jest.config.js 中,这是我的设置

module.exports = {
  preset: "ts-jest",
  testEnvironment: "node",
  modulePaths: ["node_modules", "<rootDir>/src"],
};
Run Code Online (Sandbox Code Playgroud)

就我而言,我没有任何paths内容tsconfig.json,但我已baseUrl设置src


Mat*_*újo 5

如果您已经安装了 ts-jest,则可以使用名为pathsToModuleNameMapper的 util 函数将 tsconfig.json 内的路径转换为 ​​jest.config 文件:

我的 jest.config.js 文件:

const { join } = require('path');
const { pathsToModuleNameMapper } = require('ts-jest')
const { compilerOptions } = require('./tsconfig.json')

/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */

module.exports = {
 rootDir: __dirname,
 setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
 setupFiles: ['<rootDir>/src/config/env.ts'],

 collectCoverageFrom: ["<rootDir>/src/modules/**/*UseCase.ts"],
 coverageProvider: "v8",
 coverageThreshold: {
   global: {
    lines: 40
   }
 },

 bail: true,
 clearMocks: true,
 displayName: 'unit-tests',
 testMatch: ["<rootDir>/src/modules/**/*.spec.ts"],

 preset: 'ts-jest',
 testEnvironment: 'node',

 modulePaths: ["<rootDir>/src"],
 moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
  prefix: join('<rootDir>', compilerOptions.baseUrl)
 })
};
Run Code Online (Sandbox Code Playgroud)


Dür*_*ani 5

"baseUrl": "./"在没有任何别名的情况下使用tsconfig.json

moduleDirectories: ['node_modules', '<rootDir>']jest.config.ts我工作。

现在我可以导入本地模块,例如import { Hello } from "src/modules/hello"没有任何问题。

笑话配置.ts

/*
 * For a detailed explanation regarding each configuration property and type check, visit:
 * https://jestjs.io/docs/configuration
 */
export default {
  clearMocks: true,
  collectCoverageFrom: ['**/*.(t|j)s'],
  coverageDirectory: 'coverage',
  coverageProvider: 'v8',
  moduleDirectories: ['node_modules', '<rootDir>'],
  moduleFileExtensions: ['js', 'json', 'ts'],
  roots: ['src', 'test'],
  setupFiles: ['dotenv/config'],
  testRegex: ['.*\\.spec\\.ts$'],
  transform: {
    '^.+\\.(t|j)s$': 'ts-jest',
  },
};
Run Code Online (Sandbox Code Playgroud)

tsconfig.json

/*
 * For a detailed explanation regarding each configuration property and type check, visit:
 * https://jestjs.io/docs/configuration
 */
export default {
  clearMocks: true,
  collectCoverageFrom: ['**/*.(t|j)s'],
  coverageDirectory: 'coverage',
  coverageProvider: 'v8',
  moduleDirectories: ['node_modules', '<rootDir>'],
  moduleFileExtensions: ['js', 'json', 'ts'],
  roots: ['src', 'test'],
  setupFiles: ['dotenv/config'],
  testRegex: ['.*\\.spec\\.ts$'],
  transform: {
    '^.+\\.(t|j)s$': 'ts-jest',
  },
};
Run Code Online (Sandbox Code Playgroud)


aka*_*Rem 3

您可能需要moduleNameMapperjest 配置的功能。它将您的自定义导入命名空间映射到真实的模块位置。

请参阅此处的官方文档:

https://facebook.github.io/jest/docs/en/configuration.html#modulenamemapper-object-string-string

  • 我有同样的问题。有人找到解决办法了吗?我尝试了“moduleDirectories”:[“src”],但它不起作用。 (3认同)