upgrade-support: jest fails with @react-native/polyfills/error-guard.js after upgrade to RN 0.64.0 and react 17.0.1

Environment

System: OS: Linux 5.4 Ubuntu 18.04.5 LTS (Bionic Beaver) CPU: (8) x64 Intel® Core™ i7-8550U CPU @ 1.80GHz Memory: 1.29 GB / 15.52 GB Shell: 4.4.20 - /bin/bash Binaries: Node: 14.5.0 - ~/.nvm/versions/node/v14.5.0/bin/node Yarn: 1.22.5 - /usr/bin/yarn npm: 6.14.9 - ~/.nvm/versions/node/v14.5.0/bin/npm Watchman: 20200920.192359.0 - /usr/local/bin/watchman SDKs: Android SDK: API Levels: 19, 24, 25, 27, 28, 29, 30 Build Tools: 28.0.3, 29.0.2, 29.0.3, 30.0.0 System Images: android-22 | Google APIs Intel x86 Atom, android-25 | Google APIs Intel x86 Atom, android-28 | Google Play Intel x86 Atom Android NDK: Not Found IDEs: Android Studio: Not Found Languages: Java: 11.0.10 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: 17.0.1 => 17.0.1 react-native: 0.64.0 => 0.64.0 npmGlobalPackages: react-native: Not Found

Things I’ve done to figure out my issue

did react-native upgrade which upgraded the appplication

Upgrading version

react-native 0.64.0 react 17.0.1

Description

After the upgrade, I did yarn test but all tests fail with error:

/node_modules/@react-native/polyfills/error-guard.js:14
    type ErrorHandler = (error: mixed, isFatal: boolean) => void;
         ^^^^^^^^^^^^

    SyntaxError: Unexpected identifier

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 100
  • Comments: 49

Commits related to this issue

Most upvoted comments

Add @react-native to your transformIgnorePatterns like this to your jest.config.js :

transformIgnorePatterns: [
    "/node_modules/(?!(@react-native|react-native)/).*/"
  ]

Also add the preset something like this in jest.config.js:

preset: "react-native",
setupFilesAfterEnv: ["@testing-library/jest-native/extend-expect"]

Check out for the libraries and update them accordingly to meet latest react version.

Any updates on this? Still facing the same issue.

Try to create babel.config.js with next content

module.exports = { presets: ['module:metro-react-native-babel-preset'], };

Adding the @react-native to the transformIgnorePatterns in the jest config solved it for me

transformIgnorePatterns: [
    "/node_modules/(?!(@react-native|react-native)/).*/"
]

I found out the solve ✅ You should remove react-native from transformIgnorePatterns regexp array !

transformIgnorePatterns: [
    '<rootDir>/node_modules/(react-clone-referenced-element|@react-native-community|react-navigation|@react-navigation/.*|@unimodules/.*|native-base|react-native-code-push)',
  ],

as Problem was in type define into js file which dont transforming because we was disable it. React native 64 developers add type ErrorHandler and we need it transform with ts-loader

my self jest.config.js file in root (example)

const {defaults: tsjPreset} = require('ts-jest/presets');

module.exports = {
  ...tsjPreset,
  preset: 'react-native',
  globals: {
    'ts-jest': {
      babelConfig: true,
    },
  },
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/$1',
    '^~/(.*)$': '<rootDir>/$1',
    '\\.svg': '<rootDir>/__mocks__/svgMock.js',
    'react-native-code-push': '<rootDir>/__mocks__/react-native-code-push.js',
    '@react-navigation': '<rootDir>/__mocks__/@react-navigation.js',
  },
  testRegex: '(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$',
  transformIgnorePatterns: [
    '<rootDir>/node_modules/(react-clone-referenced-element|@react-native-community|react-navigation|@react-navigation/.*|@unimodules/.*|native-base|react-native-code-push)',
  ],
  testPathIgnorePatterns: ['<rootDir>/node_modules/', '\\.snap$'],
  cacheDirectory: '.jest/cache',
  testEnvironment: 'jsdom',
  setupFiles: ['<rootDir>/__mocks__/mock-setup.js'],
};

/app/node_modules/@react-native/polyfills/error-guard.js:14
    type ErrorHandler = (error: mixed, isFatal: boolean) => void;
         ^^^^^^^^^^^^
