Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue Unit Test Error: vuex requires a Promise polyfill in this browser

I created a project using vue-cli and added vuex and vue-router in it. I am trying to setup a unit test for it, but I am getting following error. Without Vuex, it used to work.

PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR

Error: [vuex] vuex requires a Promise polyfill in this browser.

at webpack:///~/vuex/dist/vuex.js:145:0 <- index.js:9871

The following are the relevant package versions:

"babel-core": "^6.0.0",
"babel-eslint": "^7.0.0",
"babel-loader": "^6.0.0",
"vue": "^2.1.0",
"vue-router": "^2.0.3",
"vuex": "^2.0.0",
"vuex-router-sync": "^3.0.0"
"karma": "^1.3.0",
"karma-coverage": "^1.1.1",
"karma-mocha": "^1.2.0",
"karma-phantomjs-launcher": "^1.0.0",
"karma-sinon-chai": "^1.2.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-spec-reporter": "0.0.26",
"karma-webpack": "^1.7.0",
"webpack": "^1.13.2",
"webpack-dev-middleware": "^1.8.3",
"webpack-hot-middleware": "^2.12.2",
"webpack-merge": "^0.14.1"

The following is karma.conf.js:

// This is a karma config file. For more details see
//   http://karma-runner.github.io/0.13/config/configuration-file.html
// we are also using it with karma-webpack
//   https://github.com/webpack/karma-webpack

var path = require('path')
var merge = require('webpack-merge')
var baseConfig = require('../../build/webpack.base.conf')
var utils = require('../../build/utils')
var webpack = require('webpack')
var projectRoot = path.resolve(__dirname, '../../')

var webpackConfig = merge(baseConfig, {
  // use inline sourcemap for karma-sourcemap-loader
  module: {
    loaders: utils.styleLoaders()
  },
  devtool: '#inline-source-map',
  vue: {
    loaders: {
      js: 'isparta'
    }
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': require('../../config/test.env')
    })
  ]
})

// no need for app entry during tests
delete webpackConfig.entry

// make sure isparta loader is applied before eslint
webpackConfig.module.preLoaders = webpackConfig.module.preLoaders || []
webpackConfig.module.preLoaders.unshift({
  test: /\.js$/,
  loader: 'isparta',
  include: path.resolve(projectRoot, 'src'),
  exclude: /test\/unit|node_modules/
})

// only apply babel for test files when using isparta
webpackConfig.module.loaders.some(function (loader, i) {
  if (loader.loader === 'babel') {
    loader.include = path.resolve(projectRoot, 'test/unit')
    return true
  }
})

module.exports = function (config) {
  config.set({
    // to run in additional browsers:
    // 1. install corresponding karma launcher
    //    http://karma-runner.github.io/0.13/config/browsers.html
    // 2. add it to the `browsers` array below.
    browsers: ['Chrome'],
    frameworks: ['mocha', 'sinon-chai'],
    reporters: ['spec', 'coverage'],
    files: ['./index.js'],
    preprocessors: {
      './index.js': ['webpack', 'sourcemap']
    },
    webpack: webpackConfig,
    webpackMiddleware: {
      noInfo: true
    },
    coverageReporter: {
      dir: './coverage',
      reporters: [
        { type: 'lcov', subdir: '.' },
        { type: 'text-summary' }
      ]
    }
  })
}
like image 942
Saurabh Avatar asked Nov 24 '16 10:11

Saurabh


2 Answers

Using Babel polyfill solved the problem. Here are the steps what I did:

Installing Babel Polyfill:

npm install --save-dev babel-polyfill

then include the polyfill file before your source and test files within the files section of your karma.conf.js:

files: [
  '../node_modules/babel-polyfill/dist/polyfill.js',
  'index.js'
],
like image 110
Saurabh Avatar answered Nov 03 '22 06:11

Saurabh


If you think babel-polyfill is too big, you could just include the es6-promise polyfill:

files: [
  '../node_modules/es6-promise/dist/es6-promise.auto.js',
  'index.js'
],

On the other hand, if you are not sure whether your site visitors' browsers have built-in Promise support, you could include the polyfill in your entry fill, main.js:

import 'es6-promise/auto'

EDIT:

Good news! Chrome can run in headless mode since version 59. So you could run your unit tests in headless Chrome now instead of PhantomJS.

For vue-cli/webpack generated projects, you could follow these steps:

  • Install karma-chrome-launcher via npm or yarn.
  • You could also remove karma-phantomjs-launcher, karma-phantomjs-shim, phantomjs-prebuilt from your project. They are for PhantomJS.
  • In test/unit/karma.conf.js, change browsers field to ['ChromeHeadless'], and remove 'phantomjs-shim' from frameworks field.

Here's my karma.conf.js, no polyfill anymore:

var webpackConfig = require('../../build/webpack.test.conf')

module.exports = function(config) {
  config.set({
    // to run in additional browsers:
    // 1. install corresponding karma launcher
    //    http://karma-runner.github.io/0.13/config/browsers.html
    // 2. add it to the `browsers` array below.
    browsers: ['ChromeHeadless'],
    frameworks: ['mocha', 'sinon-chai'],
    reporters: ['spec', 'coverage'],
    files: ['./index.js'],
    preprocessors: {
      './index.js': ['webpack', 'sourcemap']
    },
    webpack: webpackConfig,
    webpackMiddleware: {
      noInfo: true
    },
    coverageReporter: {
      dir: './coverage',
      reporters: [
        { type: 'lcov', subdir: '.' },
        { type: 'text-summary' }
      ]
    }
  })
}

The reason to do so:

  1. Chrome 59 is the latest stable release, it supports most ES6 features, even some from ES7/8, without polyfill.
  2. PhantomJS hasn't been updated since about 18 months ago. It doesn't support many new features since ES specs are moving so fast.
  3. The author of PhantomJS has announced to discontinue.
like image 40
Leo Avatar answered Nov 03 '22 06:11

Leo