Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Jest 28][Yup Resolver] SyntaxError: Cannot use import statement outside a module #396

Closed
GustavoSchuler opened this issue Apr 27, 2022 · 13 comments · Fixed by #435
Closed
Labels
dependencies Pull requests that update a dependency file released

Comments

@GustavoSchuler
Copy link

GustavoSchuler commented Apr 27, 2022

I'm receiving a Syntax Error when running my tests with Jest v28. It was working with v27.x

image

I'm using React 17 and Next 12 with TypeScript.
Here's my deps list:

"dependencies": {
    "@fingerprintjs/fingerprintjs": "3.3.3",
    "@grupoboticario/flora": "^0.15.0",
    "@grupoboticario/flora-react": "^0.10.16",
    "@grupoboticario/flora-screenrecording-addon": "^2.3.0",
    "@hookform/resolvers": "^2.8.8",
    "@loadable/component": "^5.15.2",
    "@newrelic/next": "^0.1.1",
    "@prismicio/client": "^6.4.3",
    "@prismicio/helpers": "^2.3.0",
    "@prismicio/react": "^2.3.0",
    "@radix-ui/react-collapsible": "^0.1.6",
    "axios": "^0.27.2",
    "cache-manager": "^3.6.1",
    "newrelic": "^8.10.0",
    "next": "^12.1.5",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-google-login": "^5.2.2",
    "react-hook-form": "^7.30.0",
    "react-icons": "^4.3.1",
    "react-loadable-visibility": "^3.0.2",
    "react-swipeable": "^7.0.0",
    "sitemap": "^7.1.1",
    "tldts": "^5.7.76",
    "uuid": "^8.3.2",
    "winston": "^3.7.2",
    "yup": "^0.32.11"
  },
  "devDependencies": {
    "@prismicio/types": "^0.1.27",
    "@release-it/bumper": "^3.0.1",
    "@testing-library/dom": "^8.13.0",
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/react": "<13.0.0",
    "@testing-library/react-hooks": "^8.0.0",
    "@testing-library/user-event": "^14.1.1",
    "@types/cache-manager": "^3.4.3",
    "@types/jest": "^27.4.1",
    "@types/jest-when": "^3.5.0",
    "@types/newrelic": "^7.0.3",
    "@types/node": "^17.0.29",
    "@types/react": "^18.0.8",
    "@types/react-loadable-visibility": "^3.0.2",
    "@types/uuid": "^8.3.4",
    "@typescript-eslint/eslint-plugin": "^5.21.0",
    "@typescript-eslint/parser": "^5.21.0",
    "babel-jest": "^28.0.2",
    "canvas": "^2.9.1",
    "eslint": "<9.0.0",
    "eslint-config-next": "^12.1.5",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-jest": "^26.1.5",
    "eslint-plugin-jsx-a11y": "^6.5.1",
    "eslint-plugin-prettier": "^4.0.0",
    "eslint-plugin-react": "^7.29.4",
    "eslint-plugin-react-hooks": "^4.5.0",
    "eslint-plugin-simple-import-sort": "^7.0.0",
    "eslint-plugin-sonarjs": "^0.13.0",
    "husky": "^7.0.4",
    "jest": "^28.0.2",
    "jest-axe": "^6.0.0",
    "jest-environment-jsdom": "^28.0.2",
    "jest-watch-typeahead": "^1.1.0",
    "jest-when": "^3.5.1",
    "lint-staged": "^12.4.1",
    "news-fragments": "^1.14.4",
    "nock": "^13.2.4",
    "node-mocks-http": "^1.11.0",
    "prettier": "^2.6.2",
    "release-it": "^14.14.2",
    "slice-machine-ui": "^0.3.7",
    "std-mocks": "^1.0.1",
    "typescript": "4.5.5"
  }

And here is my jest config file:

const nextJest = require('next/jest');

const createJestConfig = nextJest({
  dir: './',
});