facing same issue: 

    SyntaxError: Unexpected identifier

      at Runtime.createScriptFromCode (../../node_modules/jest-runtime/build/index.js:1350:14)
      at Object.<anonymous> (../../node_modules/react-native/jest/setup.js:439:6)

Other folks in this discussion have mentioned TypeScript as the culprit, but these are actually Flow types. It seems like react-native is now shipping untranspiled Flow code for some reason. To work around this, I installed @babel/plugin-transform-flow-strip-types and added it to my Babel config. Combined with the default transformIgnorePatterns value from the React Native Jest preset, my tests are now able to run again.

I would encourage the maintainers to ship code that does not use untranspiled Flow, as that breaks the assumptions a lot of JavaScript tooling makes.

All of this solutions do not work for me

I ran into the original issue using react-native:0.64.1, jest:27.5.1 and ts-jest:27.1.4. Based on a combination of the answers above, I fixed the issue and trimmed my jest.config.js down to the minimum. This is what it looks like:

module.exports = {
  preset: 'react-native',
  setupFiles: ['<rootDir>/jest/setup.js'],
  globals: {
    'ts-jest': {
      babelConfig: true,
    },
  }, // this was important
  moduleNameMapper: {
    '.+\\.(png)$': 'jest-transform-stub',
    '\\.(svg)$': '<rootDir>/jest/svgMock.js',
  },
  transformIgnorePatterns: [], // so was this 
};

I found out the solve ✅ You should remove react-native from transformIgnorePatterns regexp array !

transformIgnorePatterns: [
    '<rootDir>/node_modules/(react-clone-referenced-element|@react-native-community|react-navigation|@react-navigation/.*|@unimodules/.*|native-base|react-native-code-push)',
  ],

as Problem was in type define into js file which dont transforming because we was disable it. React native 64 developers add type ErrorHandler and we need it transform with ts-loader

my self jest.config.js file in root (example)

const {defaults: tsjPreset} = require('ts-jest/presets');

module.exports = {
  ...tsjPreset,
  preset: 'react-native',
  globals: {
    'ts-jest': {
      babelConfig: true,
    },
  },
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/$1',
    '^~/(.*)$': '<rootDir>/$1',
    '\\.svg': '<rootDir>/__mocks__/svgMock.js',
    'react-native-code-push': '<rootDir>/__mocks__/react-native-code-push.js',
    '@react-navigation': '<rootDir>/__mocks__/@react-navigation.js',
  },
  testRegex: '(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$',
  transformIgnorePatterns: [
    '<rootDir>/node_modules/(react-clone-referenced-element|@react-native-community|react-navigation|@react-navigation/.*|@unimodules/.*|native-base|react-native-code-push)',
  ],
  testPathIgnorePatterns: ['<rootDir>/node_modules/', '\\.snap$'],
  cacheDirectory: '.jest/cache',
  testEnvironment: 'jsdom',
  setupFiles: ['<rootDir>/__mocks__/mock-setup.js'],
};

I can confirm this transform works for me!

I was able to fix this

starting with a jest.config.js file that was producing the error:

/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
    preset: 'react-native',
    rootDir: '..',
    testMatch: ['<rootDir>/**/*.test.ts'],
    testPathIgnorePatterns: ['<rootDir>/e2e/*'],
    moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
}

none of the answers above worked for me. no variation of transformIgnorePatterns worked either, jest still went in and tried to transpile the bad polyfill file no matter what.

i figured out my babel.config.js file wasn’t getting picked up automatically… since I added a console.log and it wasn’t running

adding this transform fixed it:

/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
    preset: 'react-native',
    rootDir: '..',
    testMatch: ['<rootDir>/**/*.test.ts'],
    testPathIgnorePatterns: ['<rootDir>/e2e/*'],
    moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
    transform: {
        '^.+\\.(js|jsx|ts|tsx)$': [
            'babel-jest',
            { configFile: './babel.config.js' }, // <- cannot use rootDir here
        ],
    },
}

also note that the configFile must be a relative path from your current directory that you are running jest from. rootDir will not be respected

this was my babel.config.js… no need for @babel/plugin-transform-flow-strip-types either…

module.exports = function (api) {
    const presets = ['module:metro-react-native-babel-preset']
    const plugins = [
        [
            'react-native-reanimated/plugin',
            {
                globals: ['__scanCodes'],
            },
        ],
    ]

    ...
    
    return {
        presets,
        plugins,
    }
}

