Jest:在 React/Typescript 项目中出现“SyntaxError: Cannot use import statement outside a module”错误

5

我在使用Babel、Typescript、React和Jest进行测试时,遇到了关于Jest的问题。

在测试React/Typescript组件时,我收到了SyntaxError: Cannot use import statement outside a module的错误信息。

我尝试过的解决方法:

  1. 使用babel插件(见下面的babel配置)
  2. 使用ts-jest
  3. 尝试使用文档中的ts-jest ESM支持
  4. 阅读了类似问题的thisthisthis文章

这是jest.config.js

const ignores = ['/node_modules/'];

module.exports = {
    preset: 'ts-jest',
    roots: ['<rootDir>'],
    modulePaths: [
        "<rootDir>/src"
    ],
    moduleDirectories: [
        "node_modules",
    ],
    transformIgnorePatterns: [...ignores],
    transform: {
        '^.+\\.(ts|tsx)?$': 'ts-jest',
        '^.+\\.(gif|svg|ico)$': '<rootDir>/svgTransform.js',
    },
    testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.js?$',
    moduleFileExtensions: ['tsx', 'js', 'ts'],
    moduleNameMapper: {
        "\\.(css|less|scss|sass)$": "identity-obj-proxy",
        '^(\\.{1,2}/.*)\\.js$': '$1',
      },
    clearMocks: true,
    // collectCoverage: true, // todo
    // coverageDirectory: "coverage",  // todo
    testEnvironment: 'jsdom',
    setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect', './src/tests/setup.js'],
    resolver: 'jest-webpack-resolver',
}

这是 babel.config.js 文件:
module.exports = {
    // For transformation of TSX and other react related bable plugins
    presets: [
        ['@babel/preset-env',  {
            targets: { esmodules: false, node: "current" }
         }],
        // Enabling Babel to understand TypeScript
        '@babel/preset-typescript', "@babel/preset-react"
    ],
    plugins: ['@babel/plugin-transform-modules-commonjs', '@babel/plugin-transform-runtime'],
}

这是错误的代码跟踪:

code-trace

package.json:

{
    "name": "@unirep-social/frontend",
    "version": "1.0.0",
    "private": true,
    "scripts": {
        "start": "webpack-dev-server",
        "start-local": "webpack-dev-server",
        "build": "webpack",
        "lint": "prettier .",
        "build:worker": "webpack --config webpack.worker.js",
        "postinstall": "link-module-alias && yarn copyCircuits",
        "copyCircuits": "node scripts/copy_circuits",
        "test": "jest --config ./jest.config.js",
        "test:watch": "jest --watch",
        "test:coverage": "jest --coverage"
    },
    "_moduleAliases": {
        "worker_threads": "./externals/worker_threads.js"
    },
    "dependencies": {
        "@babel/plugin-transform-runtime": "^7.18.6",
        "@babel/preset-env": "^7.18.6",
        "@types/react": "^17.0.15",
        "@types/react-dom": "^17.0.9",
        "@unirep/circuits": "git+https://github.com/Unirep/circuits.git#alpha",
        "@unirep/crypto": "git+https://github.com/Unirep/crypto.git",
        "@unirep/unirep": "git+https://github.com/Unirep/unirep.git#alpha",
        "@unirep/unirep-social": "git+https://github.com/Unirep/unirep-social.git#alpha",
        "babel-preset-env": "^1.7.0",
        "bootstrap": "^5.0.2",
        "dateformat": "^4.5.1",
        "ethers": "^5.5.4",
        "identity-obj-proxy": "^3.0.0",
        "jest-environment-jsdom": "^28.1.2",
        "keyv": "4.1.1",
        "markdown-it": "^12.3.2",
        "mobx": "^6.4.2",
        "mobx-react-lite": "^3.3.0",
        "n-readlines": "^1.0.1",
        "nanoid": "^4.0.0",
        "node-sass": "^6.0.1",
        "react": "^17.0.2",
        "react-circular-progressbar": "^2.0.4",
        "react-dom": "^17.0.2",
        "react-favicon": "^1.0.0",
        "react-icons": "^4.2.0",
        "react-jdenticon": "^0.0.9",
        "react-router-dom": "^5.2.0",
        "react-router-hash-link": "^2.4.3",
        "snarkjs": "^0.3.59",
        "ts-jest": "^28.0.5"
    },
    "devDependencies": {
        "@babel/core": "^7.18.6",
        "@babel/plugin-transform-modules-commonjs": "^7.18.6",
        "@babel/preset-react": "^7.18.6",
        "@babel/preset-typescript": "^7.18.6",
        "@cloudflare/kv-asset-handler": "^0.2.0",
        "@testing-library/jest-dom": "^5.16.4",
        "@testing-library/react": "12.1.5",
        "@testing-library/user-event": "^14.2.1",
        "@types/jest": "^28.1.4",
        "@types/keyv": "^3.1.2",
        "@types/markdown-it": "^12.2.3",
        "@types/n-readlines": "^1.0.2",
        "@types/react-router-dom": "^5.1.8",
        "@types/shelljs": "^0.8.9",
        "assert": "^2.0.0",
        "babel-jest": "^28.1.2",
        "babel-loader": "^8.2.3",
        "buffer": "^6.0.3",
        "crypto-browserify": "^3.12.0",
        "css-loader": "^6.7.1",
        "css-minimizer-webpack-plugin": "^3.4.1",
        "file-loader": "^6.2.0",
        "html-webpack-plugin": "^5.5.0",
        "jest": "^28.1.2",
        "jest-axe": "^6.0.0",
        "jest-webpack-resolver": "^0.3.0",
        "link-module-alias": "^1.2.0",
        "mini-css-extract-plugin": "^2.6.0",
        "os-browserify": "^0.3.0",
        "prettier": "^2.6.0",
        "react-test-renderer": "^18.2.0",
        "sass": "^1.49.9",
        "sass-loader": "^12.6.0",
        "stream-browserify": "^3.0.0",
        "ts-loader": "^9.2.8",
        "typescript": "^4.3.5",
        "url-loader": "^4.1.1",
        "webpack": "^5.70.0",
        "webpack-cli": "^4.9.2",
        "webpack-dev-server": "^4.7.4"
    },
    "jestWebpackResolver": {
        "webpackConfig": "./webpack.config.js"
    },
    "prettier": {
        "tabWidth": 4,
        "singleQuote": true,
        "semi": false
    }
}

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin')
// const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin')
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const webpack = require('webpack')

