Vue.js: vue-alert component not rendering - vue.js

import VueAlert from 'archer-vue-alert';
Vue.use(VueAlert);
this.$alert({
title: 'alertTitle',
message: 'alertMessage', //message accepts string and raw_html
confirmTxt: 'confirm btn txt' //default is 'OK'
}).then(function () {
//...
})
I am sure that there is no problem with archer-vue-alert package, in fact, I used vue-alert package as well. Same problem. Why is the alert never displayed?
My package.json file:
"archer-vue-alert": "^2.0.2",
"onsenui": "^2.5.1",
"vue": "^2.4.2",
"vue-i18n": "^7.1.1",
"vue-infinite-scroll": "^2.0.1",
"vue-onsenui": "^2.1.0",
"vue-resource": "^1.3.4",
"vue-router": "^2.7.0",
"vuex": "^2.3.1"

From your example, it looks like you are registering VueAlert as a plugin and then immediately attempting to display an alert by calling $alert() on this in the context of your main.js file.
Based on the archer-vue-alert package's README, $alert() should be called on a Vue instance.
Here's one example of correct usage:
import VueAlert from 'archer-vue-alert';
Vue.use(VueAlert);
new Vue({
el: '#app',
created() {
this.$alert({
title: 'alertTitle',
message: 'alertMessage',
confirmTxt: 'confirm btn txt'
})
}
})

Related

Unable to test vue component with v-dialog

I have been killing myself trying to figure out how to test a Vue component with a v-dialog, something which worked perfectly fine in Vue2. Currently I am using Vue3, Vitest, Vuetify3.
here is a very simple component which demonstrates a problem
<template>
<div>
<v-btn #click.stop="dialog=true" class="open-dialog-btn">click me please</v-btn>
<v-dialog v-model="dialog" max-width="290" >
<div class="dialog-content">
<v-card>welcome to dialog</v-card>
</div>
</v-dialog>
</div>
</template>
<script setup>
import {ref} from "vue";
const dialog = ref(false);
</script>
and here is a unit test for it:
import '../setup';
import { mount } from '#vue/test-utils';
import { createVuetify } from "vuetify";
import HelloDialog from "#/components/HelloDialog.vue";
describe('HelloDialog', () => {
let wrapper;
let vuetify;
beforeEach(() => {
vuetify = createVuetify();
});
describe('dialog tests', () => {
beforeEach(async () => {
wrapper = await mount(HelloDialog, {
global: {
plugins: [vuetify],
},
});
});
test('test dialog', async () => {
expect(wrapper.find('.dialog-content').exists()).toBeFalsy();
await wrapper.find('.open-dialog-btn').trigger('click');
console.log(wrapper.html());
expect(wrapper.find('.dialog-content').exists()).toBeTruthy();
});
});
});
the last line in unit test is not working - dialog content is not displayed. Here is an output from wrapper.html() after button is clicked:
<div><button type="button" class="v-btn v-btn--elevated v-theme--light v-btn--density-default v-btn--size-default v-btn--variant-elevated open-dialog-btn"><span class="v-btn__overlay"></span><span class="v-btn__underlay"></span>
<!----><span class="v-btn__content" data-no-activator="">click me please</span>
<!---->
<!---->
</button>
<!---->
<!--teleport start-->
<!--teleport end-->
</div>
AssertionError: expected false to be truthy
at ....../HelloDialog.spec.js:27:56
here is test section from vite.config.js:
test: {
// https://vitest.dev/config/
globals:true,
environment: 'happy-dom',
setupFiles: "vuetify.config.js",
deps: {
inline: ["vuetify"],
},
},
and here is vuetify.config.js:
global.CSS = { supports: () => false };
here some versions from package.json:
"dependencies": {
"#mdi/font": "7.1.96",
"#pinia/testing": "^0.0.14",
"axios": "^1.2.0",
"dotenv": "^16.0.3",
"happy-dom": "^8.1.1",
"jsdom": "^20.0.3",
"lodash": "^4.17.21",
"pinia": "^2.0.27",
"roboto-fontface": "*",
"vue": "^3.2.45",
"vuetify": "3.0.6",
"webfontloader": "^1.0.0"
},
"devDependencies": {
"#vitejs/plugin-vue": "^4.0.0",
"#vue/test-utils": "^2.2.6",
"vite": "^4.0.3",
"vite-plugin-vuetify": "^1.0.0-alpha.12",
"vitest": "^0.26.2"
}
I have tried everything at this point, and I think the problem has something to do with v-dialog using teleport component. After struggling for several days trying to figure out I settled on using a stub to not use a real dialog when testing but I really don't like this approach.
any ideas would be greatly appreciated
I have the same issue and found the content of v-dialog was rendered in document.body when I called mount().
You can test the dialog content like below.
// expect(wrapper.find('.dialog-content').exists()).toBeTruthy();
expect(document.querySelector('.dialog-content')).not.toBeNull();
I recommend to call unmount() after each test.
afterEach(() => {
wrapper.unmount()
});
Hope this helps although I doubt it's a good approach because I don't want to care whether the component is using teleport or not.