In my case, I’ve set transformIgnorePatterns: [] only. Works like a charm.

Same here after upgrading ts-jest, jest, and react-native to latest.

I fixed it by add this: "transformIgnorePatterns": [ "/node_modules/(?!(@react-native|react-native)).*/" ]

Try renaming your Babel config from .babelrc to babel.config.js

Wow it’s 2024 and it’s amazing this issue is still open years later with so many solutions and none that actually work for me. I’m in a bare react native project, no expo “for reasons”. And I just wanna write some test code. Amazing that it’s a multi-hour research project just to write some unit tests. It actually saeems quicker to write a new test runner than to spend time learning how to configure jest and babel and all this mess. Sigh…

I’m having a hell of time with this.

When I get what should be the right transformIgnorePatterns the error changes to this:

SyntaxError: /path/to/my-mono-repo/apps/mobile-v2/node_modules/react-native/Libraries/polyfills/error-guard.js: Unexpected token (45:12)

      43 |         _globalHandler && _globalHandler(error, true);
      44 |     }
    > 45 | } < mixed > , TOut;
         |             ^
      46 |  > (fun);
      47 | Fn < TArgs, TOut > ,
      48 |     context ?  :  ? mixed : ,

      at Parser._raise (../../node_modules/@babel/parser/lib/index.js:788:17)
      at Parser.raiseWithData (../../node_modules/@babel/parser/lib/index.js:781:17)
      at Parser.raise (../../node_modules/@babel/parser/lib/index.js:742:17)
      at Parser.unexpected (../../node_modules/@babel/parser/lib/index.js:9929:16)
      at Parser.parseExprAtom (../../node_modules/@babel/parser/lib/index.js:11349:20)
      at Parser.parseExprSubscripts (../../node_modules/@babel/parser/lib/index.js:10914:23)
      at Parser.parseUpdate (../../node_modules/@babel/parser/lib/index.js:10894:21)
      at Parser.parseMaybeUnary (../../node_modules/@babel/parser/lib/index.js:10872:23)
      at Parser.parseExprOpBaseRightExpr (../../node_modules/@babel/parser/lib/index.js:10819:34)
      at Parser.parseExprOpRightExpr (../../node_modules/@babel/parser/lib/index.js:10812:21)

I’ve added "plugins": ["@babel/plugin-transform-flow-strip-types"] to my babel.config.js also seems to have no effect.

Related issue with a repository that I can’t make work here: https://github.com/JacopoPatroclo/nx-react-native-expo/issues/21

Same error by me and i just created new project with typescript and cant run even initial test…


    E:\Studia\ReactNative\ComparePrices\node_modules\react-native\Libraries\vendor\core\ErrorUtils.js:11
    import type {ErrorUtilsT} from '@react-native/polyfills/error-guard';
    ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)
      at Object.<anonymous> (node_modules/react-native/jest/setup.js:37:3)

My config: Babel.config.js

// eslint-disable-next-line no-undef
module.exports = {
  presets: ["module:metro-react-native-babel-preset", "@babel/preset-typescript"],
  plugins: [
    "module:react-native-dotenv",
    "@babel/plugin-proposal-export-namespace-from",
    [
      "module-resolver",
      {
        root: ["./"],
        alias: { "^~(.+)": "./src/\\1" },
        extensions: [".ios.js", ".android.js", ".js", ".ts", ".tsx", ".json"],
      },
    ],
  ],
};

jest.config.ts

export default {
  clearMocks: true,

  globals: {
    "ts-jest": {
      tsconfig: "tsconfig.spec.json", // as specified by ts-jest
      babelConfig: true,
    },
  },

  moduleFileExtensions: ["js", "jsx", "ts", "tsx", "json", "node"],

  moduleNameMapper: {
    "^.+.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub",
  },

  preset: "react-native",

  testEnvironment: "jsdom",

  transform: {
    "^.+\\.jsx$": "babel-jest",
    "^.+\\.tsx?$": "ts-jest",
    ".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub",
  },

  transformIgnorePatterns: ["node_modules/(?!(@react-native)/)"],

  verbose: true,
};

I found out the solve ✅ You should remove react-native from transformIgnorePatterns regexp array !

transformIgnorePatterns: [
    '<rootDir>/node_modules/(react-clone-referenced-element|@react-native-community|react-navigation|@react-navigation/.*|@unimodules/.*|native-base|react-native-code-push)',
  ],

