I have problem with component testing when using 'vue-echarts'
InfoBoard.spec.ts
import { render } from '#testing-library/vue'
import InfoBoard from '#/components/InfoBoard.vue'
describe('InfoBoard', () => {
test('Should be truthy', () => {
const wrapper = render(InfoBoard, {
stubs: {
'v-charts': true
},
})
expect(wrapper).toBeTruthy()
})
})
InfoBoard.vue
<template>
<div>
<v-chart></v-chart>
</div>
</template>
<script>
import { defineComponent } from '#nuxtjs/composition-api'
import VChart from 'vue-echarts'
export default defineComponent({
components: {
VChart
},
setup() {}
})
</script>
jest.config.js
module.exports = {
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js'
},
moduleFileExtensions: [
'ts',
'js',
'vue',
'json'
],
transform: {
"^.+\\.ts$": "ts-jest",
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest'
},
collectCoverage: true,
collectCoverageFrom: [
'<rootDir>/components/**/*.vue',
'<rootDir>/pages/**/*.vue'
],
transformIgnorePatterns: [
"<rootDir>/node_modules/(?!echarts)",
"<rootDir>/node_modules/(?!echarts\/core)",
"<rootDir>/node_modules/(?!vue-echarts)"
],
testEnvironment: 'jsdom',
setupFilesAfterEnv: ["./jest-setup.js"]
}
Got Error:
FAIL components/InfoBoard.spec.ts
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
/Users/admin/Documents/THIP/node_modules/echarts/core.js:20
export * from './lib/export/core';
^^^^^^
SyntaxError: Unexpected token 'export'
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1479:14)
at Object.<anonymous> (node_modules/vue-echarts/dist/index.cjs.min.js:1:179)
I think the problem is in 'transformIgnorePatterns', maybe I write wrong patterns.
I searching for many day, I tried many anwser like change 'testEnviroment' or add plugin in .babelrc but don't found the solution.
I ran into the same problem and was just able to get it working by adding the following setting to my jest.config.js:
module.exports = {
transformIgnorePatterns: ["/node_modules/(?!(echarts|zrender)/)"],
}
If you wrote your configuration as provided here, I assume you wouldn't have to include the root directory in the ignore-pattern. It didn't work either when having more than one ignore-pattern; but this might be because of the way I wrote the ignore-pattern.
Related
I am creating a library that wraps Vuetify 3 components. But when I try to use the library it gives the following error:
[Vue warn]: Failed to resolve component: v-btn If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
Library vite.config.ts :
import { fileURLToPath, URL } from 'node:url';
import { resolve } from 'node:path';
import { defineConfig } from 'vite';
import vue from '#vitejs/plugin-vue';
import vueJsx from '#vitejs/plugin-vue-jsx';
import vuetify from 'vite-plugin-vuetify';
export default defineConfig({
plugins: [
vue(),
vueJsx(),
// vuetify({ autoImport: true, styles: 'none' }), // Don't export vuetify
],
resolve: {
alias: {
'#': fileURLToPath(new URL('./src', import.meta.url)),
},
},
build: {
lib: {
entry: resolve(__dirname, 'src/main.ts'),
name: '#my/ui',
// the proper extensions will be added
fileName: 'my-ui',
},
rollupOptions: {
// make sure to externalize deps that shouldn't be bundled
// into your library
external: ['vue', 'vuetify'],
output: {
// Provide global variables to use in the UMD build
// for externalized deps
globals: {
vue: 'Vue',
vuetify: 'Vuetify',
},
},
},
},
});
Nuxt project nuxt.config.ts:
import { defineNuxtConfig } from 'nuxt';
import vuetify from 'vite-plugin-vuetify';
export default defineNuxtConfig({
css: ['#/assets/css/main.css'],
modules: [
async (options, nuxt) => {
nuxt.hooks.hook('vite:extendConfig', (config) =>
config.plugins.push(vuetify({ autoImport: true }))
);
},
],
build: {
transpile: ['#my/ui', 'vuetify'],
},
});
Nuxt project app.vue:
<template>
<v-app>
<v-main>
<HelloWorld label="Test" primary />
</v-main>
</v-app>
</template>
<script lang="ts" setup>
import { HelloWorld } from '#my/ui';
</script>
Nuxt project plugin vuetify.ts:
import 'vuetify/styles';
import { createVuetify } from 'vuetify';
import * as components from 'vuetify/components';
import * as directives from 'vuetify/directives';
export default defineNuxtPlugin((nuxtApp) => {
const vuetify = createVuetify({
// components, if imported components getting resolved but treeshaking doesn't work.
// directives
});
nuxtApp.vueApp.use(vuetify);
});
Expected Behavior
Vuetify components from the Library project should be auto imported.
Current workaround:
If the vuetify components are imported in the parent project then the components are resolved. But this causes issue as the library users has to know what to import or import on global which is creating larger bundle size.
Is there an alternative way to implement and meet the following criteria:
Wrapping module doesn't depend on vuetify (Peer dep only)
Consuming app can auto import and get all of the benefits of tree shaking
Consuming app doesn't need to import any of the peer dependencies of the wrapping module.
Thank you so much in advance.
Just to create an answer for the workaround Sasank described:
If you just want to get rid of the error, import the components into the parent project as described in this link: https://next.vuetifyjs.com/en/features/treeshaking/#manual-imports
In our project we are using vue-svg-loader (latest version) with the following configuration file vue.config.js:
const svgRule = config.module.rule('svg')
svgRule.uses.clear()
svgRule
.use('babel-loader')
.loader('babel-loader')
.end()
.use('vue-svg-loader')
.loader('vue-svg-loader')
.options({
svgo: {
plugins: [{ removeViewBox: false }]
}
})
unfortunately after upgrading our #vue/cli-service 5.0.4 from #vue/cli-service 3.4.0
everything works but our svgs, which are not loading any more with the following error:
[Vue warn]: Invalid Component definition: /public/img/island-small.3fa8ec4c.svg found in <ZnLogin> at src/pages/login/login.vue
I tried playing with the versions, variety of configurations (mostly the default one) and nothing seems to work. I do wish to keep the current usage method:
<template>
<VueLogo/>
</template>
<script>
import VueLogo from './public/vue.svg';
export default {
name: 'Example',
components: {
VueLogo,
},
};
</script>
any idea?
Check out this issue.
https://github.com/visualfanatic/vue-svg-loader/issues/185
Changing the vue configuration worked for me.
// vue.config.js
module.exports = {
chainWebpack: (config) => {
config.module.rules.delete("svg");
config.module.rule("svg")
.test(/\.(svg)(\?.*)?$/)
.use("babel-loader")
.loader("babel-loader")
.end()
.use("vue-svg-loader")
.loader("vue-svg-loader");
},
};
this is my first question here so please let me know if you need more info.
I am working on a small project using vue CLI 3 and I want to add audio and audio controls but I get the following error:
Module parse failed: Unexpected character '' (1:0) You may need an
appropriate loader to handle this file type, currently no loaders are
configured to process this file. See
https://webpack.js.org/concepts#loaders
I don't really know how to edit webpack. Nonetheless, I found this in the documentation to create a vue.config.js file. But I don't really understand what should I add there.
this is how my component looks:
<template>
<div class="controller-container">
<audio controls>
<source src="#/assets/Catastrophe03music.m4a" type="audio/mp4" />
</audio>
</div>
</template>
<script>
export default {
name: "MusicController",
components: {},
};
</script>
thanks for helping
If you are using Vue App then go to webpack.config.js and add the following code
module: {
rules: [
{
test: /\.mp3$/,
loader: 'file-loader',
exclude: /node_modules(?!\/foundation-sites)|bower_components/,
options: {
name: '[path][name].[ext]'
}
}
]
}
But if you have webpack.mix.js file then add the following code.
mix.webpackConfig({
module: {
rules: [
{
test: /\.mp3$/,
loader: 'file-loader',
exclude: /node_modules(?!\/foundation-sites)|bower_components/,
options: {
name: '[path][name].[ext]'
}
}
]
}
});
I am writing code by Vue3 and Typescript, and this is the code of App.vue, which is the root component:
<template>
<router-view v-if="inited" />
<div v-else>
Initing...
</div>
</template>
<script lang="ts">
import router from './router';
import { defineComponent } from 'vue';
import { useStore } from 'vuex';
import { key } from './store';
const store = useStore(key);
export default defineComponent({
data() {
return { inited: store.state.inited };
},
});
</script>
But the eslint tell me:
/home/peter/proj/skogkatt-next/src/App.vue
17:9 error Parsing error: '}' expected
I use many time on Google and so on, but still cannot find a useful solution. This is the config of eslint in package.json:
{
// ...
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"parser": "#typescript-eslint/parser",
"plugins": [
"#typescript-eslint"
],
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended",
"#vue/typescript",
"plugin:#typescript-eslint/eslint-recommended",
"plugin:#typescript-eslint/recommended"
],
"parserOptions": {
"parser": "#typescript-eslint/parser"
},
"rules": {
"#typescript-eslint/camelcase": "off"
}
},
// ...
}
I am not sure which config is useful or not, so I post those out. Thanks.
The error is caused by "plugin:#typescript-eslint/recommended", which sets the top-level parser, which collides with Vue's vue-eslint-parser. In addition, your own config duplicates the top-level parser setting already set in the plugin, and should also be removed.
Vue's ESLint config for TypeScript projects addresses this problem, so consider copying it:
module.exports = {
plugins: ['#typescript-eslint'],
// Prerequisite `eslint-plugin-vue`, being extended, sets
// root property `parser` to `'vue-eslint-parser'`, which, for code parsing,
// in turn delegates to the parser, specified in `parserOptions.parser`:
// https://github.com/vuejs/eslint-plugin-vue#what-is-the-use-the-latest-vue-eslint-parser-error
parserOptions: {
parser: require.resolve('#typescript-eslint/parser'),
extraFileExtensions: ['.vue'],
ecmaFeatures: {
jsx: true
}
},
extends: [
'plugin:#typescript-eslint/eslint-recommended'
],
overrides: [{
files: ['*.ts', '*.tsx'],
rules: {
// The core 'no-unused-vars' rules (in the eslint:recommeded ruleset)
// does not work with type definitions
'no-unused-vars': 'off',
}
}]
}
Another option is to generate a TypeScript project with Vue CLI, and copying the resulting ESLint config.
I think it should be:
import { router } from './router';
Check if you have eslintConfig specified in both package.json and separate eslint config file. Both of these conflict and give this inconsistent state.
Its best to remove eslintConfig from package.json and move those to eslint config file.
I've recently switched to Webpack and have all my JS and CSS running perfectly through it now. Here's the relevant piece of webpack.config.js:
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
},
{loader: 'import-glob-loader'}
]
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: [
{loader: MiniCssExtractPlugin.loader},
{loader: 'css-loader'},
{
loader: 'postcss-loader',
options: {
plugins: [
require('autoprefixer')
]
}
},
{loader: 'sass-loader'},
{loader: 'import-glob-loader'}
]
}
]
I have Vue included from a CDN and with this setup I can do the following no problem:
Vue.component('test-component', {
data: function () {
return {
title: 'Title',
description: 'Description'
};
},
methods: {
created: function () {
console.log('Created');
}
},
template: '<section id="test-component"><h2>{{ title }}</h2>{{ description }}</section>'
});
new Vue({el: '#app'});
And in my HTML:
<div id="app">
<test-component></test-component>
</div>
I'd now like to use Vue single file components instead, and reading the docs it tells me to simply run .vue files through vue-loader, so I changed my rules to the following:
rules: [
// NOTE: This is new
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
},
{loader: 'import-glob-loader'}
]
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: [
{loader: MiniCssExtractPlugin.loader},
{loader: 'css-loader'},
{
loader: 'postcss-loader',
options: {
plugins: [
require('autoprefixer')
]
}
},
// NOTE: This is new too, but commented because it throws errors
// {loader: 'vue-style-loader'},
{loader: 'sass-loader'},
{loader: 'import-glob-loader'}
]
}
]
With that in place my .vue files are picked up and added to dist/main.js so it seems to be working (as long as I don't include a <style> element in the Vue file in which case it fails), but now new Vue({el: '#app'}) does absolutely nothing. Checking the DOM the <test-component> is still in there and not rendered by Vue at all.
If I also try to enable vue-style-loader the build fails entirely saying:
(1:4) Unknown word
> 1 | // style-loader: Adds some css to the DOM by adding a <style> tag
| ^
2 |
3 | // load the styles
What am I doing wrong here?
Edit: Progress. Thanks to Daniel my <style> now works as long as it has lang="scss" set. This is because my webpack config only has rules for scss files and not css files.
I've also figured out the reason the <test-component> won't render is because I never actually register it, simply including the .vue-file is not enough for it to be registered obviously.
The problem I'm having now is trying to glob import all my .vue-files as an array of components. If I do this it works fine:
import TestComponent from "./test-component.vue";
import AnotherComponent from "./another-component.vue";
document.querySelectorAll('[data-vue]').forEach(el => {
new Vue({
el: el,
components: {
'test-component': TestComponent,
'another-component': AnotherComponent
}
});
});
But I'd like to be able to do this some how:
import components from "./**/*.vue";
document.querySelectorAll('[data-vue]').forEach(el => {
new Vue({
el: el,
components: components
});
});
Using import-glob-loader.
Simply importing the vue files is not enough for them to be available for use. You also have to register them with Vue.
So, this is wrong:
import 'component.vue';
new Vue({el: '#app'});
This is right:
import component from 'component.vue';
new Vue({
el: '#app',
components: {
'component': component
}
});
That takes care of making them usable.
The reason the <style> elements don't work is because I don't have a webpack rule for CSS files - only for SCSS files. Thanks to #Daniel for pointing out that I need <style lang="scss">.
vue-style-loader is only needed to inject styles into the DOM as <style> elements which I don't actually use (I use mini-css-extract-plugin to create css-files) also according to the docs:
However, since this is included as a dependency and used by default in vue-loader, in most cases you don't need to configure this loader yourself.
Will create a separate question regarding the glob import.
Make sure you have <style lang="scss"> in your SFC
You can also try deleting the package-lock and node_modules folder and do a clean install. Sometimes that can resolve an issue if the dependencies are not using compatible versions.
Update
To import using glob style imports you may need to use import-glob
https://www.npmjs.com/package/import-glob
You can also achieve similar result using global component registration. This is documented well in the official docs at:
https://v2.vuejs.org/v2/guide/components-registration.html#Automatic-Global-Registration-of-Base-Components