Error in cypress: Object(...) is not a function - vue.js

This is my test component:
<template>
<div class="container">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String,
},
data () {
},
}
</script>
<style>
.container {
max-width: 500px;
margin: 30px auto;
overflow: auto;
min-height: 300px;
border: 1px solid steelblue;
padding: 30px;
border-radius: 5px;
}
</style>
And this is my test:
import { mount } from '#cypress/vue'
import HelloWorld from '../../src/HelloWorld.vue'
describe('HelloWorld', () => {
it('renders a message', () => {
const msg = 'Hello Cypress Component Testing!'
mount(HelloWorld, {
propsData: {
msg,
},
})
cy.get('h1').should('have.text', msg)
})
})
Below is the output in Cypress when I run yarn cypress open-ct:

Maybe it's too late but the solution for me was to change import { mount } from 'cypress' to import { mount } from 'cypress/vue2 in the test file. That solved my problem.

Related

getActivePinia was called with no active Pinia. Vue

i get this error: Uncaught Error: [šŸ]: getActivePinia was called with no active Pinia. Did you forget to install pinia?
const pinia = createPinia()
app.use(pinia)
This will fail in production.
at useStore (pinia.mjs:1691:19)
at PokemonDetails.vue:3:22
what's wrong with my code?
pokemonDetails:
<script>
import { usePokemonStore } from '../stores/PokemonStore';
const pokemonStore = usePokemonStore();
export default {
name: 'PokemonDetails',
methods: {
evolutions() {
return [
pokemonStore.evolutionOne,
pokemonStore.evolutionTwo,
pokemonStore.evolutionThree,
];
},
resetApp() {
this.$router.push('/');
pokemonStore.$reset();
},
},
};
</script>
<template>
<template v-if="pokemonStore.findPokemon == false">
<div class="firstDiv">
<div class="secondDiv">
<div>
<strong>{{ pokemonStore.pokemonName }}</strong
><img :src="pokemonStore.selfie" alt="foto de pokemon" />
<p>Elemento Principal: {{ pokemonStore.type }}</p>
</div>
<div>
<strong>Habilidades:</strong>
<ul>
<li v-for="stat in pokemonStore.stats[0]">
{{ stat.stat.name }}: +{{ stat.base_stat }}
</li>
</ul>
</div>
</div>
<div class="divEvolutions">
<strong>EvoluĆ§Ć£o</strong>
<ul class="evolutions">
<li v-for="evolution in evolutions">
<img :src="evolution.selfie" />
{{ evolution.name }}
</li>
</ul>
</div>
<button v-on:click="resetApp" class="newSearch">Nova pesquisa</button>
</div>
</template>
</template>
<style lang="scss" scoped>
.firstDiv {
text-align: center;
}
.secondDiv {
display: grid;
justify-items: center;
align-items: center;
grid-template-columns: repeat(2, 1fr);
max-height: 600px;
width: 400px;
padding: 20px;
border-radius: 1.5rem;
background-color: $gray-200;
div {
display: flex;
flex-direction: column;
}
}
.divEvolutions {
background-color: $gray-200;
border-radius: 1.5rem;
margin-top: 10px;
}
.evolutions {
display: flex;
justify-content: center;
align-items: center;
li {
display: flex;
flex-direction: column;
}
}
.newSearch {
margin-top: 10px;
padding: 5px;
border-radius: 1rem;
background-color: $gray-200;
transition-duration: 500ms;
&:hover {
background-color: black;
color: $gray-200;
}
}
</style>
pokemonStore.js:
import { defineStore } from 'pinia';
export const usePokemonStore = defineStore('pokemon', {
state: () => ({
findPokemon: true,
pokemonName: '',
speciesLink: '',
selfie: '',
type: '',
stats: [],
evolutionOne: {},
evolutionTwo: {},
evolutionThree: {},
}),
getters: {},
actions: {
addPokemon(
name,
species,
selfie,
type,
stats,
evolutionOne,
evolutionTwo,
evolutionThree
) {
this.pokemonName = name;
this.speciesLink = species;
this.selfie = selfie;
this.type = type;
this.stats.push(stats);
this.findPokemon = false;
this.evolutionOne = evolutionOne;
this.evolutionTwo = evolutionTwo;
this.evolutionThree = evolutionThree;
},
},
});
main.js:
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
import router from './router';
import './assets/main.css';
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.mount('#app');
i tried call my store in computed:
computed: {
pokemonStore() {
return usePokemonStore();
},
evolutions() {
return [
this.pokemonStore.evolutionOne,
this.pokemonStore.evolutionTwo,
this.pokemonStore.evolutionThree,
];
},
},
it works, but i believe is don't the best practices
Stores aren't supposed to be used before Pinia is installed to Vue application.
The reason why use... composables are created by Pinia defineStore instead of store objects is that this allows to avoid race conditions.
Here usePokemonStore is called on pokemonDetails import before Pinia install. pokemonStore is referred in the template while it's not a part of component instance. For a component with options API it should be:
name: 'PokemonDetails',
data() {
return { pokemonStore: usePokemonStore() }
},

