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
},
Related
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.
I am setting up tests on a Nuxt2 app using #nuxtjs/composition-api and
#vue/test-utils.
In addition, there is a vue-CLI UI library using #vue/composition-api and vue-demi.
The issue is that even if the context is mocked as per solution here, our store is still undefined and the tests are failling.
///// SET UP /////
The Nuxt2 app is set as follow:
Package.json
"dependencies": {
"#nuxtjs/composition-api": "^0.20.2",
"core-js": "2",
}
"devDependencies": {
"#vue/test-utils": "^1.3.0",
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "^28.1.0",
"jest": "^28.1.0",
"jest-environment-jsdom": "^28.1.0",
"jest-junit": "^14.0.0",
"vue-jest": "^3.0.7",
}
nuxt.config.js
alias: {
'vue-demi': '#nuxtjs/composition-api',
},
jest.config.js
module.exports = {
verbose: true,
testEnvironment: 'jsdom',
moduleFileExtensions: ['js', 'vue', 'json'],
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js',
'^.+\\.(s?css|less)$': '<rootDir>/css_stub.js',
'^#atoms/(.*)$':
'<rootDir>/node_modules/UILIBRARY-path/$1',
'^#molecules/(.*)$':
'<rootDir>/node_modules/UILIBRARY-path/$1',
'^#organisms/(.*)$':
'<rootDir>/node_modules/UILIBRARY-path/$1',
},
transform: {
'^.+\\.js$': '<rootDir>/node_modules/babel-jest',
'.*\\.(vue)$': '<rootDir>/node_modules/vue-jest',
},
transformIgnorePatterns: ['<rootDir>/node_modules/UILIBRARY'],
moduleDirectories: ['<rootDir>/node_modules/'],
globals: {
'vue-jest': {
babelConfig: {
configFile: './babel.config.js',
},
},
},
setupFilesAfterEnv: ['<rootDir>/test/unit/vueSetup.js'],
collectCoverage: true,
collectCoverageFrom: ['components/**.vue', 'pages/**.vue'],
coverageDirectory: 'tmp/coverage',
reporters: ['default', ['jest-junit', { outputDirectory: 'tmp/coverage' }]],
coverageReporters: ['text', 'html', 'cobertura'],
coverageThreshold: {
global: {
statements: 0,
branches: 0,
functions: 0,
lines: 0,
},
},
}
test/vueSetp.js
import Vue from 'vue'
import Buefy from 'buefy'
import VueFormulate from 'UILIBRARY/vue-formulate/src/Formulate'
import { config } from '#vue/test-utils'
Vue.use(Buefy)
Vue.use(VueFormulate)
config.mocks.$t = (key) => key
config.mocks.$tc = (key) => key
///// Component and Test ////
Component.vue
export default {
name: 'Component',
setup() {
const {
store,
} = useContext()
// when consol.log(store), it is defined
const gettingStoreData = computed(
() =>
store.getters['data']?.key === 1
)
test.spec.js
import { mount } from '#vue/test-utils'
import Component from '#/path-to-component/Component.vue'
jest.mock('#nuxtjs/composition-api')
describe('Component.vue', () => {
const factory = (mockDataForm) => {
const wrapper = mount(Component, {
propsData: {
various data
},
mocks: {
$nuxt: {
context: {
store: {},
},
},
},
provide: {
form: mockDataForm
},
})
return wrapper
}
test('component mounts properly', () => {
const wrapper = factory({
various data
})
expect(wrapper.vm).toBeTruthy()
})
There were a couple of attempts to define/ mock the store globally:
vueSetup.js
setting a mock store globaly
config.mocks.store
adding $nuxt to Vue.prototype
Vue.prototype.$nuxt = {
context: {
store: {},
},
}
creating a new Vue and adding store to its prototype
const newVue = new Vue({})
newVue.prototype = (key) => key
{
context: {
store: { $auth: {} },
But all of it result in the same error as in the title:
TypeError: Cannot destructure property 'store' of '(0 , _compositionApi.useContext)(...)' as it is undefined.
So what else could be done in order to not have an undefined store and be able to run the tests properly?
Should Vuex be added (which sounds not good as it is a nuxt app)
Is it actually only related to the store and not the context since mocking $t and $tc works fine?
Could it be linked to the component code itself and not the test?
Many thanks in advance for your support and please let me know if there is any missing information or if you need more details.
Cheers,
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?
I am using Laravel 8 with Inertia.js version 0.5.4. Can anyone help solve this problem? The app works fine without the ssr. I think the problem is in the Webpack config file.
ReferenceError: document is not defined
package.json
"#inertiajs/inertia": "^0.11.0",
"#inertiajs/inertia-vue": "^0.8.0",
"laravel-mix": "^6.0",
"sass": "~1.32",
"sass-loader": "^12.2.0",
"vue-cli-plugin-vuetify": "~2.3.1",
"vue-loader": "^15.9.6",
"vue-template-compiler": "^2.6.10",
"vuetify-loader": "^1.7.0",
"webpack": "^5.59.1",
"vue": "^2.6.14",
"vue-server-renderer": "^2.6.14",
"vuetify": "^2.5.5",
"vuetifyjs-mix-extension": "0.0.20",
"vuex": "^3.4.0",
"webpack-node-externals": "^3.0.0"
webpack.ssr.mix.js
const path = require('path')
const mix = require('laravel-mix')
const webpackNodeExternals = require('webpack-node-externals');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
mix
.options({ manifest: false, processCssUrls: false })
.js('resources/js/ssr.js', 'public/js')
.vue({
version: 2, options: { optimizeSSR: true }
})
.webpackConfig({
resolve: {
alias: {
'#resources': path.resolve('resources'),
'{Template}': path.resolve('resources/js/Themes/default'),
'#themeConfig': path.resolve('themeConfig.js'),
'#core': path.resolve('resources/#core'),
'#axios': path.resolve('resources/js/plugins/axios.js'),
'#user-variables': path.resolve('resources/sass/variables.scss'),
'#sass': path.resolve('resources/sass/'),
'apexcharts': path.resolve(__dirname, 'node_modules/apexcharts-clevision'),
'#': path.resolve('resources/js'),
},
},
plugins: [new MiniCssExtractPlugin(
{
filename: "[name].css",
chunkFilename: "[id].css",
linkType: false,
}
)],
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
// enable CSS extraction
extractCSS: true
}
}
// ...
]
},
target: 'node',
devtool: 'source-map',
externals: [webpackNodeExternals({
// this WILL include `jquery` and `webpack/hot/dev-server` in the bundle, as well as `lodash/*`
allowlist: [/^vuetify/, /^lodash/, 'vue-tel-input-vuetify/lib', /^vue-tel-input-vuetify^/, /^apexcharts^/, /^vue-apexcharts/, /apexcharts/, /apexcharts-clevision/, /^apexcharts-clevision/, /^apexcharts-clevision^/, /^vue-country-flag/, /\.css$/]
})],
})
ssr.js
import Vue from 'vue'
import {createRenderer} from 'vue-server-renderer'
import {createInertiaApp} from '#inertiajs/inertia-vue'
import createServer from '#inertiajs/server'
import PortalVue from 'portal-vue';
import store from './store'
import './plugins/acl'
import VueCompositionAPI from '#vue/composition-api'
import VueMeta from 'vue-meta'
import vuetify from '#/plugins/vuetify'
import Layout from '#/Layouts/AdminLayout.vue'
import AppLayout from "#/Layouts/AppLayout.vue"
import UserLayout from "#/Layouts/UserLayout.vue"
import ClientOnly from 'vue-client-only'
const moment = require('moment');
createServer((page) => createInertiaApp({
page,
render: createRenderer().renderToString,
// resolve: name => require(`./Pages/${name}`),
resolve: (name) => {
// const page = (await import(`./Pages/${name}`)).default
const page = require(`./Pages/${name}`);
if (page.layout === undefined && name.startsWith('Admin/')) {
page.layout = Layout
}
if (page.layout === undefined && name.startsWith('Dashboard/')) {
page.layout = Layout
}
if (page.layout === undefined && name.startsWith('UserDashboard/')) {
page.layout = UserLayout
}
if (page.layout === undefined && !name.startsWith('Admin/') && !name.startsWith('Dashboard/')) {
page.layout = AppLayout
}
return page
},
setup({app, props, plugin}) {
Vue.use(plugin);
Vue.use(VueCompositionAPI);
Vue.use(PortalVue);
Vue.component('client-only', ClientOnly)
Vue.use(VueMeta, {
// optional pluginOptions
refreshOnceOnNavigation: true
})
Vue.mixin({methods: {route}});
return new Vue({
vuetify: vuetify,
store,
render: h => h(app, props),
})
},
}))
npx mix --mix-config=webpack.ssr.mix.js
result : webpack compiled successfully
node public/js/ssr.js
error :
var style = document.createElement('style');
^
ReferenceError: document is not defined
at insertStyleElement (C:\laragon\www\test2\public\js\ssr.js:44989:15)
at addStyle (C:\laragon\www\test2\public\js\ssr.js:45104:13)
at modulesToDom (C:\laragon\www\test2\public\js\ssr.js:44977:18)
at module.exports (C:\laragon\www\test2\public\js\ssr.js:45135:25)
at Module../resources/sass/overrides.scss (C:\laragon\www\gooreo2\public\js\ssr.js:41942:145)
at webpack_require (C:\laragon\www\test2\public\js\ssr.js:130966:42)
at Module../resources/js/plugins/vuetify/default-preset/preset/index.js
(C:\laragon\www\test2\public\js\ssr.js:38073:1)
at webpack_require (C:\laragon\www\test2\public\js\ssr.js:130966:42)
at Module../resources/js/plugins/vuetify/index.js (C:\laragon\www\test2\public\js\ssr.js:38099:80)
at webpack_require
(C:\laragon\www\test2\public\js\ssr.js:130966:42)
public/js/ssr.js
You can fix it is by adding one line to your webpack.mix.js to opt in to using the vue-style-loader
mix
.js('resources/js/ssr.js', 'public/js')
.vue({
version: 3,
useVueStyleLoader: true // This should fix it!
});
Ref: https://aaronfrancis.com/2021/vue-referenceerror-document-is-not-defined-at-insertstyleelement
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>' }