as Problem was in type define into js file which dont transforming because we was disable it. React native 64 developers add type ErrorHandler and we need it transform with ts-loader

my self jest.config.js file in root (example)

const {defaults: tsjPreset} = require('ts-jest/presets');

module.exports = {
  ...tsjPreset,
  preset: 'react-native',
  globals: {
    'ts-jest': {
      babelConfig: true,
    },
  },
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/$1',
    '^~/(.*)$': '<rootDir>/$1',
    '\\.svg': '<rootDir>/__mocks__/svgMock.js',
    'react-native-code-push': '<rootDir>/__mocks__/react-native-code-push.js',
    '@react-navigation': '<rootDir>/__mocks__/@react-navigation.js',
  },
  testRegex: '(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$',
  transformIgnorePatterns: [
    '<rootDir>/node_modules/(react-clone-referenced-element|@react-native-community|react-navigation|@react-navigation/.*|@unimodules/.*|native-base|react-native-code-push)',
  ],
  testPathIgnorePatterns: ['<rootDir>/node_modules/', '\\.snap$'],
  cacheDirectory: '.jest/cache',
  testEnvironment: 'jsdom',
  setupFiles: ['<rootDir>/__mocks__/mock-setup.js'],
};

This one solved my problem. Great thanks to @interhub.

For my case,

  globals: {
    'ts-jest': {
      tsconfig: 'tsconfig.spec.json', // as specified by ts-jest
      babelConfig: true,
    },
  },
  // ...
  transformIgnorePatterns: [],

does the trick.

Even if I put "/node_modules/(?!(@react-native|react-native)/).*/" in transformIgnorePatterns, I still got type ErrorHandler ... SyntaxError: Unexpected identifier. After digging in react-native’s jest-preset.js (source code), the line ("/node_modules/(?!(@react-native|react-native)/).*/") was already there. There must be something else going wrong. Then, I saw @interhub 's line babelConfig: true. Suddenly, I remembered some stuff written by react-native contributors, they stated that they used Babel to transpile Typescript instead of compiling Typescript code using tsc. Then, if we could build the app, but the tests failed, how about letting Babel to take care of the mess? (No offense, I am more used to Typescript than Flow.) Then, it works. After using this approach, aside from solving the type in .js problem with jest, no need to repeat the path alias set in babel.config.js in jest.config.js - moduleNameMapper again, those non-relative path imports will be taken care by Babel (I am using babel-plugin-module-resolver).

I am using react-native@0.64.2, jest@^26.6.3, ts-jest@^26.5.6. The following is my jest.config.js.

// jest.config.js
module.exports = {
  preset: 'react-native',
  globals: {
    'ts-jest': {
      tsconfig: 'tsconfig.spec.json',
      babelConfig: true,
    },
  },
  moduleFileExtensions: [
    'ts',
    'tsx',
    'js',
    'jsx',
    'json',
    'node',
  ],
  transform: {
    '^.+\\.(js|jsx)$': 'babel-jest',
    '^.+\\.(ts|tsx)$': 'ts-jest',
  },
  // This line should be kept even with nothing to be ignored, otherwise the transform will not take place.
  // Not quite sure about the reason.
  transformIgnorePatterns: [],
  testRegex: '(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$',
  testPathIgnorePatterns: [
    '<rootDir>/node_modules/',
    '\\.snap$',
  ],
  cacheDirectory: '.jest/cache',
};

For tsconfig.spec.json, please refer to Using with React Native | ts-jest.

any update on this? still test cases breaking on RN version 0.64.2

After testing almost every solution posted above, the only combination that worked for me was the following:

Please note that I’m using EXPO 50 which recommends removing the Babel config file and use the Metro config file. I’m not sure if there is a way to solve this WITHOUT adding the Babel file.

babel.config.js ({ loose: true } is key for this to work, thanks @elenitaex5 🙏🏼)

// eslint-disable-next-line no-undef
module.exports = {
  presets: [
    'babel-preset-expo',
    '@babel/preset-typescript',
  ],
  plugins: [['@babel/plugin-transform-private-methods', { loose: true }]],
};

