Nuxt 2 & Vuelidate 2 not working properly - vue.js

I have installed vuelidate 2 to validate forms in my NuxtJS project. I followed instructions for installation and setup according to vuelidate documentation. This is how my setup files look until now:
Package.json
"dependencies": {
"#nuxtjs/axios": "^5.13.6",
"#vue/composition-api": "^1.6.1",
"#vuelidate/core": "^2.0.0-alpha.41",
"#vuelidate/validators": "^2.0.0-alpha.29",
"core-js": "^3.19.3",
"nuxt": "^2.15.8",
"vue": "^2.6.14",
"vue-server-renderer": "^2.6.14",
"vue-template-compiler": "^2.6.14",
"vuelidate": "^0.7.7",
"webpack": "^4.46.0"
},
plugins/composition-api.js for #vue/composition-api
import Vue from 'vue'
import VueCompositionAPI from '#vue/composition-api'
Vue.use(VueCompositionAPI)
plugins/vuelidate.js
import Vue from 'vue'
import Vuelidate from 'vuelidate'
Vue.use(Vuelidate)
nuxt.config.js
plugins: [
{ src: '~/plugins/composition-api.js' },
{ src: '~/plugins/vuelidate' },
],
components/form.vue
<template>
<form #submit.prevent="submitForm">
<div>
<label for="name">Name:</label>
<input v-model="name" type="text" name="name" />
</div>
<button>Submit</button>
</form>
</template />
<script>
import useVuelidate from '#vuelidate/core'
import { required } from '#vuelidate/validators'
export default {
setup() {
return { v$: useVuelidate() }
},
data() {
return {
name: '',
}
},
methods: {
submitForm() {
this.v$.$validate().then((isFormValid) => {
if (isFormValid) {
console.log('valid!!!', this.$v)
} else {
return console.log('false', this.$v)
}
})
},
},
validations() {
return {
name: {
required,
},
}
},
}
</script>
These are a couple of problems that occur:
When I place v-if="v$.name.$error" inside template I get the error Cannot read property 'name' of undefined.
When I call submitForm method, the validation of isFormValid works properly. When I open the console to observe $v.errors, $v.dirty, or $v.invalid, I see this error inside the array:
[Exception: RangeError: Maximum call stack size exceeded at Watcher.depend (webpack-internal...

Related

Vuetify icons gives an error with storybook

Hello everyone I'm facing an issue When I use the storybook with vuetify framework and when I run the project it gives the following error multiple times.
Cannot read properties of undefined (reading 'component')
TypeError: Cannot read properties of undefined (reading 'component')
at remapInternalIcon (http://localhost:6006/vendors~main.f3adcb00877b75c26c76.bundle.js:267378:37)
at VueComponent.getIcon
and here is I'm using storybook v6.1.11 npm packages
"#storybook/addon-essentials": "^6.5.16",
"#storybook/addon-actions": "^6.1.11",
"#storybook/addon-controls": "^6.5.16",
"#storybook/addon-docs": "^6.1.11",
"#storybook/addon-links": "^6.1.11",
"#storybook/addons": "^6.1.11",
"#storybook/preset-scss": "^1.0.3",
"#storybook/vue": "^6.1.11",
"vuetify-loader": "^1.7.0",
"vuetify": "^2.6.0"
knowing that the my project is working fine and all of the components renders correctly even v-icon
main.js
const path = require('path');
module.exports = {
addons: [
'#storybook/addon-controls',
'#storybook/addon-docs',
'#storybook/addon-actions',
'#storybook/preset-scss',
],
webpackFinal: async (config, { configType }) => {
config.module.rules.push({
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
include: path.resolve(__dirname, '../'),
});
config.module.rules.push({
resolve: {
alias: {
'#': path.resolve(__dirname, '../src'),
vue: 'vue/dist/vue.js',
'vue$': 'vue/dist/vue.esm.js',
},
},
});
// Return the altered config
return config;
},
};
preview.js
import { configure, addDecorator } from "#storybook/vue";
import "!style-loader!css-loader!sass-loader!./scss-loader.scss";
import "vuetify/dist/vuetify.css";
import "#mdi/font/css/materialdesignicons.css";
import i18n from '../src/plugins/i18n';
import Vue from "vue";
import Vuetify from "vuetify";
Vue.use(Vuetify);
Vue.prototype.$t = function(...args){
return i18n.t(...args);
}
addDecorator(() => ({
i18n,
vuetify: new Vuetify({
rtl: true,
icons: {
iconfont: "mdi",
}
}),
template:
'<v-app style="background-color: white"><v-main><story/></v-main></v-app>',
}));
// automatically import all files ending in *.stories.js
configure(require.context("../stories", true, /\.stories\.js$/), module);
manager.js
import "#storybook/addon-actions/register";
import "#storybook/addon-links/register";
Here is an example of my stories
import Calendar from "../src/components/Calendar/calendar.vue";
export default {
title: "Components/Calendar",
component: Calendar,
};
const Template = (args, { argTypes }) => ({
components: { Calendar },
props: Object.keys(argTypes),
template: `<Calendar v-bind="$props" />`,
});
export const WithLabel = Template.bind({});
WithLabel.args = {
label: "Pick a date",
};
I don't know What is the issue.
Thanks in advance.

Component is missing template or render function - VueJS Library

I am trying to create an SVG library using Vue3 but all I am getting is error...I created the basic library project following this article. Here is my file structure
and this is my code in BaseIcon.vue
<template>
<component :is="iconComponent" class="inline-block fill-current"
style="height: 1em; width: 1em; vertical-align: -0.125em" />
</template>
<script>
const icons = {}
const requireComponents = require.context('../assets/icons/', false, /.svg$/)
requireComponents.keys().forEach(fileName => {
const iconName = fileName.replace(/^\.\/icon-(.+)\.svg$/, '$1')
const componentConfig = requireComponents(fileName)
icons[iconName] = componentConfig.default || componentConfig
})
export default {
props: {
name: {
type: String,
required: true,
validator(value) {
return Object.prototype.hasOwnProperty.call(icons, value)
}
}
},
computed: {
iconComponent() {
return icons[this.name]
},
}
}
</script>
This is the App.vue file code
<template>
<div id="app" class="p-10 text-xl">
<BaseIcon name="user" class="text-blue-500" /> Home
<BaseIcon name="home" class="text-blue-500" /> Profile
</div>
</template>
<script>
import BaseIcon from './BaseIcon.vue'
export default {
name: 'App',
components: {
BaseIcon,
}
}
</script>
My Index.js looks like this
/* eslint-disable import/prefer-default-export */
export { default as App } from './App.vue'
Dev Dependencies in my Package.json are these:
"devDependencies": {
"#babel/core": "^7.14.6",
"#babel/preset-env": "^7.14.7",
"#rollup/plugin-alias": "^3.1.2",
"#rollup/plugin-babel": "^5.3.0",
"#rollup/plugin-commonjs": "^14.0.0",
"#rollup/plugin-node-resolve": "^9.0.0",
"#rollup/plugin-replace": "^2.4.2",
"#vue/cli-plugin-babel": "^4.5.13",
"#vue/cli-service": "^4.5.13",
"#vue/compiler-sfc": "^3.1.0-0",
"cross-env": "^7.0.3",
"minimist": "^1.2.5",
"postcss": "^8.2.10",
"rimraf": "^3.0.2",
"rollup": "^2.52.8",
"rollup-plugin-postcss": "^4.0.0",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-vue": "^6.0.0",
"vue-loader": "16.8.3",
"vue-svg-loader": "^0.17.0-beta.2",
"vue": "^3.0.5"
},
and I've added vue.config.json with following settings:
module.exports = {
chainWebpack: (config) => {
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');
},
};
And here is what I am getting as error:
I'm not sure what I am missing here, or what is wrong.. Any kind of help will be appreciated, because its been days that I am stuck here and just couldn't get any idea of resolving this.

Vue.js 3: Vue is not defined with mount when running unit tests with external library

I am currently experienced the following error when running my unit tests:
ReferenceError: Vue is not defined
> 10 | import hljsVuePlugin from '#highlightjs/vue-plugin';
| ^
Here is my component code:
<template>
<div>
<highlightjs autodetect :code="'hello world'" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import hljsVuePlugin from '#highlightjs/vue-plugin';
export default defineComponent({
components: {
highlightjs: hljsVuePlugin.component,
},
});
</script>
in my test file, I'm simply trying to mount this component:
const wrapper = mount(FooBlah, {
global: {
stubs: {
highlightjs: {
template: '<div />',
},
},
},
});
Here are my libraries versions:
"vue": "^3.2.33",
"#highlightjs/vue-plugin": "^2.1.2",
"highlight.js": "^11.6.0",
"#vue/cli-plugin-unit-jest": "~5.0.4",
"#vue/test-utils": "^2.0.2",
"#vue/vue3-jest": "^27.0.0",
Is there any way I could tell him to simply ignore the highlightjs the component in the jest.config ?
As mentionned in the comments, this fixed my issue:
jest.mock('#highlightjs/vue-plugin', () => ({
hljsVuePlugin: {
component: jest.fn(),
},
}));
const wrapper = mount(FooBlah, {
global: {
stubs: {
highlightjs: {
template: '<div />',
},
},
},
})
You can find more information here: How can I mock an ES6 module import using Jest?

[Vue warn]: Unknown custom element: <nuxt-link> - When running jest unit tests

Problem
I'm using nuxt 1.4 with routing using Jest to do unit testing. My application doesn't throw errors and seems to work perfectly. However when running my unit test npm run unit (which runs jest) it throws an error in the terminal: [Vue warn]: Unknown custom element: <nuxt-link> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
Expected
I would expect it to not throw this error since my application is working.
Files
package.json:
{
"name": "vue-starter",
"version": "1.0.0",
"description": "Nuxt.js project",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
"precommit": "npm run lint",
"test": "npm run lint && npm run unit",
"unit": "jest",
"unit:report": "jest --coverage"
},
"dependencies": {
"babel-jest": "^22.4.1",
"jest-serializer-vue": "^1.0.0",
"node-sass": "^4.7.2",
"npm": "^5.7.1",
"nuxt": "^1.0.0",
"sass-loader": "^6.0.7",
"vue-jest": "^2.1.1"
},
"devDependencies": {
"#vue/test-utils": "^1.0.0-beta.12",
"babel-eslint": "^8.2.1",
"eslint": "^4.15.0",
"eslint-friendly-formatter": "^3.0.0",
"eslint-loader": "^1.7.1",
"eslint-plugin-vue": "^4.0.0",
"jest": "^22.4.2"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
],
"jest": {
"moduleFileExtensions": [
"js",
"vue"
],
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
},
"snapshotSerializers": [
"<rootDir>/node_modules/jest-serializer-vue"
]
}
}
The component that I test:
<template>
<div>
<nuxt-link class="name" :to="{ path: `entity/${item.id}`, params: { id: item.id }}">{{item.name}}</nuxt-link>
<button class="connect" #click="connect">{{ btnText }}</button>
</div>
</template>
<script>
// import nuxtLink from '../.nuxt/components/nuxt-link';
const connectionStatusMap = [
'Connect',
'Connected',
'Pending',
'Cancel',
];
export default {
/*components: {
'nuxt-link': nuxtLink,
},*/
props: {
item: {
type: Object
}
},
...
}
</script>
My test script:
import TestItem from '../components/TestItem';
import { shallow, mount, createLocalVue } from '#vue/test-utils';
import Vuex from 'vuex';
import VueRouter from 'vue-router';
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(VueRouter)
...
it(`should show the entity`, () => {
const wrapper = mount(TestItem, {
propsData: { item },
localVue,
store,
// stubs: ['nuxt-link'],
})
expect(wrapper.find('.name').text()).toBe(item.name);
});
it(`should show allow me to connect if I'm not yet connected`, () => {
const wrapper = shallow(TestItem, {
propsData: { item },
localVue,
store,
stubs: ['nuxt-link'],
})
expect(wrapper.find('.connect').text()).toBe('Connect');
});
...
I tried
I tried creating a localVue and also stubbing the component as suggested in this github comment
I also tried shallow/mount but that did not seem to work either.
This is how I was able to get rid of the annoying warning:
Include RouterLinkStub, eg.:
import { shallowMount, createLocalVue, RouterLinkStub } from '#vue/test-utils';
Map NuxtLink stub to RouterLinkStub
const wrapper = shallowMount(TestItem, {
...
stubs: {
NuxtLink: RouterLinkStub
}
})
And in case you were checking nuxt-link text or something, change:
const link = wrapper.find('nuxt-link');
to
const link = wrapper.find(RouterLinkStub);
Found this gold on https://onigra.github.io/blog/2018/03/19/vue-test-utils-router-link-stub/
Good thing you don't need to know japanese to read code...
Although the answers provided could work. What I ended up using was based on this guide
const wrapper = mount(TestItem, {
propsData: { item },
localVue,
store,
stubs: {
NuxtLink: true,
// Any other component that you want stubbed
},
});
I managed to get it working using this workaround for Storybook:
import { mount, createLocalVue } from '#vue/test-utils'
import Component from '#/components/Component.vue'
const localVue = createLocalVue()
localVue.component('nuxt-link', {
props: ['to'],
template: '<slot>NuxtLink</slot>',
})
describe('Test Component', () => {
const wrapper = mount(Component, {
stubs: ['nuxt-link'],
localVue
})
})
I added below lines of code to get this working.
In your test file
import NuxtLink from "path to nuxt-link.js"
Mycomponent.components.NuxtLink = NuxtLink
In your jest conf file
transformIgnorePatterns: [
"path to nuxt-link.js"
],
Or you could add below line in mount options
mount(Mycomponent, {stubs: ["nuxt-link"]})
I have:
// path: ./test/jest.setup.js
import Vue from 'vue'
import VueTestUtils from '#vue/test-utils'
// Mock Nuxt components
VueTestUtils.config.stubs['nuxt-link'] = '<a><slot /></a>'
VueTestUtils.config.stubs['no-ssr'] = '<span><slot /></span>'
and
// path: ./jest.config.js
module.exports = {
// ... other stuff
setupFilesAfterEnv: ['./test/jest.setup.js']
}
... and this solves all my jest test in the nuxt app
To anyone getting the Unknow custom element: <router-link>
My issue was, I used mount instead of shallow when creating the component.
shallow usage:
Like mount, it creates a Wrapper that contains the mounted and
rendered Vue component, but with stubbed child components.
Source: https://vue-test-utils.vuejs.org/en/api/shallow.html
Here is a working example
import { shallow } from '#vue/test-utils';
import ContentCard from '../../components/ContentCard.vue';
import NuxtLink from '../../.nuxt/components/nuxt-link';
const createComponent = propsData => shallow(ContentCard, { propsData });
describe('ContentCard', () => {
let component;
beforeEach(() => {
ContentCard.components = ContentCard.components || {};
ContentCard.components.NuxtLink = NuxtLink;
});
describe('Properties', () => {
it('has an imgSrc property', () => {
component = createComponent({ imgSrc: 'X' });
expect(component.props().imgSrc).toBe('X');
});
});
});
...
import NuxtLink from '../.nuxt/components/nuxt-link.js'
...
TestItem.components = TestItem.components || {};
TestItem.components.NuxtLink = NuxtLink;
const wrapper = shallow(TestItem, {
...
});
...
// test/jestSetup.js
import Vue from 'vue'
import Vuetify from 'vuetify'
import { config } from '#vue/test-utils'
Vue.use(Vuetify)
config.stubs.NuxtLink = { template: '<a><slot /></a>' }

Import vue package in laravel

What is the corect way to import vue packages in laravel 5.6? It comes with vue and bootstrap preinstall. I see they are all compile in app.js from public directory but I can figure out how to import https://github.com/moreta/vue-search-select and use it. After I tried to import it on my own:
Error:
ncaught TypeError: Vue.component is not a function
At line:
Vue.component('search-user', __webpack_require__(42));
Until now I tried this:
assets/js/bootstrap.js:
import { BasicSelect } from 'vue-search-select';
window.BasicSelect = BasicSelect;
assets/js/app.js:
require('./bootstrap');
window.Vue = require('vue');
window.Vue = require('vue-search-select');
Vue.component('search-user', require('./components/SearchUser.vue'));
var app = new Vue({
el: '#app'
})
components
<template>
<basic-select :options="options"
:selected-option="item"
placeholder="select item"
#select="onSelect">
</basic-select>
</template>
<script>
export default {
data() {
return {
keywords: null,
options: []
};
},
watch: {
keywords(after, before) {
if (this.keywords.length > 0)
this.fetch();
}
},
methods: {
fetch() {
axios.get('/api/search', {params: {keywords: this.keywords}})
.then(response => this.options = response.data)
.catch(error => {
});
},
onSelect (item) {
this.item = item
},
reset () {
this.item = {}
},
selectOption () {
// select option from parent component
this.item = this.options[0]
},
components: {
BasicSelect
}
}
}
</script>
I ran: npm install and npm run watch:
"devDependencies": {
"ajv": "^6.0.0",
"bootstrap": "^4.0.0",
"cross-env": "^5.1",
"laravel-mix": "^2.0",
"lodash": "^4.17.4",
"popper.js": "^1.12",
"uikit": "^3.0.0-beta.35",
"vue": "^2.5.7",
"vue-search-select": "^2.5.0"
},
"dependencies": {
"axios": "^0.17.1",
"jquery": "^3.3.1"
}
I think that the simple will do
window.Vue = require('vue');
require('vue-search-select');
Then in your components you can import what you need on top:
import { BasicSelect } from 'vue-search-select';
export default {
data() {
return {
keywords: null,
options: [],
item: null
};
},
...
One missing detail that tricked me with this one, you need to register the components like this, otherwise it won't be found:
components: {
ModelSelect,
BasicSelect
},