module.exports = {
    entry: ['./src/index.tsx'],
    mode: 'development',
    devServer: {
        port: 3000,
        // proxy: {
        //     '/api': {
        //         target: 'http://localhost:3000',
        //         router: () => 'http://localhost:3001',
        //     },
        // },
        historyApiFallback: true,
    },
    output: {
        path: path.resolve(__dirname, 'build'),
        publicPath: '/',
    },
    resolve: {
        extensions: ['*', '.js', '.ts', '.tsx', '.json', '.scss'],
        fallback: {
            crypto: require.resolve('crypto-browserify'),
            assert: require.resolve('assert/'),
            stream: require.resolve('stream-browserify'),
            os: require.resolve('os-browserify/browser'),
            fs: false,
            dotenv: false,
        },
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-react'],
                        },
                    },
                    {
                        loader: 'ts-loader',
                    },
                ],
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                options: {
                    presets: ['@babel/preset-react'],
                },
            },
            {
                test: /\.(png|jpg|gif|svg|ico)$/i,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            esModule: false,
                            limit: 8192,
                        },
                    },
                ],
            },
            {
                test: /\.s[ac]ss$/i,
                use: [
                    MiniCssExtractPlugin.loader,
                    // Translates CSS into CommonJS
                    'css-loader',
                    // Compiles Sass to CSS
                    'sass-loader',
                ],
            },
            {
                test: /\.(css)$/,
                // exclude: /node_modules/,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader,
                    },
                    'css-loader',
                ],
            },
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: 'public/index.html',
            filename: 'index.html',
            inlineSource: '.(js|css)',
        }),
        new MiniCssExtractPlugin({
            filename: 'styles.css',
        }),
        // new HtmlWebpackInlineSourcePlugin(),
        new webpack.DefinePlugin({
            'process.env': {},
            'process.argv': [],
            'process.versions': {},
            'process.versions.node': '"12"',
            process: {
                exit: '(() => {})',
                browser: true,
                versions: {},
                cwd: '(() => "")',
            },
        }),
        new webpack.ProvidePlugin({
            Buffer: path.resolve(__dirname, 'externals', 'buffer.js'),
        }),
        new webpack.ContextReplacementPlugin(/\/keyv\//, (data) => {
            delete data.dependencies[0].critical
            return data
        }),
        new webpack.ContextReplacementPlugin(/\/maci\-crypto\//, (data) => {
            delete data.dependencies[0].critical
            return data
        }),
    ],
    optimization: {
        // minimizer: [
        //   `...`,
        //   new CssMinimizerPlugin(),
        // ],
    },
}


对我有用的方法:将nanoid软件包降级至3.3.4版本。


1
我的意思是,您不需要将Babel与TypeScript一起使用,因为两者都可以将TypeScript转换为JavaScript。在这种情况下,由于您正在使用Babel构建webpack捆绑包,我建议仅在Jest中使用Babel。您可以卸载ts-jest,这应该可以加快和简化测试设置。 - Nick McCurdy
啊,我明白了。那你会建议jest文件中的预设是什么吗?测试时间变得很长,这可能就是原因。@NickMcCurdy - AAMCODE
你在这个项目中使用TypeScript吗?我注意到了.js扩展名。 - Nick McCurdy
1
@NickMcCurdy 是的,我上面已经提到了。 - AAMCODE
1
注意:通过降级nanoid包已修复。 - AAMCODE
显示剩余2条评论
1个回答

4

原帖是以评论的形式发布的,但是他通过将nanoid软件包从v4.0.0降级来解决了这个问题。

我也遇到了同样的问题,降级到之前稳定版本的3.3.4可以解决我的问题。以下是我的做法:

npm i nanoid@3.3.4

感谢原帖作者!


1
另外,我对原帖进行了编辑,关于降级nanoid的问题。https://dev59.com/vcTsa4cB1Zd3GeqPGsmA#73795371:~:text=What%20worked%20for%20me%3A%20Downgraded%20nanoid%20package%20to%203.3.4 - AAMCODE
对我来说没用,我用的是nanoid@3.3.4!同样的问题。 - undefined
@PeterStjernholmMeldgaard 你用的是哪个Node版本? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接