使用 Jest 和 @testing-library/react-native 测试 React Native 项目时出现“SyntaxError: Cannot use import stateme

Posted

技术标签:

【中文标题】使用 Jest 和 @testing-library/react-native 测试 React Native 项目时出现“SyntaxError: Cannot use import statement outside a module”错误?【英文标题】:"SyntaxError: Cannot use import statement outside a module" error while testing React Native project with Jest and @testing-library/react-native? 【发布时间】:2021-06-03 15:01:42 【问题描述】:

我每次运行npm test时都会遇到错误:

 FAIL  ./App.test.js

● 测试套件无法运行

Jest encountered an unexpected token

This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain javascript.

By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

Here's what you can do:
 • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
 • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
 • If you need a custom transformation specify a "transform" option in your config.
 • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/en/configuration.html

Details:

/Users/bestes/Desktop/react-native-training/node_modules/react-native-status-bar-height/index.js:1
("Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest)import  Dimensions, Platform, StatusBar  from 'react-native';
                                                                                         ^^^^^^

SyntaxError: Cannot use import statement outside a module

  at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1350:14)
  at Object.<anonymous> (node_modules/react-native-elements/src/config/index.js:1:1)

我的测试:

import 'react-native';
import React from 'react';
import  render  from '@/../testing/test-utils'
import App from './App'


test('should render app component', () => 
  const result = render(<App />)

  expect(result).toMatchSnapshot()
)

我的 test-utils.js 文件:

import React from 'react'

import  render  from '@testing-library/react-native'
import  store  from '@/bootstrap/redux'
import  Provider  from 'react-redux'

const AllTheProviders = ( children ) => 
  return (
    <Provider store=store>
      children
    </Provider>
  )


const customRender = (ui, options) =>
  render(ui,  wrapper: AllTheProviders, ...options )

// re-export everything
export * from '@testing-library/react-native'

// override render method
export  customRender as render 

我的 package.json 文件:


  "name": "ReactNativeTraining",
  "version": "0.0.1",
  "private": true,
  "scripts": 
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
  ,
  "dependencies": 
    "@react-native-community/geolocation": "2.0.2",
    "@react-native-community/masked-view": "0.1.10",
    "@react-native-picker/picker": "1.9.10",
    "@reduxjs/toolkit": "1.5.0",
    "axios": "0.21.1",
    "dayjs": "1.10.4",
    "lodash": "4.17.20",
    "react": "16.13.1",
    "react-native": "0.63.2",
    "react-native-config": "1.4.2",
    "react-native-elements": "3.0.0-alpha.1",
    "react-native-geocoding": "0.5.0",
    "react-native-gesture-handler": "1.9.0",
    "react-native-permissions": "3.0.0",
    "react-native-picker-select": "8.0.4",
    "react-native-reanimated": "1.13.2",
    "react-native-safe-area-context": "3.1.9",
    "react-native-screens": "2.17.0",
    "react-native-size-matters": "0.4.0",
    "react-native-vector-icons": "8.0.0",
    "react-navigation": "4.0.2",
    "react-navigation-stack": "1.5.4",
    "react-navigation-tabs": "2.4.1",
    "react-redux": "7.2.2"
  ,
  "devDependencies": 
    "@babel/core": "7.12.10",
    "@babel/runtime": "7.12.5",
    "@react-native-community/eslint-config": "2.0.0",
    "@testing-library/jest-native": "4.0.1",
    "@testing-library/react-native": "7.2.0",
    "babel-jest": "^26.6.3",
    "babel-plugin-module-resolver": "4.0.0",
    "eslint": "7.18.0",
    "jest": "26.6.3",
    "metro-react-native-babel-preset": "0.64.0",
    "react-test-renderer": "16.13.1"
  ,
  "type": "module",
  "jest": 
    "verbose": true,
    "preset": "react-native",
    "setupFilesAfterEnv": ["@testing-library/jest-native/extend-expect"],
    "transformIgnorePatterns": [
      "node_modules/(?!(react-native",
      "@react-native-community/geolocation",
      "@react-native-community/masked-view",
      "|@react-native-picker/picker",
      "|@reduxjs/toolkit",
      "|axios",
      "|dayjs",
      "|lodash",
      "|react",
      "|react-native",
      "|react-native-config",
      "|react-native-elements",
      "|react-native-geocoding",
      "|react-native-gesture-handler",
      "|react-native-permissions",
      "|react-native-picker-select",
      "|react-native-reanimated",
      "|react-native-safe-area-context",
      "|react-native-screens",
      "|react-native-size-matters",
      "|react-native-vector-icons",
      "|react-navigation",
      "|react-navigation-stack",
      "|react-navigation-tabs",
      "|react-redux",
      ")/)"
    ]
  

