Debugging Mocha Setup for Vue Project
I am working on a Vue project with Webpack 4 and Babel 7.
At the point of writing this post, they are Webpack 4.12.0 and Babel 7.0.0-rc.1.
When setting up Mocha with @vue/test-util
, I have encountered a number of bugs.
After a number of rounds try, my test script in package.json
becomes:
"scripts": {
"test": "cross-env NODE_ENV=test nyc mocha-webpack --full-trace --recursive --require @babel/register --require ignore-styles --require test/setup.js test/**/*.spec.js"
}
Is it necessary or overkill? Will all the additional flags be the solution to problems, or the cause of new errors?
Probably yes.
Debug 1: Filename
Cannot find module 'my-path/main.[hash].js?[hash]'
at Function.Module._resolveFilename (module.js)
This is because of the hash after the output filename. Check webpack.config.js
config output.filename
. If the hash is within the filename, it works fine.
Debug 2: Styles
.my-class-name[data-v-hash] {
^
SyntaxError: Unexpected token .
at createScript (vm.js)
Check whether you have extract CSS plugins e.g. MiniCssExtractPlugin.loader
enabled for test
environment. If yes, this may be the cause of the error.
Check webpack.config.js
config module.rules
for related settings.
For my project, I uses Vue templates with scss.
- For
vue-loader
(test: /\.vue$/
), itsoptions.extractCSS
is alwaystrue
and not causing the problem; - For
test: /\.css$/
, havingMiniCssExtractPlugin.loader
is not causing the problem; - For
test: /\.scss$/
, havingMiniCssExtractPlugin.loader
leads to the problem; (More related problems see below) - For
test: /\.less$/
which I only used aless
file to overwrite iView’s default theme, havingMiniCssExtractPlugin.loader
is not causing the problem.
Debug 3: No Error but No Tests 1
There are tests but “0 passing (0ms)
“ and “Tests completed successfully
“ with no Error.
Strangely, if have ignore-styles
installed and included a --require ignore-styles
flag, and having MiniCssExtractPlugin.loader
enabled for test: /\.scss$/
, Error will not appear but nor the tests can be carried out. ignore-styles
seems not needed but it would result in non-debuggable result when meets MiniCssExtractPlugin.loader
.
I have stuck on this problem for quite a long time, as there is no hint on this issue.
Debug 4: No Error but No Tests 2
It only shows:
WEBPACK Compiled successfully in 2459ms
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 0 | 0 | 0 | 0 | |
----------|----------|----------|----------|----------|-------------------|
The latest stable version of mocha-webpack
which only for Webpack 2 and 3. (at the point of writing, its 1.1.0). If you are using Webpack 4, need install the next version (2.0.0+).
npm i mocha-webpack@next --save-dev
This is regardless whether you are using @vue/test-utils
or vue-test-utils
.
Debug 5: TypeError
for All Tests
Tests are properly detected, but all having the following TypeError
.
TypeError: Object(...) is not a function
Solution: Please use @vue/test-utils
instead of vue-test-utils
.
Debug 5: Unexpected token import
1
(function (exports, require, module, __filename, __dirname) { import { shallowMount } from '@vue/test-utils';
^^^^^^
SyntaxError: Unexpected token import
This may becuase of an additional --require
flag in you test script:
"scripts": {
"test": "cross-env NODE_ENV=test nyc mocha-webpack --require test/setup.js --require test/**/*.spec.js"
}
The second --require
before the test/**/*.spec.js
should be removed.
Debug 6: Unexpected token import
2
Based on some people’s suggestion, babel
may be added to the test script as --require @babel/register
:
"scripts": {
"test": "cross-env NODE_ENV=test nyc mocha-webpack --require @babel/register --require test/setup.js test/**/*.spec.js"
}
Sometimes there may be warning for import
again, which is clearly from @babel
.
(function (exports, require, module, __filename, __dirname) { import _Promise from "@babel/runtime-corejs2/core-js/promise";
^^^^^^
SyntaxError: Unexpected token import
This would need specify the modules
as "commonjs"
in .babelrc
or babel.config.js
:
"env":{
"test": {
"presets": {
/* other presets */
"modules": "commonjs"
},
"plugins": ["istanbul", ...]
}
}
Alternatively, @babel/plugin-transform-modules-commonjs
plugin can be included:
"env":{
"test": {
"presets": {
/* other presets */
"modules": false
},
"plugins": ["istanbul","@babel/plugin-transform-modules-commonjs", ...]
}
}
It should also work if you do both.
Debug 6: Cannot find module
or Unexpected token <
Error: Cannot find module '@components/myVueComponent.vue'
at Function.Module._resolveFilename (module.js:536:15)
'@components'
is an alias I set in webpack.config.js
pointing to the folder cotaining my Vue component files.
This error may result from the double --require
flags (See Debug 5) when @babel/register
is also required.
"scripts": {
"test": "cross-env NODE_ENV=test nyc mocha-webpack --require @babel/register --require test/setup.js --require test/**/*.spec.js"
}
After seeing above error, one natually would change the path for the Vue components path from @components/myVueComponent.vue'
to something like '../my-path-to-components/myVueComponent.vue'
. The file you wish to test can be found, but whatever in the webpack.config.js
would not take effect such as vue-loader
, and would result in the following error:
(function (exports, require, module, __filename, __dirname) { <template>
^
SyntaxError: Unexpected token <
at createScript (vm.js:80:10)
Final
Eventually, I found out that even I don’t have all these fancy flags, everything still works:
"scripts": {
"test": "cross-env NODE_ENV=test nyc mocha-webpack --require test/setup.js test/**/*.spec.js",
}
As long as:
I am using
mocha-webpack
next version (2.0.0) instead of the latest 1.1.0.I am importing
@vue/test-utils
instead ofvue-test-utils
.Make sure I don’t include
MiniCssExtractPlugin.loader
for myscss
loaders in test environment.I should not have an additional
--require
flag beforetest/**/*.spec.js
in the test script.--require @babel/register
seems not necessary for my case. However if it is included, make sure themodule
is specified as"commonjs"
in.babelrc
orbabel.config.js
, or@babel/plugin-transform-modules-commonjs
is included as one of the plugins for testenv
.