jest.config.js (remove the “jest” entry from your package.json

import { Config } from '@jest/types';

const config: Config.InitialOptions = {
  preset: 'jest-expo',
  globals: {
    'ts-jest': {
      tsconfig: 'tsconfig.spec.json',
      babelConfig: true,
    },
  },
  transformIgnorePatterns: [],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
};

export default config;

Make sure you install this dev dependencies: @babel/plugin-transform-private-methods @babel/preset-typescript metro-react-native-babel-preset

[update] I found using jest: "^27" works. Just use preset: react-native and don’t need to override transform nor transformIgnorePatterns


still not working 😔 I’ve tried all methods mentioned above.

Here’s the repo which is just a new RN project. If possible, please someone to help. Thanks!

    "react": "18.1.0",
    "react-native": "0.70.1"
    "@babel/core": "^7.19.3",
    "@testing-library/jest-native": "^5.0.0",
    "@testing-library/react-native": "^11.2.0",
    "@types/jest": "^29.1.1",
    "babel-jest": "^29.1.2",
    "babel-preset-expo": "^9.2.0",
    "detox": "^19.12.5",
    "jest": "^29.1.2",
    "metro-react-native-babel-preset": "^0.72.1",
    "ts-jest": "^29.0.3",
    "typescript": "^4.8.4"

What worked for me.

My error

node_modules/@react-native/polyfills/error-guard.js:14 type ErrorHandler = (error: mixed, isFatal: boolean) => void; ^^^^^^^^^^^^

SyntaxError: Unexpected identifier

jest.config.ts file below. I added @react-native to it

import { Config } from "@jest/types";

// By default, all files inside `node_modules` are not transformed. But some 3rd party
// modules are published as untranspiled, Jest will not understand the code in these modules.
// To overcome this, exclude these modules in the ignore pattern.
const untranspiledModulePatterns = [
  "(jest-)?react-native",
  "@react-native-community",
  "expo(nent)?",
  "@expo(nent)?/.*",
  "react-navigation",
  "@react-navigation/.*",
  "@unimodules/.*",
  "unimodules",
  "sentry-expo",
  "native-base",
  "react-native-svg",
  "@react-native*" <--- This line did it for me
];

const config: Config.InitialOptions = {
  preset: "jest-expo",
  transformIgnorePatterns: [
    `node_modules/(?!${untranspiledModulePatterns.join("|")})`,
  ],
  moduleFileExtensions: ["ts", "tsx", "js", "jsx"],
};

export default config;

jest.config.ts

All above consolidated for Expo and TS

const config: Config.InitialOptions = {
  preset: "jest-expo",
  globals: {
    "ts-jest": {
      tsconfig: "tsconfig.spec.json", // as specified by ts-jest
      babelConfig: true,
    },
  },
  transformIgnorePatterns: [],
  moduleFileExtensions: ["ts", "tsx", "js", "jsx"],
};

export default config;

Same issue here, but I get this failure when using typescript.

I had my project with EXPO and detox configuration still… I had this error too, but looking for a solution here I fix my code. Including config in package Json I had another error:

Class private methods are not enabled. Please add @babel/plugin-transform-private-methods to your configuration.

So I added it into my devs and modify my babel.config.js

My package.json

{
...
"jest": {
    "preset": "jest-expo",
    "globals": {
      "ts-jest": {
        "tsconfig": "tsconfig.spec.json",
        "babelConfig": true
      }
    },
    "transformIgnorePatterns": [],
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js",
      "jsx"
    ]
  },
  "devDependencies": {
  ...
  "@babel/plugin-transform-private-methods": "^7.22.5",
  }
  ...
}

in babel.config.js add this

{
   ...
   plugins: [
      ['@babel/plugin-transform-private-methods', { loose: true }],
   ]
}

Hope it helps to someone ❤️

Thanks @Eandalf, babelConfig: true + empty transformIgnorePatterns does the trick.

  globals: {
    'ts-jest': {
      tsconfig: 'tsconfig.spec.json', // as specified by ts-jest
      babelConfig: true,
    },
  },
  // ...
  transformIgnorePatterns: [],

Same error ` C:\SourceCode\leyserkids-kp-rn\node_modules\react-native-config\index.js:6 import { NativeModules } from ‘react-native’; ^^^^^^

SyntaxError: Cannot use import statement outside a module

  1 | // eslint-disable-next-line no-restricted-imports
> 2 | import Config from 'react-native-config';
    | ^
  3 |
  4 | export enum Env {
  5 |     dev = 'dev',

  at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)
  at Object.<anonymous> (config/config.ts:2:1)

`

Same here, with RN 0.63.3