Vuejs2.6 - Images not loading

I know there are several other questions about it, but none of them seems to help me.
I'm trying to create a simple Image component, but I images are not loading since I tried to use them in a component.
<template>
<!-- <img :click="go()" :src="require(`../assets/img/${filename}`)"> -->
<img :click="go()" :src="`../assets/img/'${filename}`">
</template>
<script>
export default {
name: 'Imagem',
data() {
return {
filename: ''
}
},
methods: {
go() {
console.log('image click')
}
}
}
</script>
<style scoped>
img{
min-width: 20%;
}
</style>
The first line throws error:
The second line, without require, gives no error but don't load the image (i restarted the project and cleaned cache)
This is the view where Imagem component is imported:
<template>
<div class="login-images">
<!-- <img #click="novoProfessor" src="../assets/professor.png" alt="" srcset="">
<img #click="novoAluno" src="../assets/aluno.png" alt="" srcset=""> -->
<Imagem :filename="'professor.png'" />
<Imagem :filename="'aluno.png'" />
</div>
</template>
<script>
import Imagem from '../components/Imagem';
export default {
name: 'Login',
components: {
Imagem
},
props: {
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.login-images {
min-width: 100%;
min-height: 50%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
.login-images > * {
margin: 10%;
}
</style>
Change your Imagem component like this:
<template>
<img :src="imageURL" #click="go">
</template>
<script>
export default
{
name: 'Imagem',
props:
{
filename:
{
type: 'String',
required: true
}
},
computed:
{
imageURL()
{
return `../assets/img/${this.filename}`;
}
},
methods:
{
go(event)
{
console.log('You clicked on the "' + event.target.src + '"');
}
}
}
</script>

Getting the computed method to another components (Vuejs)

i wanted to get the computed data and display in another component. However i put the computed in my app.vue and try to call this computed using :style="inputStyles" in my ChangeBackground.vue . But when i try to do this it showing error that " Property or method "inputStyles" is not defined on the instance but referenced during render" Can someone help me? Thank you
You can access the code here:
https://codesandbox.io/s/hardcore-morning-5ch1u?file=/src/components
Here is the code:
App.vue
<template>
<div id="app">
<ChangeBackground msg="Hello Vue in CodeSandbox!" />
</div>
</template>
<script>
import ChangeBackground from "./components/ChangeBackground";
export default {
name: "App",
components: {
ChangeBackground,
},
data() {
return {
bgColor: "red",
};
},
created() {
this.bgColor = "#F6780D";
},
computed: {
inputStyles() {
return {
background: this.bgColor,
};
},
},
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
body {
background-color: blue;
}
</style>
ChangeBackground.vue
<template>
<div class="hello" :style="inputStyles">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
msg: "Getting the computed area here to change the background",
};
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
h1,
h2 {
font-weight: bold;
}
ul {
list-style-type: none;
padding: 1rem;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
You should pass it as prop as you did with msg :
App.vue
<ChangeBackground msg="Hello Vue in CodeSandbox!" :input-styles="inputStyles" />
ChangeBackground.vue
<template>
<div class="hello" :style="inputStyles">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props:["inputStyles"],//ā¬…
data() {
return {
msg: "Getting the computed area here to change the background",
};
},
};
</script>

Why does Bootstrap Autocomplete send vue.js router go to /#/exclamationmark?

Why does it happen that my Vue router navigates to /#/! without apparent reason?
This seems to happen when I fire an event from an autocomplete form built with Bootstrap Autocomplete and trigger a function.
Calling the same function by clicking a button does not lead to the problem.
This is the parent component where the event is emitted to
<style scoped>
</style>
<template>
<div id="appspace">
<div id="leftbar">
</div>
<div id="workarea">
<div id="mapblock">
</div>
<div id="infoblock">
<div class="form-group"><label for="gotoff">Go to</label>
<autosuggest #locselect="locSelect($event)" id="gotoff"></autosuggest>
</div>
<button v-on:click="searchAround()" type="button" class="btn btn-primary">Search</button>
</div>
</div>
<div id="rightbar">
</div>
</div>
</template>
<script>
module.exports = {
data: function () {
return {
};
},
components: {
autosuggest: httpVueLoader('components/base/autosuggest.vue'),
},
mounted: function(){
},
destroyed: function(){
},
methods: {
setMarkerInCenter: function(){
this.locSelect({ value: { lng: 12, lat: 14 }})
},
locSelect: function(e) {
console.log('locSelect');
console.log(e);
},
},
}
</script>
and this is the component emitting the event:
<style scoped>
.autocomplete {
position: relative;
width: 130px;
}
.autocomplete-results {
padding: 0;
margin: 0;
border: 1px solid #eeeeee;
height: 120px;
overflow: auto;
}
.autocomplete-result {
list-style: none;
text-align: left;
padding: 4px 2px;
cursor: pointer;
}
.autocomplete-result:hover {
background-color: #4AAE9B;
color: white;
}
</style>
<template>
<div class="input-group">
<input ref="ac" class="form-control">
<div class="input-group-append">
<div class="input-group-text"><i class="fa fa-compass" style="height:0.5em;padding:0;margin:0;margin-bottom:4px"></i></div>
</div>
</div>
</template>
<script>
module.exports = {
mounted: function(){
var i = this.$refs.ac;
var c = this
$(i).autoComplete({ resolverSettings: { url: '/api/gc/autocomplete' } });
$(i).on('autocomplete.select', function(e, sel) {
e.preventDefault();
c.$emit('locselect', sel);
e.preventDefault();
});
},
}
</script>
Any leads as to how to debug this?
I couldn't find the reason why this autocomplete changes the route, that behavoir
seems to be undocumented. But here's a method to temporarily prevent this behavior until you find the solution, add this global route guard to your router to prevent navigation to '/#/!' route:
router.js
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
console.log(to)
// TEMP PATCH:
// Autocomplete changes route to '/#/!'
if (to.path !== '/#/!') {
next()
}
})
Just make sure that console.log(to) actually has a property path === '/#/!'

Delete item for todo app in with $emit 2 level up or 1 level up? [duplicate]

This question already has answers here:
Vue 2 - Mutating props vue-warn
(28 answers)
Closed 2 years ago.
I have 3 .vue here: App.vue (default), Todos.vue and Todoitem.vue. I am following the tutorial from https://www.youtube.com/watch?v=Wy9q22isx3U&t=2458. May I know why the author in TodoItem.vue emit id two level up to App.vue to perform the method to delete? Is it best practice or better coding style? Is it easier to just go up one level for Todos.vue to do the same? Below is my one level up approach for any comment.
Below is my TodoItem.vue code
<template>
<div class="todo-item" v-bind:class="{'is-complete':todoObj.completed}">
<p>
<input type="checkbox" v-on:change="markComplete" />
{{todoObj.title}}
<button #click="$emit('del-todo',todoObj.id)" class="del">x</button>
</p>
</div>
</template>
<script>
export default {
name: "TodoItem",
props: ["todoObj"], // todoObj is defined in the parent.
methods: {
markComplete() {
this.todoObj.completed = !this.todoObj.completed;
}
}
};
</script>
<style scoped>
.todo-item {
background: #f4f4f4;
padding: 10px;
border-bottom: 1px #ccc dotted;
}
.is-complete {
text-decoration: line-through;
}
.del {
background: #ff0000;
color: #fff;
border: none;
padding: 5px 9px;
border-radius: 50%;
cursor: pointer;
float: right;
}
</style>
Below is my Todo.vue code
<template>
<div>
<h1>Todo List2</h1>
<!-- :key= and v-bind:key= are exactly the same. -->
<!-- v-bind. Shorthand: : -->
<div v-for="todo in ptodos" :key="todo.id">
<!-- Define todoObj here which to be used in the child component, TodoItem -->
<MyTodoItem v-bind:todoObj="todo" v-on:del-todo="deleteTodo" />
<!-- del-todo is from the child. child goes up to parent and then to grandparent (App.vue) -->
</div>
</div>
</template>
<script>
import MyTodoItem from "./TodoItem.vue";
export default {
name: "Todos",
components: {
MyTodoItem
},
props: ["ptodos"],
methods: {
deleteTodo(id) {
this.ptodos = this.ptodos.filter(todo => todo.id !== id);
}
}
};
</script>
<style scoped>
</style>
Below is my App.vue code
<template>
<MyToDos v-bind:ptodos="todos" />
</template>
<script>
import MyToDos from "./components/Todos";
export default {
name: "App",
components: { MyToDos },
data() {
return {
todos: [
{
id: 1,
title: "Todo One",
completed: false
},
{
id: 2,
title: "Todo Two",
completed: true
},
{
id: 3,
title: "Todo Three",
completed: false
}
]
};
}
};
</script>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, Helvetica, sans-serif;
line-height: 1.4;
}
</style>
If you can do it with one level up it's better. To have multiple props on each child can be a bad practice called prop drilling.
Vuex is a good alternative to avoid to get props nested.