我的 babel.config.js 文件:

module.exports = function (api) 
  api.cache(true)
  const presets = [
    'module:metro-react-native-babel-preset'
  ]
  const plugins = [
    [
      'module-resolver', 
        'root': ['./src/'],
        'extensions': ['.js', '.ios.js', '.android.js'],
        'alias': 
          '@': './src/'
        
      
    ]
  ]
  return 
    presets,
    plugins
  

我尝试过的: 将 "type": "module" 添加到我的根级别 package.json 文件中,它修复了与导出类似的错误, 将转换忽略模式添加到 package.json 文件中的 Jest 键。 我将所有依赖项都添加到了 transformIgnorePatterns 中,因为它不断在每个依赖项上抛出错误,直到我添加了所有依赖项,现在它在 react-native 模块导入时抛出。

【问题讨论】:

我要补充一点,这似乎只是在尝试导入 App 组件时出现的问题。我在导入单个组件时没有看到错误。 错误似乎来自react-native-status-bar-height 模块。那是从哪里来的?您是否尝试将其包含在您的 transformIgnorePatterns 中? 【参考方案1】:

[已解决]为我工作 在下面安装

npm install --save-dev @babel/core
npm install --save-dev @babel/preset-env

之后在根目录下创建“babel.config.js”文件,内容如下

module.exports = 
  presets: ['@babel/preset-env', '@babel/preset-react'],
  env: 
    test: 
      plugins: ["@babel/plugin-transform-runtime"]
    
  
;

【讨论】:

它的 npm install --save-dev @babel/preset-env 而不是 npm install --save-dev @babel/present-env 请更新 感谢您的更新..@MuhammadOwaisChaudhary 它不能解决 react native 项目的问题。从 0.63.3 升级到 0.66.3 突然使一些测试因这个奇怪的错误而中断。【参考方案2】:

“Jest 附带对 ECMAScript 模块 (ESM) 的实验性支持” - ECMAScript Modules

package.json 中添加您的 test 脚本,并使用 Node 实验功能:--experimental-vm-modules

这样你就不需要 babel 或其他依赖了。

例子:

"test": "NODE_OPTIONS='--experimental-vm-modules --experimental-specifier-resolution=node' jest"

如果您收到此错误:zsh: command not found: jest,请尝试使用 node 传递 jest.js,如下所示:

"test": "NODE_OPTIONS='--experimental-vm-modules --experimental-specifier-resolution=node --trace-warnings' node node_modules/jest/bin/jest.js --detectOpenHandles"

与此类似:https://***.com/a/70199545/5078874

【讨论】:

以上是关于使用 Jest 和 @testing-library/react-native 测试 React Native 项目时出现“SyntaxError: Cannot use import stateme的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 jest 和 detox 生成代码覆盖率报告?

使用 React、Typescript 和 ES6 进行 Jest 测试

如何在 React 和 Webpack 中使用 Jest

babel@7 和 jest 配置

使用 jest 和 vue 抛出 SyntaxError: Unexpected identifier error for import

React Redux:使用 Enzyme/Jest 测试 mapStateToProps 和 mapDispatchToProps