Embed a VSCode style IDE in the browser

I am trying to find a vue 3 component that is a code editor with a similar theme as vscode. It should have the tree structure and be able to execute the code.
Some of the things I found that sadly did not fit the bill are:
monaco-editor
vue3-ace-editor
ace
I would like to send the files from the backend and have them rendered in the embedded code editor.
Any advice would be greatly appreciated.
Update 1
I got it to work. There is not a file tree but there is a component for it. Just need to add a watcher to the file tress and have what is selected in the ManacoEditor. Here is a basic example to get the IDE to render in the browser.
<template>
<div>
<MonacoEditor
width="900"
height="750"
language="go"
#change="onChange"
:value="value"
></MonacoEditor>
</div>
</template>
<script lang="ts">
import {Options, Vue} from "vue-class-component";
import MonacoEditor from "monaco-editor-vue3";
#Options({
components: {
MonacoEditor,
},
props: {
editorInit: String,
content: String,
},
})
export default class Editor extends Vue {
value = `
package main
import "fmt"
func main() {
fmt.println("HelloWorld")
}`
onChange() {
console.log("value");
}
async mounted() {
// add parameters here
}
}
</script>
<style scoped>
</style>
package.json
"dependencies": {
"#codemirror/lang-html": "^6.1.1",
"#codemirror/lang-javascript": "^6.1.0",
"#codemirror/lang-json": "^6.0.0",
"#monaco-editor/loader": "^1.3.2",
"codemirror": "^6.0.1",
"core-js": "^3.8.3",
"monaco-editor": "^0.34.0",
"monaco-editor-vue3": "^0.1.6",
"monaco-editor-webpack-plugin": "^7.0.1",
"monaco-languageclient": "^4.0.0",
"vscode-ws-jsonrpc": "^2.0.0",
"vue": "^3.2.13",
"vue-class-component": "^8.0.0-0",
"vue-codemirror": "^6.1.1",
"vue-monaco": "^1.2.2",
"vue-router": "4"
},
Enjoy!
The editor powering VSCode is open source and Microsoft provides examples on how to use it.
Demo:
var editor = monaco.editor.create(document.getElementById("container"), {
value: ["function x() {", '\tconsole.log("Hello world!");', "}"].join("\n"),
language: "javascript",
});
monaco.editor.setTheme("vs-dark");
body {
margin: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link
rel="stylesheet"
data-name="vs/editor/editor.main"
href="https://unpkg.com/monaco-editor#0.34.0/min/vs/editor/editor.main.css"
/>
</head>
<body>
<div
id="container"
style="width: 800px; height: 600px; border: 1px solid grey"
></div>
<script>
var require = {
paths: {
vs: "https://unpkg.com/monaco-editor#0.34.0/min/vs",
},
};
</script>
<script src="https://unpkg.com/monaco-editor#0.34.0/min/vs/loader.js"></script>
<script src="https://unpkg.com/monaco-editor#0.34.0/min/vs/editor/editor.main.nls.js"></script>
<script src="https://unpkg.com/monaco-editor#0.34.0/min/vs/editor/editor.main.js"></script>
</body>
</html>
How does it not fit the bill?
I got it to work. There is not a file tree but there is a component for it. Just need to add a watcher to the file tress and have what is selected in the ManacoEditor. Here is a basic example to get the IDE to render in the browser.
<template>
<div>
<MonacoEditor
width="900"
height="750"
language="go"
#change="onChange"
:value="value"
></MonacoEditor>
</div>
</template>
<script lang="ts">
import {Options, Vue} from "vue-class-component";
import MonacoEditor from "monaco-editor-vue3";
#Options({
components: {
MonacoEditor,
},
props: {
editorInit: String,
content: String,
},
})
export default class Editor extends Vue {
value = `
package main
import "fmt"
func main() {
fmt.println("HelloWorld")
}`
onChange() {
console.log("value");
}
async mounted() {
// add parameters here
}
}
</script>
<style scoped>
</style>
package.json
"dependencies": {
"#codemirror/lang-html": "^6.1.1",
"#codemirror/lang-javascript": "^6.1.0",
"#codemirror/lang-json": "^6.0.0",
"#monaco-editor/loader": "^1.3.2",
"codemirror": "^6.0.1",
"core-js": "^3.8.3",
"monaco-editor": "^0.34.0",
"monaco-editor-vue3": "^0.1.6",
"monaco-editor-webpack-plugin": "^7.0.1",
"monaco-languageclient": "^4.0.0",
"vscode-ws-jsonrpc": "^2.0.0",
"vue": "^3.2.13",
"vue-class-component": "^8.0.0-0",
"vue-codemirror": "^6.1.1",
"vue-monaco": "^1.2.2",
"vue-router": "4"
},

