jest: Jest cannot understand token "?" from @babel/plugin-proposal-optional-chaining

💬 Questions and Help

My project is Vue 2.x. I am using @babel/plugin-proposal-optional-chaining and I have a line of code in my component.vue file that uses “?”

this.$refs.refreshBtn?.$el.addEventListener("animationend", _ => { ... });

which works well when run the app. However, my unit tests are failing because it cannot recognize the token “?”

  unknown: Unexpected token (149:26)

      Jest encountered an unexpected token
      ......
      ......
      ......
Details:
        147 |
        148 |    
      > 149 |     this.$refs.refreshBtn?.$el.addEventListener("animationend", _ => {
            |                           ^
        150 |       this.refreshClicked = false;
        151 |     });
        152 |

my babel.config.js

module.exports = {
  presets: [
    [
      '@vue/app',
      {
        useBuiltIns: "entry",
      }
    ],

  ],

  plugins: [
    '@babel/plugin-proposal-optional-chaining'
  ],
 
  sourceType: 'unambiguous'
};

my partial package.json:

    "scripts": {    
        "test:unit": "vue-cli-service test:unit --no-cache"
    },
    "dependencies": {
        "@casl/ability": "^2.5.1",
        "@casl/vue": "^0.2.0"
        "axios": "^0.18.1",
        "babel-polyfill": "^6.26.0",
        "base64-js": "^1.3.0",
        "commonjs": "0.0.1",
        "echarts": "^4.2.0-rc.2",
        "element-ui": "^2.4.4",
        "eureka-js-client": "^4.4.1",
        "express": "^4.16.3",
        "express-actuator": "^1.1.0",
        "google-protobuf": "3.6.1",
        "grpc": "^1.22.2",
        "gsap": "^1.20.4",
        "jasmine-core": "^3.2.1",
        "jest-junit": "^4.0.0",
        "js-cookie": "^2.2.0",
        "lodash": "^4.17.15",
        "material-design-icons": "^3.0.1",
        "moment": "^2.22.2",
        "moment-timezone": "^0.5.21",
        "normalize.css": "^8.0.0",
        "npm": "^6.4.1",
        "nprogress": "^0.2.0",
        "platform": "^1.3.5",
        "requirejs": "^2.3.5",
        "sjcl": "^1.0.8",
        "uuid": "^3.3.2",
        "vue": "^2.5.21",
        "vue-acl": "^3.0.4",
        "vue-animate-number": "^0.4.2",
        "vue-content-loader": "^0.2.1",
        "vue-echarts": "^3.1.3",
        "vue-echarts-v3": "^1.0.19",
        "vue-material": "^1.0.0-beta-10.1",
        "vue-router": "^3.0.1",
        "vue-toasted": "^1.1.24",
        "vue2-dropzone": "^3.5.2",
        "vuex": "^3.0.1",
        "vuex-persistedstate": "^2.5.2"
    },
    "devDependencies": {
        "@babel/plugin-proposal-optional-chaining": "^7.2.0",
        "@vue/cli-plugin-babel": "^3.9.2",
        "@vue/cli-plugin-e2e-nightwatch": "^3.9.2",
        "@vue/cli-plugin-eslint": "^3.9.2",
        "@vue/cli-plugin-unit-jest": "^3.9.0",
        "@vue/cli-service": "^3.9.3",
        "@vue/test-utils": "^1.0.0-beta.25",
        "autoprefixer": "^7.1.2",
        "babel-core": "7.0.0-bridge.0",
        "babel-eslint": "^10.0.1",
        "babel-helper-vue-jsx-merge-props": "^2.0.3",
        "babel-jest": "^23.6.0",
        "babel-loader": "^7.1.1",
        "babel-plugin-add-module-exports": "^0.2.1",
        "babel-plugin-dynamic-import-node": "^1.2.0",
        "babel-plugin-syntax-jsx": "^6.18.0",
        "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
        "babel-plugin-transform-runtime": "^6.22.0",
        "babel-plugin-transform-vue-jsx": "^3.5.0",
        "babel-preset-env": "^1.3.2",
        "babel-preset-es2015": "^6.24.1",
        "babel-preset-stage-2": "^6.22.0",
        "babel-register": "^6.22.0",
        "chalk": "^2.0.1",
        "chromedriver": "^76.0.0",
        "copy-webpack-plugin": "^4.0.1",
        "cross-spawn": "^5.0.1",
        "csp-html-webpack-plugin": "^2.4.0",
        "css-loader": "^0.28.0",
        "detect-browser": "^2.5.1",
        "eslint": "^5.8.0",
        "eslint-config-google": "^0.9.1",
        "eslint-config-standard": "^10.2.1",
        "eslint-friendly-formatter": "^3.0.0",
        "eslint-loader": "^1.7.1",
        "eslint-plugin-import": "^2.7.0",
        "eslint-plugin-node": "^5.2.0",
        "eslint-plugin-promise": "^3.4.0",
        "eslint-plugin-standard": "^3.0.1",
        "eslint-plugin-vue": "^5.0.0",
        "extract-text-webpack-plugin": "^3.0.0",
        "file-loader": "^1.1.4",
        "friendly-errors-webpack-plugin": "^1.6.1",
        "html-webpack-plugin": "^2.30.1",
        "jest": "^23.5.0",
        "jest-localstorage-mock": "^2.2.0",
        "jest-serializer-vue": "^0.3.0",
        "jest-transform-stub": "^1.0.0",
        "jsdom": "^12.0.0",
        "jsdom-global": "^3.0.2",
        "karma": "^3.0.0",
        "karma-chrome-launcher": "^2.2.0",
        "karma-firefox-launcher": "^1.1.0",
        "karma-ie-launcher": "^1.0.0",
        "karma-jasmine": "^1.1.2",
        "karma-webpack": "^3.0.0",
        "nightwatch": "^0.9.21",
        "node-notifier": "^5.1.2",
        "node-sass": "^4.12.0",
        "optimize-css-assets-webpack-plugin": "^3.2.0",
        "ora": "^1.2.0",
        "portfinder": "^1.0.13",
        "postcss-import": "^11.0.0",
        "postcss-loader": "^2.0.8",
        "postcss-url": "^7.2.1",
        "rimraf": "^2.6.0",
        "sass-loader": "^7.0.1",
        "selenium-server": "^3.12.0",
        "semver": "^5.3.0",
        "shelljs": "^0.7.6",
        "uglifyjs-webpack-plugin": "^1.1.1",
        "url-loader": "^0.5.8",
        "vue-jest": "^1.0.2",
        "vue-loader": "^15.5.1",
        "vue-style-loader": "^3.0.1",
        "vue-template-compiler": "^2.5.21",
        "webpack": "^4.28.1",
        "webpack-bundle-analyzer": "^2.9.0",
        "webpack-dev-server": "^2.11.1",
        "webpack-merge": "^4.1.0"
    },
   "eslintConfig": {
        "root": true,
        "env": {
            "node": true
        },
        "extends": [
            "plugin:vue/essential",
            "eslint:recommended"
        ],
        "rules": {},
        "parserOptions": {
            "parser": "babel-eslint"
        }
    },
    "postcss": {
        "plugins": {
            "autoprefixer": {}
        }
    },
    "browserslist": [
        "> 1%",
        "last 2 versions",
        "not ie <= 8"
    ]

