I have a more-or-less vanilla Laravel + Vue.js app and I am trying to do some JS testing with Karma and Jasmine. If I try to use () => {}
style functions or keywords like const
in my tests, they fail with Unexpected token errors, however, I do not have a problem using the import
keyword and I am able to transpile and work with .vue
files without issue.
A trivial assertion like
expect(true).toBe(true);
Seems to work fine (see last line)
$ ./node_modules/karma/bin/karma start
22 11 2016 11:09:23.250:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
22 11 2016 11:09:23.254:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
22 11 2016 11:09:23.263:INFO [launcher]: Starting browser PhantomJS
22 11 2016 11:09:24.025:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket /#U1dCZ7i3UtsC-M3_AAAA with id 84458811
PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 1 of 1 SUCCESS (0.004 secs / 0.002 secs)
Then, if I add a trivial const
declaration to my test function
const myVar = 1
expect(true).toBe(true);
I get an error:
$ ./node_modules/karma/bin/karma start
22 11 2016 11:10:00.741:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
22 11 2016 11:10:00.745:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
22 11 2016 11:10:00.752:INFO [launcher]: Starting browser PhantomJS
22 11 2016 11:10:01.659:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket /#Gwh8ywcLStrKf-ljAAAA with id 78654911
PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR
SyntaxError: Unexpected token 'const'
at tests/unit/Example.spec.js:165
Instead, if I try to cause a syntax error
const = 1 // syntax error
expect(true).toBe(true);
then Babel complains (on the first line, before Karma or PhantomJS boots up)
22 11 2016 11:07:00.079:ERROR [preprocessor.babel]: /Users/crcarter/Software/CropPlanning/cps-php/resources/assets/js/tests/unit/Example.spec.js: Unexpected token (8:15)
at /Users/crcarter/Software/CropPlanning/cps-php/resources/assets/js/tests/unit/Example.spec.js
22 11 2016 11:07:00.090:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
22 11 2016 11:07:00.091:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
22 11 2016 11:07:00.101:INFO [launcher]: Starting browser PhantomJS
22 11 2016 11:07:00.986:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket /#9Y6QLVxtJ57qRrgDAAAA with id 56249014
PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR
You need to include some adapter that implements __karma__.start method!
This seems to imply that the Example.spec.js
file is being parsed/transpiled by Babel, but that the transpiled version is not being delivered to the browser properly, even though the Example.vue
file seems to be delivered properly.
What can I do to be able to get things like const
and () => {}
to work in my tests? Thank you.
Here are the relevant files:
resources/assets/js/components/Example.vue
resources/assets/js/tests/unit/Example.spec.js
karma.conf.js
package.json
// Example.vue
<template>
<div class="container">
</div>
</template>
<script>
export default {
mounted() {
console.log('Component ready.')
},
data() {
return { input: '# Hello!' }
}
}
</script>
// Example.spec.js
import Example from '../../components/Example.vue';
describe('Example', function () {
it('should set correct default data', function () {
const myVar = 1
// trivial assertions
expect(true).toBe(true);
});
});
// karma.conf.js
var path = require('path')
var basePath = './resources/assets/js/';
module.exports = function(config) {
config.set({
frameworks: ['jasmine'],
port: 9876,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['PhantomJS'],
singleRun: true,
basePath: basePath,
webpack: {
resolve: {
extensions: ['', '.js', '.vue'],
fallback: [path.join(__dirname, 'node_modules')],
},
resolveLoader: {
fallback: [path.join(__dirname, 'node_modules')]
},
module: {
loaders: [
{ test: /\.vue$/, loader: 'vue' },
{ test: /\.js$/, loader: 'babel',
include: basePath,
}
]
}
},
webpackMiddleware: {
noInfo: true,
stats: 'errors-only'
},
files: [
{ pattern: 'tests/**/*.spec.js', watched: false },
],
exclude: [],
preprocessors: {
'app.js': ['webpack', 'babel'],
'tests/**/*.spec.js': [ 'babel', 'webpack' ]
},
})
}
And package.json
{
"private": true,
"scripts": {
"prod": "gulp --production",
"dev": "gulp watch"
},
"devDependencies": {
"bootstrap-sass": "^3.3.7",
"gulp": "^3.9.1",
"jquery": "^3.1.0",
"laravel-elixir": "^6.0.0-11",
"laravel-elixir-vue-2": "^0.2.0",
"laravel-elixir-webpack-official": "^1.0.2",
"lodash": "^4.16.2",
"vue": "^2.0.1",
"vue-resource": "^1.0.3"
},
"dependencies": {
"jasmine-core": "^2.5.2",
"karma": "^1.3.0",
"karma-babel-preprocessor": "^6.0.1",
"karma-chrome-launcher": "^2.0.0",
"karma-firefox-launcher": "^1.0.0",
"karma-jasmine": "^1.0.2",
"karma-phantomjs-launcher": "^1.0.2",
"karma-webpack": "^1.8.0"
}
}
The comments by @craig_h and @PanJunjie set me on the track of looking at the configuration for karma-babel-preprocessor
, which led me to the config for karma-webpack
. I'm still not sure what was causing the original problem, but it appears that my webpack config for Karma was incorrect or incomplete, and was failing silently. I added babel-loader
and babel-preset-es2015
packages via
yarn add babel-loader babel-preset-es2015
And then I redid and cleaned up my karma.conf.js
as such:
module.exports = function(config) {
config.set({
singleRun: false, // false => watch for changes and rerun tests
autoWatch: true, // enable / disable watching files & then run tests
frameworks: ['jasmine'],
browsers: ['PhantomJS'],
// Options: LOG_DISABLE, LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG
logLevel: config.LOG_INFO,
basePath: './resources/assets/js/',
files: [
{ pattern: 'tests/**/*.spec.js', watched: false },
],
// how to process files before serving them to the browser for testing
preprocessors: {
'app.js': ['webpack'],
'tests/**/*.spec.js': ['webpack'],
},
webpack: {
module: {
loaders: [
{ test: /\.vue$/, loader: 'vue' },
{ test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: { presets: ['es2015'] }
}
]
},
// make sure to use the stand-alone version of Vue
resolve: {
alias: {vue: 'vue/dist/vue.js'}
}
},
webpackMiddleware: {
noInfo: true,
stats: 'errors-only'
}
});
};
My package.json
now looks like this:
{
"private": true,
"scripts": {
"prod": "gulp --production",
"dev": "gulp watch"
},
"devDependencies": {
"bootstrap-sass": "^3.3.7",
"gulp": "^3.9.1",
"jquery": "^3.1.0",
"laravel-elixir": "^6.0.0-11",
"laravel-elixir-vue-2": "^0.2.0",
"laravel-elixir-webpack-official": "^1.0.2",
"lodash": "^4.16.2",
"vue": "^2.0.1",
"vue-resource": "^1.0.3"
},
"dependencies": {
"babel-loader": "^6.2.8",
"babel-preset-es2015": "^6.18.0",
"jasmine-core": "^2.5.2",
"karma": "^1.3.0",
"karma-babel-preprocessor": "^6.0.1",
"karma-chrome-launcher": "^2.0.0",
"karma-firefox-launcher": "^1.0.0",
"karma-jasmine": "^1.0.2",
"karma-phantomjs-launcher": "^1.0.2",
"karma-webpack": "^1.8.0"
}
}
With all of that, I can now use all of the ES2015 goodness like const
and () => {}
. Sorry to answer my own question, but I hope this helps someone else that encounters a similar issue.
I had a similar problem (though not identical; your configuration is pretty specific). I was also using Vue, karma, webpack, and phantomjs (as configured in the vue-Webpack template).
However, my problem is that I was defining const
in a helper file that was getting imported into my app. When I changed const
to var
in that file, the tests were able to run.(It didn't matter whether or not const
was used in other files that were already within the src
directory).
This problem was fixed when I moved this helper file into my src
folder or one of its subdirectories. I'm too much of a novice to know why this solved the problem, but I'm guessing that babel wasn't configured to work in the root folder, and was only pointed towards the src
folder.
Hopefully this is helpful for others as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With