"Module parse failed: Unexpected token." Trying to import Bootstrap 5 in VueJS 2

I encountered a strange error trying to add bootstrap 5.1.3 to VueJS 2.5.2
error in ./node_modules/bootstrap/dist/js/bootstrap.esm.js
Module parse failed: Unexpected token (1243:15)
You may need an appropriate loader to handle this file type.
|
| _getConfig(config) {
| config = { ...Default$a,
| ...Manipulator.getDataAttributes(this._element),
| ...(typeof config === 'object' ? config : {})
# ./src/main.js 11:0-19
# multi (webpack)-dev-server/client?http://localhost:8080 webpack/hot/dev-server ./src/main.js
This is the problematic Vue App component:
import App from './App'
import store from './store/index'
import "bootstrap/dist/css/bootstrap.min.css"
import "bootstrap"
/* eslint-disable no-new */
new Vue({
el: '#app',
store,
components: { App },
template: '<App/>'
})
If I remove the import "bootstrap" line, it compiles. But once I add import "bootstrap" it breaks.
Here are my dependencies:
"dependencies": {
"#popperjs/core": "^2.11.5",
"axios": "^0.26.1",
"bootstrap": "^5.1.3",
"bootstrap-icons": "^1.8.1",
"lodash": "^4.17.21",
"qs": "^6.10.3",
"vue": "^2.5.2",
"vue-router": "^3.0.1",
"vuex": "^3.6.2"
},

#Vue/test-utils shallowMount outputs "[Vue warn]: Unknown custom element" for vuetify components

My unit test in Vue outputs the following warning not just for <v-col> but for every single vuetify component:
[Vue warn]: Unknown custom element: < v-col> - did you register the
component correctly? For recursive components, make sure to provide
the "name" option.
I created a localVue and added Vuetify, but that doesn't seem to work. This is my test case:
import { shallowMount, createLocalVue } from '#vue/test-utils'
import expect from 'expect'
import ProjetoShow from '../../views/Projeto/ProjetoShow.vue'
import Vuetify from 'vuetify'
describe('ProjetoShow component', () => {
let wrapper
let localVue
beforeEach(() => {
localVue = createLocalVue()
localVue.use(Vuetify)
})
it('renders correctly', ()=> {
let vuetify = new Vuetify()
wrapper = shallowMount(ProjetoShow, {localVue, vuetify})
expect(wrapper.find('h2').text()).toContain('PROJETO')
})
})
my packages versions in package.json
"devDependencies": {
"#vue/test-utils": "^1.0.0-beta.31",
"axios": "^0.19.0",
"cross-env": "^5.1",
"expect": "^24.9.0",
"jsdom": "^15.1.1",
"jsdom-global": "^3.0.2",
"laravel-mix": "^4.0.7",
"lodash": "^4.17.13",
"mocha": "^6.2.0",
"mochapack": "^1.1.5",
"resolve-url-loader": "^2.3.1",
"sass": "^1.15.2",
"sass-loader": "^7.1.0",
"vue": "^2.5.17",
"vue-template-compiler": "^2.6.10"
},
"dependencies": {
"vue-router": "^3.1.3",
"vuetify": "^2.2.15",
"vuex": "^3.1.1"
},
I made a mistake by adding vuetify to localVue and not Vue. This changed fixed it. Depending on the version used this can still output some errors. Update vuetify, #vue/test-utils and mocha to latests versions if something goes wrong.
import { shallowMount, createLocalVue } from '#vue/test-utils'
import expect from 'expect'
import ProjetoShow from '../../views/Projeto/ProjetoShow.vue'
import Vuetify from 'vuetify'
import VueRouter from 'vue-router'
import Vue from 'vue'
Vue.use(Vuetify)
describe('ProjetoShow component', () => {
let wrapper
let localVue
beforeEach(() => {
localVue = createLocalVue()
localVue.use(VueRouter)
})
it('renders correctly', ()=> {
let router = new VueRouter()
let vuetify = new Vuetify()
wrapper = shallowMount(ProjetoShow, {localVue, router, vuetify})
expect(wrapper.find('h2').text()).toContain('PROJETO')
})
})
In Vuetify's documentation on Unit Testing, they declare let vuetify in the describe block, then in beforeEach, assign that variable to a new Vuetify()
I don't see you actually initializing Vuetify anywhere in your test code, so perhaps that's what's needed here.
I found two different solutions:
One, register vuetify in test file (of moment i did not found a way to declare globally)
import Vue from 'vue'
import Vuetify from 'vuetify'
Vue.use(Vuetify)
Two, add stubs to wrapper with specific vuetify components
wrapper = shallowMount(ProjetoShow, {stubs: ['v-col']})
Edit, i found the solution for declare globally, is necessary create a file setup.js in tests folder as the doc says and add the path in test configuration file, in case of jest in jest.config.js adding setupFiles: ['./tests/setup.js']

Vue.js and Webpack - Failed to mount component: template or render function not defined

I keep getting the following error for some global components that I have:
Failed to mount component: template or render function not defined.
found in
---> <Paginator>
<Root>
This is what I have in package.json:
{
"version": "1.0.0",
"scripts": {
"dev": "cross-env NODE_ENV=development webpack",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
},
"dependencies": {
"vue": "^2.4.4"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
],
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-2": "^6.0.0",
"babel-preset-vue-app": "^1.2.0",
"babel-plugin-transform-runtime": "^6.0.0",
"cross-env": "^5.0.5",
"css-loader": "^0.28.7",
"file-loader": "^1.1.4",
"fs": "^0.0.1-security",
"node-sass": "^4.5.3",
"sass-loader": "^6.0.6",
"vue-loader": "^13.0.5",
"vue-template-compiler": "^2.4.4",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.1"
}
}
In webpack.config i have the following defined:
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
And this is my main js file:
import Vue from 'vue';
Vue.component('paginator', require('./components/Paginator.vue'));
var vm = new Vue({
el: '#root',
data: {}
});
html:
<div id="root>
<paginator v-bind:total-items="totalItems" v-bind:page-size="query.pageSize" v-bind:page="query.page" v-on:pagechanged="onPageChange"></paginator>
</div>
any ideas why im getting this error?
When I change the code as follows is seems to work however I want to register the paginator as a global component:
import Vue from 'vue';
import Paginator from './components/Paginator.vue';
var vm = new Vue({
el: '#root',
components: {
'paginator': Paginator
},
data: {}
});
This is the paginator component:
<template>
<div>
<div >
<nav>
<ul class="pagination">
...
</ul>
</nav>
</div>
</div>
</template>
<script>
export default {
props: ['totalItems', 'pageSize', 'page'],
data: function () {
return {
currentPage: 1,
}
},
computed: {
pages: function () {
this.currentPage = this.page;
var pageArray = [];
var pagesCount = Math.ceil(this.totalItems / this.pageSize);
for (var i = 1; i <= pagesCount; i++)
pageArray.push(i);
return pageArray;
}
},
methods: {
changePage: function (page){
this.currentPage = page;
this.$emit('pagechanged', page);
},
previous: function (){
if (this.currentPage == 1)
return;
this.currentPage--;
this.$emit('pagechanged', this.currentPage);
},
next: function () {
if (this.currentPage == this.pages.length)
return;
this.currentPage++;
this.$emit('pagechanged', this.currentPage);
}
},
}
I believe this line is the issue - require inside the component declaration hasn't ended well for me when using it (although I've not looked into why).
Edit: See #DecadeMoon answer for info on this.
Vue.component('paginator', require('./components/Paginator.vue'));
Recommended way:
import Paginator from './components/Paginator.vue'
Vue.component('paginator', Paginator);
You can also do one of the following which will make webpack split the module into a separate file download asynchronously (this can be useful for large components)
Option 1:
Vue.component('paginator', () => import('./components/Paginator.vue'));
Option 2:
I have a load function that wraps this as it allows me to pass a string and wrap the directory without having to type it multiple times but this is a simple version of that function I use:
function load (component) {
return () => import(component)
}
so it would become:
Vue.component('paginator', load('./components/Paginator.vue'));
This is a consequence of the way Webpack combines require (CommonJS) and import (ES6) module import styles.
I always recommend using ES6-style import syntax.
If you must use require, then you will need to select the default import as follows:
Vue.component('paginator', require('./components/Paginator.vue').default);
^^^^^^^^
I recommend using ES6 import syntax instead (it's a standardized, non-webpack-specific syntax):
import Paginator from './components/Paginator.vue';
Vue.component('paginator', Paginator);
The reason why import() syntax works is because of this issue. Only use import() if you want the module to be split into a separate file and downloaded asynchronously by Webpack.