Search code examples
javascriptvuejs2babeljsvue-test-utils

Vue-test-utils can't find `Set()`: ReferenceError: Can't find variable: Set


Currently I'm trying to write some tests for a Vue component. However when I try to run the tests it errors out with the following message:

[BABEL] Note: The code generator has deoptimised the styling of /home/bono/dev/git_repos/hypernode-control-panel/hncp/vue/common/tests/unit/UpdateElementRadio.spec.es5.js as it exceeds the max of 500KB.
13 12 2018 15:52:18.339:INFO [karma-server]: Karma v3.1.3 server started at http://0.0.0.0:9876/
13 12 2018 15:52:18.341:INFO [launcher]: Launching browsers PhantomJS with concurrency unlimited
13 12 2018 15:52:18.344:INFO [launcher]: Starting browser PhantomJS
13 12 2018 15:52:18.594:INFO [PhantomJS 2.1.1 (Linux 0.0.0)]: Connected on socket fBfbs8v8mD1WMsLOAAAA with id 26571362
ERROR LOG: '[Vue warn]: Error in config.errorHandler: "ReferenceError: Can't find variable: Set"'
ERROR LOG: ReferenceError: Can't find variable: Set
patchRenderMixin
callHook
_init
VueComponent
createComponentInstanceForVnode
init
createComponent
createElm
patch
_update
updateComponent
get
Watcher
mountComponent
$mount
mount
shallowMount

callFn@http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:4550:25
run@http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:4542:13
runTest@http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:5078:13
http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:5196:19
next@http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:4992:16
http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:5002:11
next@http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:4926:16
http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:4970:9
timeslice@http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:82:27
ERROR LOG: '[Vue warn]: Error in beforeCreate hook: "ReferenceError: Can't find variable: Set"

found in

---> <UpdateElementRadio> at hncp/vue/common/src/components/UpdateElementRadio.vue
       <Root>'
ERROR LOG: ReferenceError: Can't find variable: Set
patchRenderMixin
callHook
_init
VueComponent
createComponentInstanceForVnode
init
createComponent
createElm
patch
_update
updateComponent
get
Watcher
mountComponent
$mount
mount
shallowMount

callFn@http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:4550:25
run@http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:4542:13
runTest@http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:5078:13
http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:5196:19
next@http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:4992:16
http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:5002:11
next@http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:4926:16
http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:4970:9
timeslice@http://localhost:9876/base/node_modules/mocha/mocha.js?840d4fbbcc65a16cec39f9e25af2ea6d2cff68ea:82:27

  UpdateElementRadio
    ✗ accepts label_text prop
    Can't find variable: Set
    patchRenderMixin
    callHook
    _init
    VueComponent
    createComponentInstanceForVnode
    init
    createComponent
    createElm
    patch
    _update
    updateComponent
    get
    Watcher
    mountComponent
    $mount
    mount
    shallowMount



PhantomJS 2.1.1 (Linux 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.041 secs / 0.01 secs)

npm ERR! Test failed.  See above for more details.

This is the test I'm trying to run (note that it might be a bit of a non-sense test, I'm just trying to get things to work first):

import Vue from 'vue'
import { expect } from 'chai';
import { shallowMount } from '@vue/test-utils';
import UpdateElementRadio from '../../src/components/UpdateElementRadio.vue';

describe('UpdateElementRadio', () => {
  it('accepts label_text prop', () => {
    shallowMount(UpdateElementRadio);
    const vm = new Vue(UpdateElementRadio).$mount();
    console.log(vm.props);
    expect(vm.props.label_text).to.equal(String);
  });
});

I'm not too experienced with setting this stuff up, but everything works fine when I don't try to use any mount function from vue-test-utils. I have a feeling there's something wrong with my babel setup or something, since it's a es2015 reference (at least I found it was trying to get it from a lib.es2015 file). I tried using different babel presets, none really worked (or came up with more errors). I also checked the docs for @babel/preset-env and I think it's the correct preset to use.

I'll share my karma config, webpack config and package.json as well:

karma.conf.js:

// Karma configuration
// Generated on Thu Dec 13 2018 11:28:18 GMT+0100 (Central European Standard Time)
let webpackConfig = require('./webpack.config.js');