const customJestConfig = {
  testEnvironment: 'jest-environment-jsdom',
  setupFilesAfterEnv: ['<rootDir>/setupTests.ts', 'jest-axe/extend-expect'],
  testPathIgnorePatterns: ['/node_modules/', '/.next/', '/dist'],
  collectCoverage: false,
  transform: {
    '^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
  },
  transformIgnorePatterns: [
    '/node_modules/',
    '^.+\\.module\\.(css|sass|scss)$',
  ],
  collectCoverageFrom: [
    'config/*.ts',
    'slices/**/*.{js,jsx,ts,tsx}',
    'src/**/*.{js,jsx,ts,tsx}',
    '!slices/index.tsx',
    '!src/services/api.ts',
    '!**/*.d.ts',
    '!src/pages/_*.{js,jsx,ts,tsx}',
    '!**/node_modules/**',
    '!src/shared/static/**/*.{js,jsx,ts,tsx,json}',
    '!src/shared/interfaces/**/*',
    '!src/tests/**/*',
    '!src/**/interfaces/*',
  ],
  moduleNameMapper: {
    '^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
    '^@api/(.*)$': '<rootDir>/src/pages/api/$1',
    '^@clients/(.*)$': '<rootDir>/src/clients/$1',
    '^@components/(.*)$': '<rootDir>/src/components/$1',
    '^@config/(.*)$': '<rootDir>/config/$1',
    '^@contexts/(.*)$': '<rootDir>/src/contexts/$1',
    '^@pages/(.*)$': '<rootDir>/src/pages/$1',
    '^@layouts/(.*)$': '<rootDir>/src/layouts/$1',
    '^@repositories/(.*)$': '<rootDir>/src/repositories/$1',
    '^@schemas/(.*)$': '<rootDir>/src/schemas/$1',
    '^@services/(.*)$': '<rootDir>/src/services/$1',
    '^@shared/(.*)$': '<rootDir>/src/shared/$1',
    '^@slices/(.*)$': '<rootDir>/slices/$1',
    '^@tests/(.*)$': '<rootDir>/src/tests/$1',
    '^uuid$': '<rootDir>/node_modules/uuid/dist/index.js',
  },
};

module.exports = createJestConfig(customJestConfig);

Environment

  • OS: macOS Monterey 12.3.1
@GustavoSchuler GustavoSchuler changed the title [Jest 28] SyntaxError: Cannot use import statement outside a module [Jest 28][Yup Resolver] SyntaxError: Cannot use import statement outside a module Apr 27, 2022
@bluebill1049
Copy link
Member

This issue probably should belong to Jest as we didn't make any change to the module.

@bluebill1049 bluebill1049 added the dependencies Pull requests that update a dependency file label Apr 27, 2022
@GustavoSchuler
Copy link
Author

I truly understand that. But it will be nice if you can give any help 🙏

@jorisre
Copy link
Member

jorisre commented Apr 29, 2022

Can you provide a repo or a codesandbox please?

@GustavoSchuler
Copy link
Author

@jorisre I've created this repo with minimal project to reproduce the error.

@nemanjam
Copy link

nemanjam commented Apr 30, 2022