my jest.config.js

module.exports = {
    moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
    transform: {
        '^.+\\.vue$': 'vue-jest',
        '.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$':
            'jest-transform-stub',
        '^.+\\.(js|jsx)?$': 'babel-jest'
    },
    moduleNameMapper: {
        '^@/(.*)$': '<rootDir>/src/$1'
    },
    snapshotSerializers: ['jest-serializer-vue'],
    testMatch: [
        '<rootDir>/(tests/unit/**/*.test.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx))'
    ],
    transformIgnorePatterns: ['<rootDir>/node_modules/']
};

I am pretty new to Babel and Webpack…not sure what is the correct way to make Jest to be able to recognize the plugins that I use for my project. I am thinking it is because the .vue file is processed by vue-jest which does not take babel config… if that is the case I don’t know how to fix it…

If someone knows please help…appreciate it…

Please note that this issue tracker is not a help forum and this issue will be closed.

For questions or help please see:

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 20
  • Comments: 15 (2 by maintainers)

Most upvoted comments

Any updates on this?

Another thing that works for ts-jest users, without using Babel but by changing the target of the TypeScript compiler to anything lower than ES2020 or ESNext (see https://github.com/kulshekhar/ts-jest/issues/1283#issuecomment-592711385):

globals: {
  'ts-jest': {
    tsConfig: {
      target: 'ES2019'
    }
  }
}

I actually think I found a solution from this comment: https://github.com/kulshekhar/ts-jest/issues/1283#issuecomment-552147794. Adding this to my jest.config.js seems to work for me, though it does open up a number of other issues for me.:

  globals: {
    'ts-jest': {
      babelConfig: true,
    }
  },

Or if you use a babel.config.js instead:

globals: {
        'ts-jest': {
            babelConfig: 'babel.config.js',
        }
    },

Does not work:

    globals: {
        'ts-jest': {
            babelConfig: true,
        }
    },

But this does:

    globals: {
        'ts-jest': {
            babelConfig: '.babelrc',
        }
    },

Duno why everyting is finding .babelrc but ts-jest. So this problem is related to ts-jest

I have the same problem. Unit Tests fail because of

    Add @babel/plugin-proposal-optional-chaining (https://git.io/vb4Sk) to the 'plugins' section of your Babel config to enable transformation.

Jest 24.9.0 (25.0.0 fails too)

.babelrc

{
    "presets": [
        [
            "@babel/preset-env",
            {
                "useBuiltIns": "usage",
                "shippedProposals": true,
                "corejs": 3
            }
        ]
    ],
    "plugins": [
        ["transform-react-jsx", {"pragma": "h"}],
        "@babel/plugin-syntax-dynamic-import",
        "@babel/plugin-proposal-optional-chaining"
    ]
}

jest.config.js

module.exports = {
    preset: 'ts-jest',
    testEnvironment: 'jsdom',
    roots: [
        "<rootDir>/src"
    ],
    collectCoverageFrom: [
        "<rootDir>/src/**/*.tsx",
        "<rootDir>/src/**/*.ts",
        "!<rootDir>/src/test/**",
        "!<rootDir>/src/types/**",
    ],
    coverageReporters: [
        "text-summary",
        "html",
    ],
    coverageDirectory: "./coverage/",
    collectCoverage: true,
    moduleDirectories: [
        "src",
        "node_modules",
    ],
    moduleFileExtensions: [
        "ts",
        "tsx",
        "js",
    ],
    moduleNameMapper: {
        "\\.(jpg|png|otf|svg|ttf|woff|woff2)$": "<rootDir>/src/test/stubs/file.js",
        "\\.(css)$": "identity-obj-proxy",
    },
    snapshotSerializers: [
        "preact-render-spy/snapshot",
    ],
    snapshotResolver: "<rootDir>/src/test/snapshot-resolver.js",
};

I will try to setup a minimal repo. The workaround does not work for me:

  globals: {
    'ts-jest': {
      babelConfig: true,
    }
  },

Then my imports don’t work anymore and I got muuuch more errors.