Next.js 和 Jest:语法错误:无法在模块外部使用 import 语句

Gre*_*eco 16 javascript typescript jestjs babel-jest next.js

我正在使用 TypeScript 开发 Next.js 项目,并使用 Jest 和 React 测试库进行测试。但是,我遇到 SyntaxError : Cannot use import statements external a module for elements where I import rehype-raw

\n

据我了解,Jest不支持ES6,因此node_modules可能需要转换。这可以使用配置transformIgnorePatterns。例如,如果rehype-raw导致此错误,"transformIgnorePatterns": ["node_modules/(?!rehype-raw)/"]则应允许转换rehype-raw但不允许转换其他模块。从而解决这个错误。

\n

但是,这对我不起作用。但我不知道为什么以及如何解决这个问题。我发现没有建议的解决方案可以解决这个问题。我在下面附上了我的错误输出jest.config.jsbabel.rc文件。

\n

错误输出

\n
 FAIL  test/pages/companies/[id].test.tsx                  \n  \xe2\x97\x8f Test suite failed to run\n\n    Jest encountered an unexpected token\n\n    [...]\n\n    Details:\n\n    /path/frontend-job/node_modules/rehype-raw/index.js:7\n    import {raw} from 'hast-util-raw'\n    ^^^^^^\n\n    SyntaxError: Cannot use import statement outside a module\n\n      3 | import Image from 'next/image';\n      4 | import { Remark } from 'react-remark';\n    > 5 | import rehypeRaw from 'rehype-raw';\n        | ^\n      6 | import rehypeSanitize from 'rehype-sanitize';\n      7 | import { logError } from '@utils/logger';\n      8 |\n\n      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)\n      at Object.<anonymous> (components/markdown/JobMarkdown.tsx:5:1)\n
Run Code Online (Sandbox Code Playgroud)\n

笑话配置.js

\n
const { resolve } = require('path');\n\nmodule.exports = {\n  roots: ['<rootDir>'],\n  moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'],\n  setupFiles: ['<rootDir>/test/setup.js'],\n  testPathIgnorePatterns: ['<rootDir>[/\\\\\\\\](node_modules|.next)[/\\\\\\\\]'],\n  transform: {\n    '^.+\\\\.(ts|tsx)$': 'babel-jest',\n  },\n  transformIgnorePatterns: [\n    'node_modules/(?!rehype-raw)/',\n  ],\n  watchPlugins: [\n    'jest-watch-typeahead/filename',\n    'jest-watch-typeahead/testname',\n  ],\n  moduleNameMapper: {\n    // Force mocks: https://github.com/facebook/jest/issues/4262\n    '@api/axios': '<rootDir>/test/__mocks__/axios.js',\n    // Normal module aliases\n    '\\\\.(css|less|sass|scss)$': 'identity-obj-proxy',\n    '\\\\.(gif|ttf|eot|svg|png)$': '<rootDir>/test/__mocks__/fileMock.js',\n    '^@test/(.*)$': resolve(__dirname, './test/$1'),\n    '^@test/faker/(.*)$': resolve(__dirname, './test/faker/$1'),\n    '^@components/(.*)$': resolve(__dirname, './components/$1'),\n    '^@pages/(.*)$': resolve(__dirname, './pages/$1'),\n    '^@utils/(.*)$': resolve(__dirname, './utils/$1'),\n    '^@api/(.*)$': resolve(__dirname, './api/$1'),\n    '^@store/(.*)$': resolve(__dirname, './store/$1'),\n  },\n  testEnvironment: 'jsdom',\n};\n
Run Code Online (Sandbox Code Playgroud)\n

babel.rc

\n
{\n  "presets": ["next/babel"]\n}\n
Run Code Online (Sandbox Code Playgroud)\n

use*_*488 7

Jest 不支持使用 ECMAScript 模块hast-util-raw。第二个问题;transformIgnorePatterns也不起作用,所以下面是我自己使用 Next.JS 设置进行的修复。

1.删​​除babel.rc

删除你的babel.rc. 您只需使用以下更改即可。

2.添加模块名称映射器

parse5这修复了无法找到的不同错误。要求者hast-util-raw

/** @type {import('jest').Config} */
const customJestConfig = {
  //...
  moduleNameMapper: {
    'parse5/lib/parser/index.js':
      '<rootDir>/node_modules/hast-util-raw/node_modules/parse5/lib/parser/index.js',
  }
}
Run Code Online (Sandbox Code Playgroud)

3.添加transformIgnorePatterns

transformIgnorePatterns但是在最后添加。正如我所说,由于某种原因,这无法直接添加到配置中。我还必须添加hast-util-raw. 我确信有更好的方法来做到这一点:)

module.exports = async () => ({
  ...(await createJestConfig(customJestConfig)()),
  transformIgnorePatterns: [
    'node_modules/(?!(rehype-raw|hast-util-raw|unist-util-position|unist-util-visit|unist-util-visit-parents|unist-util-is|hast-util-from-parse5|hastscript|property-information|hast-util-parse-selector|space-separated-tokens|comma-separated-tokens|vfile-location|web-namespaces|hast-util-to-parse5|zwitch|html-void-elements)/)'
  ]
})

Run Code Online (Sandbox Code Playgroud)

如果有人感兴趣的话我的完整配置...

/* eslint-disable @typescript-eslint/no-var-requires */
// jest.config.js
const nextJest = require('next/jest')

const createJestConfig = nextJest({
  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
  dir: './'
})

// Add any custom config to be passed to Jest
/** @type {import('jest').Config} */
const customJestConfig = {
  // Add more setup options before each test is run
  setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
  // if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
  moduleDirectories: ['<rootDir>/node_modules', '<rootDir>/src', '<rootDir>/src/pages'],
  testEnvironment: 'jest-environment-jsdom',
  testPathIgnorePatterns: [
    '<rootDir>/.next/',
    '<rootDir>/node_modules/',
    '<rootDir>/coverage',
    '<rootDir>/dist'
  ],
  moduleNameMapper: {
    'react-markdown': '<rootDir>/node_modules/react-markdown/react-markdown.min.js',
    'parse5/lib/parser/index.js':
      '<rootDir>/node_modules/hast-util-raw/node_modules/parse5/lib/parser/index.js'
  },
  resolver: '<rootDir>/.jest/resolver.js',
  clearMocks: true,
  testTimeout: 20000
}

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
// module.exports = createJestConfig(customJestConfig)
module.exports = async () => ({
  ...(await createJestConfig(customJestConfig)()),
  transformIgnorePatterns: [
    'node_modules/(?!(rehype-raw|hast-util-raw|unist-util-position|unist-util-visit|unist-util-visit-parents|unist-util-is|hast-util-from-parse5|hastscript|property-information|hast-util-parse-selector|space-separated-tokens|comma-separated-tokens|vfile-location|web-namespaces|hast-util-to-parse5|zwitch|html-void-elements)/)'
  ]
})

Run Code Online (Sandbox Code Playgroud)


小智 -3

Next 已经对 Jest 提供了开箱即用的支持,我建议您按照文档中提供的步骤进行操作。

  • 我尝试了文档中描述的 next/js 并扩展了自定义笑话配置,但我仍然得到“SyntaxError:无法在模块外使用 import 语句” (8认同)
  • 我认为使用 https://github.com/vercel/next.js/discussions/31152#discussioncomment-1697047 我可以解决这个语法错误,但有些模拟不再工作 (3认同)
  • 如果有效,您可以发布解决方案吗?文档没有给出修复方法 (2认同)