module.exports = function (config) {
    config.set({

        // base path that will be used to resolve all patterns (eg. files, exclude)
        basePath: '',


        // frameworks to use
        // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
        frameworks: ['mocha'],


        // list of files / patterns to load in the browser
        files: [
            'hncp/vue/**/tests/unit/*.spec.js'
        ],


        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors: {
            'hncp/vue/**/tests/unit/*.spec.js': ['webpack', 'sourcemap', 'babel']
        },


        babelPreprocessor: {
            options: {
                presets: ['@babel/preset-env'],
                sourceMap: 'inline',
            },
            filename: function (file) {
                return file.originalPath.replace(/\.js$/, '.es5.js')
            },
            sourceFileName: function (file) {
                return file.originalPath;
            },
        },


        webpack: webpackConfig,


        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['spec'],


        plugins: [
            'karma-phantomjs-launcher',
            'karma-webpack',
            'karma-sourcemap-loader',
            'karma-mocha',
            'karma-spec-reporter',
            'karma-babel-preprocessor',
            'karma-chai',
        ],


        // web server port
        port: 9876,


        // enable / disable colors in the output (reporters and logs)
        colors: true,


        // level of logging
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_INFO,


        // enable / disable watching file and executing tests whenever any file changes
        autoWatch: true,


        // start these browsers
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: ['PhantomJS'],


        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: true,

        // Concurrency level
        // how many browser should be started simultaneous
        concurrency: Infinity,
    })
};

webpack.config.js:

var path = require('path'); var webpack = require('webpack'); var BundleTracker = require('webpack-bundle-tracker'); const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
    context: __dirname,
    mode: 'development',
    entry: {
        'hncp/order': ['./hncp/vue/order/src/main'],
    },
    output: {
        path: path.resolve('./hncp/static/webpack_bundles/'),
        filename: "[name].js"
    },
    module: {
        rules: [
            {  // Needed for loading Vue stuff
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            {  // Needed for loading things like <style> tags (used inside Vue stuff)
                test: /\.css$/,
                loader: 'style-loader!css-loader'
            },
            {  // Needed for loading things like png files (used inside Vue templates)
                test: /\.(eot|svg|png|ttf|woff|woff2)(\?\S*)?$/,
                loader: 'file-loader'
            },
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            }
        ]
    },

    plugins: [
        new BundleTracker({filename: './webpack-stats.json'}),
        new VueLoaderPlugin()
    ],
};

package.json:

{
    "scripts": {
        "test": "karma start --single-run"
    },
    "dependencies": {
        "babel-preset-es2015": "^6.24.1",
        "karma-cli": "^2.0.0",
        "karma-phantomjs-launcher": "^1.0.4",
        "vue-template-compiler": "^2.5.21"
    },
    "devDependencies": {
        "@babel/core": "^7.2.0",
        "@babel/preset-env": "^7.2.0",
        "@vue/test-utils": "^1.0.0-beta.27",
        "babel-loader": "^8.0.4",
        "chai": "^4.2.0",
        "css-loader": "^2.0.0",
        "file-loader": "^2.0.0",
        "karma": "^3.1.3",
        "karma-babel-preprocessor": "^8.0.0-beta.0",
        "karma-chai": "^0.1.0",
        "karma-chrome-launcher": "^2.2.0",
        "karma-mocha": "^1.3.0",
        "karma-sourcemap-loader": "^0.3.7",
        "karma-spec-reporter": "0.0.32",
        "karma-webpack": "^3.0.5",
        "mocha": "^5.2.0",
        "style-loader": "^0.23.1",
        "vue": "^2.5.21",
        "vue-loader": "^15.4.2",
        "vue-test-utils": "^1.0.0-beta.11",
        "webpack": "^4.27.1",
        "webpack-bundle-tracker": "^0.4.2-beta",
        "webpack-cli": "^3.1.2"
    }
}

If try using $mount from Vue that works fine. I.e.:

import Vue from 'vue'
import { expect } from 'chai';
import { mount } from '@vue/test-utils';
import UpdateElementRadio from '../../src/components/UpdateElementRadio.vue';

describe('UpdateElementRadio', () => {
  it('accepts label_text prop', () => {
    const vm = new Vue(UpdateElementRadio).$mount();
    console.log(vm);
    expect(vm.props.label_text).to.equal(String);
  });
});

I know it's a bit much to look at, but running out of ideas on how to fix this.


Edit

This is the UpdateElementRadio:

<template>
    <div class="float-label">
      <label>{{ label_text }}</label>
      <input type="radio" :name="name" v-on:change="$emit('update-value', value)"/>
      <slot></slot>
      <div class="update-element-radio-content" style="float:right">
        {{ value }}
      </div>
    </div>
</template>

<script>
export default {
  name: 'UpdateElementRadio',
  props: {
    label_text: String,
    name: String,
    value: Number
  },
};
</script>

Solution

  • So I figured out why this was happening when, it turns out the culprit was PhantomJS. Since it's no longer being actively developed it also means it does not support ES6. See this issue on Github for the same problem I was experiencing.

    So instead I decided to use Chrome for my tests instead, I made the following changes:

    In karma.conf.js:

    //Other config...
    
    plugins: [
                'karma-chrome-launcher',
                ...
             ]
    
    //Other config...
    
    browsers: ['ChromeHeadless'],
    
    //Other config
    

    In package.json make sure the karma-chrome-launcher is set:

    {
      //other
      "devDependencies": {
        // Other...
        "karma-chrome-launcher": "^2.2.0",
        // Other...
      }
    }