I got this error too for Zod resolver after updating to Jest 28.

 FAIL   Client tests  views/Home/Home.test.tsx
  ● Test suite failed to run

    Jest encountered an unexpected token

    Jest 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.

    Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.

    By default "node_modules" folder is ignored by transformers.

    Here's what you can do:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
     • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
     • 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/configuration
    For information about custom transformations, see:
    https://jestjs.io/docs/code-transformation

    Details:

    /home/username/Desktop/nextjs-prisma-boilerplate/node_modules/@hookform/resolvers/zod/dist/zod.module.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import{appendErrors as r}from"react-hook-form";import{validateFieldsNatively as e,toNestError as o}from"@hookform/resolvers";var n=function(e,o){for(var n={};e.length;){var s=e[0],t=s.code,i=s.message,a=s.path.join(".");if(!n[a])if("unionErrors"in s){var u=s.unionErrors[0].errors[0];n[a]={message:u.message,type:u.code}}else n[a]={message:i,type:t};if("unionErrors"in s&&s.unionErrors.forEach(function(r){return r.errors.forEach(function(r){return e.push(r)})}),o){var c=n[a].types,f=c&&c[s.code];n[a]=r(a,o,n,t,f?[].concat(f,s.message):s.message)}e.shift()}return n},s=function(r,s,t){return void 0===t&&(t={}),function(i,a,u){try{return Promise.resolve(function(o,n){try{var a=Promise.resolve(r["sync"===t.mode?"parse":"parseAsync"](i,s)).then(function(r){return u.shouldUseNativeValidation&&e({},u),{errors:{},values:r}})}catch(r){return n(r)}return a&&a.then?a.then(void 0,n):a}(0,function(r){return{values:{},errors:r.isEmpty?{}:o(n(r.errors,!u.shouldUseNativeValidation&&"all"===u.criteriaMode),u)}}))}catch(r){return Promise.reject(r)}}};export{s as zodResolver};
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      1 | import React, { FC } from 'react';
      2 | import { useForm } from 'react-hook-form';
    > 3 | import { zodResolver } from '@hookform/resolvers/zod';
        | ^
      4 | import { postSearchSchema } from 'lib-server/validation';
      5 | import { getErrorClass, withBem } from 'utils/bem';
      6 |

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1773:14)
      at Object.<anonymous> (components/SearchInput/SearchInput.tsx:3:1)

@georgekaran
Copy link

georgekaran commented May 1, 2022

Hey guys, I found a workaround for now as described in this comment.

First I create a new file called resolver.js under my .jest folder:

module.exports = (path, options) => {
    // Call the defaultResolver, so we leverage its cache, error handling, etc.
    return options.defaultResolver(path, {
        ...options,
        // Use packageFilter to process parsed `package.json` before
        // the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb)
        packageFilter: pkg => {
            // jest-environment-jsdom 28+ tries to use browser exports instead of default exports,
            // but @hookform/resolvers only offers an ESM browser export and not a CommonJS one. Jest does not yet
            // support ESM modules natively, so this causes a Jest error related to trying to parse
            // "export" syntax.
            //
            // This workaround prevents Jest from considering @hookform/resolvers module-based exports at all;
            // it falls back to CommonJS+node "main" property.
            if (pkg.name === '@hookform/resolvers') {
                delete pkg['exports'];
                delete pkg['module'];
            }
            return pkg;
        },
    });
};

Then in my jest.config.js, I've added as a resolver:

resolver: '<rootDir>/.jest/resolver.js',

Hope it helps you guys.

@GustavoSchuler
Copy link
Author

@georgekaran thank you so much! It worked for me!

@nico1510
Copy link

nico1510 commented May 2, 2022

It's also possible to manually import from the correct dist file e.g.
import { yupResolver } from '@hookform/resolvers/yup/dist/yup.js';

@GustavoSchuler
Copy link
Author

@nico1510 I've tried that, but didn't worked.

@nemanjam
Copy link

nemanjam commented May 2, 2022

It's also possible to manually import from the correct dist file e.g. import { yupResolver } from '@hookform/resolvers/yup/dist/yup.js';

I usually get circular dependencies when I do that.

@EmilioHerreraSoukup
Copy link

Is there an update on this?

@cdomigan
Copy link

Adding the offending modules (in my case "vest" and "@hookform/resolvers") to transformIgnorePatterns in jest.config.js solved this for me.

Eg. transformIgnorePatterns: ["/node_modules/(?!(vest|@hookform/resolvers))"],

@github-actions
Copy link
Contributor

🎉 This issue has been resolved in version 2.9.7 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dependencies Pull requests that update a dependency file released
Projects
None yet
8 participants