I'm trying to introduce testing with Jest into an app build with Vue. I've run
vue add unit-jest
and similarly to what testing single file components with Jest guide suggests, created the following simple test file (Paginator.spec.js in the same folder as Paginator.vue, that is /src/components
):
import { mount } from '@vue/test-utils'
import Paginator from "./Paginator.vue";
describe('Paginator', () => {
it('is a Vue instance', () => {
const wrapper = mount(Paginator);
// const a = 2;
expect(wrapper.isVueInstance()).toBeTruthy();
// expect(a).toBe(2);
})
});
Initially I had some issue with Jest itself not finding the file. Later I've changed in jest.config.js
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
to
testMatch: [
'**/*.spec.(js|ts)|**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
and after some weird glitches I got it finding the file (did git stash
, made sure that the app is working, then git stash pop
and it started to find the files).
But I still has the issue of Jest not recognizing import
. I get the following errors regardless I run jest
or npm test
(which is vue-cli-service test:unit
). A simple test like this works normally:
describe('tests of components', () => {
it('work', () => {
const a = 2;
expect(a).toBe(2);
})
});
but the test shown in the beginning of the question brings
Test suite failed to run
[...]({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import { mount } from '@vue/test-utils' ^ SyntaxError: Unexpected token { at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)
and if I switch the import order to
import Paginator from "./Paginator.vue";
import { mount } from '@vue/test-utils'
I get
● Test suite failed to run
C:\NNTC\medkiosk\src\components\Paginator.spec.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import Paginator from "./Paginator.vue";
^^^^^^^^^
SyntaxError: Unexpected identifier
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)
(I haven't changed jest.config.js in any fashion other than extending the regexp as shown above)
What's the problem here? Looks like Jest doesn't recognize import
as a language feature.. is this a webpack misconfiguration issue? Some loader is missing?
There's no webpack config file in the project because it was started with vue cli. One guy claims that the actual config is in
node_modules/@vue/cli-service/webpack.config.js
it's not that helpful:// this file is for cases where we need to access the // webpack config as a file when using CLI commands. let service = process.VUE_CLI_SERVICE if (!service || process.env.VUE_CLI_API_MODE) { const Service = require('./lib/Service') service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd()) service.init(process.env.VUE_CLI_MODE || process.env.NODE_ENV) } module.exports = service.resolveWebpackConfig()
(resolveWebpackConfig seems to be this one)
As I understand this, tweaking internal webpack config is done inside vue.config.js, but I don't know that is the initial config to start modifying and also what is actually should be tweaked
I've tried
npm i babel-jest
(not sure if it's installed already by vue cli), adding.babelrc
with{ "presets": ["latest"] }
similarly to what a person with a similar problem did, tried adding to vue.config.js the part the other guy from that thread suggested:configureWebpack: { module: { rules: [ { loader: "babel-loader", options: { presets: ["latest"] } } ] } },
and also some suggestions from here and for now I'm out of ideas
below you can see all the config files
a bonus: if I rename the Paginator.spec.js into Paginator.spec.ts makes Jest show this instead:
● Test suite failed to run Passing cached plugin instances is not supported in babel.loadPartialConfig() at forEach.item (node_modules/@babel/core/lib/config/partial.js:120:13) at Array.forEach (<anonymous>) at loadPartialConfig (node_modules/@babel/core/lib/config/partial.js:118:27) at TsJestTransformer.process (node_modules/ts-jest/dist/ts-jest-transformer.js:110:32)
Can anyone suggest how to fix the config? Or how to debug it? From what I've read so far it seems that probably Jest should get a file piped through babel-loader which doesn't seem to be the case, but I'm not sure. I know, I probably don't know enough about how Webpack works exactly, so hints what to learn are welcome as well, I'll post the solution when I find one.
jest.config.js:
module.exports = {
moduleFileExtensions: [
'js',
'jsx',
'json',
'vue',
'ts',
'tsx'
],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
'^.+\\.tsx?$': 'ts-jest'
},
transformIgnorePatterns: [
'/node_modules/'
],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: [
'jest-serializer-vue'
],
testMatch: [
'**/*.spec.(js|ts)|**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
testURL: 'http://localhost/',
watchPlugins: [
'jest-watch-typeahead/filename',
'jest-watch-typeahead/testname'
],
globals: {
'ts-jest': {
babelConfig: true
}
}
};
babel.config.js:
module.exports = {
presets: [
'@vue/app'
]
}
vue.config.js:
module.exports = {
// the default value is '/', which may be ok for production but is not suitable for local build/deploy
publicPath: ''
};
part of package.json:
"scripts": {
"lint": "vue-cli-service lint",
"serve": "vue-cli-service serve",
"test:unit": "vue-cli-service test:unit",
"build": "vue-cli-service build"
},
"dependencies": {
"core-js": "^2.6.5",
"vue": "^2.6.10",
"vuex": "^3.1.1",
"vue-class-component": "^7.0.2",
"vue-property-decorator": "^8.2.2",
"axios": "^0.19.0",
// more packages
},
"devDependencies": {
"@types/jest": "^23.1.4",
"@vue/cli-plugin-babel": "^3.11.0",
"@vue/cli-plugin-eslint": "^3.11.0",
"@vue/cli-plugin-typescript": "^3.11.0",
"@vue/cli-plugin-unit-jest": "^3.11.0",
"@vue/cli-service": "^3.11.0",
"@vue/eslint-config-typescript": "^4.0.0",
"@vue/test-utils": "1.0.0-beta.29",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "^10.0.1",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"ts-jest": "^23.0.0",
"typescript": "^3.4.3",
"vue-template-compiler": "^2.6.10"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended",
"@vue/typescript"
],
"rules": {},
"parserOptions": {
"parser": "@typescript-eslint/parser"
},
"overrides": [
{
"files": [
"**/__tests__/*.{j,t}s?(x)"
],
"env": {
"jest": true
}
}
]
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}
tsconfig.json:
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env",
"jest"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}