How Test MapGetter - javascript

I would like to test if my getter is called in my component or view, but I don't understand how can it.
My method in the component :
computed: {
...mapGetters({ item: 'moduleA/getData' }),
},
And this is my unit test declaration :
beforeEach(() => {
store = new Vuex.Store({
modules: {
moduleA: {
state: {},
getters: {
getData() {
return { item: { name: 'test' } };
},
},
},
},
});
wrapper = shallowMount(MyComponent, {
store,
});
});
And I try to test if the data is loaded in my template:
it('should check if name is thruthy', () => {
expect(wrapper.find('.classA').text()).toEqual('test');
});
my component :
<template>
<v-content>
<ComponentA v-if="item.name"
key="keyA" ></ComponentA>
<ComponentB v-else key="keyA"></ComponentB>
</v-content>
</template>
<script>
import { mapGetters } from 'vuex';
import ComponentA from '#/components/ComponentA.vue';
import ComponentB from '#/components/ComponentB.vue';
export default {
/**
* Component's name :
*/
name: 'ViewA',
/**
* Component's used :
*/
components: {
ComponentA,
ComponentB,
},
/**
* computed's used :
*/
computed: {
...mapGetters({ item: 'moduleA/getData' }),
},
};
</script>
and my getter in the moduleA :
const getters = {
getData: state => state.data,
};
But I have this message:
TypeError: Cannot read property 'name' of undefined
Why? Thank you for your help.

As shown in docs, shallowMount's options has field named localVue. To solve your problem you should create a localVue, using createLocalVue and pass it to shallowMount.
createLocalVue returns a Vue class for you to add components, mixins
and install plugins without polluting the global Vue class.
import Vuex from 'vuex'
import { createLocalVue, shallowMount } from '#vue/test-utils'
beforeEach(() => {
const localVue = createLocalVue()
localVue.use(Vuex)
store = new Vuex.Store({
modules: {
moduleA: {
state: {},
getters: {
getData() {
return { item: { name: 'test' } }
},
},
},
},
})
wrapper = shallowMount(MyComponent, {
localVue,
store,
})
})

Related

Vue 3 cdn example with vuex 4, but how do I access the store inside main.js?

My app structure:
> public
> scripts
> - cdn
> - vue.js
> - vuex.js
> main.js
> store.js
> index.html
Inside the head tag I have:
<script src="./scripts/cdn/vue.js"></script>
<script src="./scripts/cdn/vuex.js"></script>
<script src="./scripts/main.js" type="module"></script>
And in the body I have-
<div id="app"> <div v-for="item in items" >{{item.text}}</div> </div>
store.js
console.log('test in store.js', store.state)
const store = new Vuex.createStore({
state: {
items: [{
text: 'ahhh STORE 1'
}, {
text: 'ahhh STORE 2'
}],
},
mutations: {
},
actions: {
test({
state
}) {
console.log(state.items)
}
},
modules: {
}
})
main.js
import * as store from "./store.js";
const {
onMounted,
onUpdated,
onUnmounted,
ref,
reactive,
getCurrentInstance
} = Vue; //here define only what you need
//Define Vue app
const App = {
state: store,
// store, //using either store or state: store does not work
data() {
return {};
},
methods: {},
setup(props, context) {
onMounted(() => {
console.info("App mounted!");
console.log('mounted state', store.state)
});
onUpdated(() => {
console.info("App updated!");
});
onUnmounted(() => {
console.info("App unmounted!");
});
}
};
// Create new Vue app
const app = Vue.createApp(App);
app.use(store)
app.mount("#app");
So when the app runs, in the console it shows
test in store.js Proxy { <target>: {…}, <handler>: {…} }
But in onMounted it returns store.state as undefined.
It can work by using createStore inside main.js but I would like to keep this separated.
What am I missing and how do I make the store accessible in the main?
app.use(store) -
you have already added the store to the vue instance.
Then you can access this storage from any component, for example using:
import { mapState} from 'vuex';
...
computed: {
...mapState({
items: state => state.items
}),
},
or in setup:
import { useStore } from 'vuex';
...
setup(){
const store = useStore();
const state = store.state; // <-- state from vuex
}
Your working example:
const store = new Vuex.createStore({
state: {
items: [{
text: 'ahhh STORE 1'
}, {
text: 'ahhh STORE 2'
}],
},
mutations: {
},
actions: {
test({
state
}) {
console.log(state.items)
}
},
modules: {
}
})
const {
onMounted,
onUpdated,
onUnmounted,
ref,
reactive,
} = Vue; //here define only what you need
//Define Vue app
const App = {
data() {
return {};
},
methods: {},
computed: {
...Vuex.mapState({
items: state => state.items
}),
},
setup(props, context) {
const store = Vuex.useStore()
onMounted(() => {
console.info("App mounted!");
console.log('mounted state', store.state)
});
onUpdated(() => {
console.info("App updated!");
});
onUnmounted(() => {
console.info("App unmounted!");
});
}
};
// Create new Vue app
const app = Vue.createApp(App);
app.use(store)
app.mount("#app");
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<script src="https://unpkg.com/vuex#4.0.0/dist/vuex.global.js"></script>
<div id="app">
<div v-for="item in items">{{item.text}}</div>
</div>

Test element in module with vue-utils

Here is my problem that I can't solve:
I would like to test the yearsDropdownItems function of my MonthlyFoodCostModal component.
However, I keep getting this error:
TypeError: Cannot read properties of undefined (reading 'outlet_start_date')
How can I set a value to activeOutlet?
Here is my component code :
import { createNamespacedHelpers } from "vuex";
const { mapGetters: userGetters } = createNamespacedHelpers("user");
export default {
computed: {
yearsDropdownItems,
...userGetters([
"activeOutlet"
])
},
};
function yearsDropdownItems() {
const outletStartYear = moment(this.activeOutlet.outlet_start_date).year(),
outletEndYear = moment(this.activeOutlet.outlet_data_validity).year(),
years = this.$utils.range(outletStartYear, outletEndYear);
return this.$utils.sortDesc(years);
}
Here is my test code :
import { mount } from "#vue/test-utils"
import MonthlyFoodCostModal from "#/components/monthlyFoodCostModal/monthlyFoodCostModal.js"
import User from "#/store/Module/User/userModule.js"
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
let state;
let store;
describe('Unit test MonthlyFoodCostModal.vue', () => {
beforeEach(() => {
state = {}
store = new Vuex.Store({
modules: {
User: {
state,
getters: User.getters,
namespaced: true
}
}
})
})
it('test yearsDropdownItems method', async() => {
const wrapper = mount(MonthlyFoodCostModal, {store})
expect(wrapper.vm.yearsDropdownItems).toBe("?")
})
})
I didn't put anything in the "expect" part because the error happens before the test is viewed.
My module behaves as follows:
const initialState = () => ({
user: {
firstName: "",
lastName: "",
role: ""
},
properties: [],
activeProperty: null,
activeOutlet: null,
selectedDevicesFilter: [],
});
export default {
namespaced: true,
state: initialState(),
getters: {
activeOutlet: state => state.activeOutlet
}
}

How to mock extended component vue.js

I have the following problem, I want to test a component in vuejs which extends another component like this :
<template>
<div></div>
</template>
<script>
import MySuperComponent from '#/project/MySuperComponent'
export default {
extends: MySuperComponent,
name: myComponent,
components: {
}
</script>
my test look like this :
import {createLocalVue, shallowMount, mount} from '#vue/test-utils'
// Component to test
import myComponent from '#/project/myComponent.vue'
// import store
import Vuex from 'vuex'
// LIB
import VueI18n from "vue-i18n"
describe(`myComponent.vue`, () => {
const localVue = createLocalVue()
let i18n, store, getters, state, mutations, actions
beforeAll(() => {
localVue.use(Vuex)
getters = {
mygetters: jest.fn()
}
state = {
getNames: jest.fn(),
}
mutations = {}
actions = {}
store = new Vuex.Store({
getters, state, mutations, actions
})
localVue.use(VueI18n)
i18n = new VueI18n({
silentTranslationWarn: true
})
})
it(`Test default mounted myComponent ok`, () => {
const wrapper = mount(myComponent, {
propsData: {
component : 'mycompnent',
json : {},
animationEnabled: true
},
computed: {
getNames : jest.fn(),
},
watch: {
ageUser : jest.fn(),
},
i18n,
localVue,
store
})
expect(wrapper.exists()).toBeTruthy()
})
})
the problem is even if my component is empty I need to set all the props of the extended component and all the computed .... I tried using jest.mock(MySuperComponent) but nothing work, my goal here is just to test what's inside my component

vuex unknown action type: showRegisterLogin/show

I wrote the following code but it shows an error. What is the reason for this?
Error
[vuex] unknown action type: showRegisterLogin/show
HomePage.vue // component
When using the sh method This error is caused
import { mapState, mapActions } from "vuex";
export default {
name: "HomePage",
components: {
RegisterLogin
},
data() {
return {}
},
computed: {
...mapState({
showRegisterLogin: state => state.showRegisterLogin.show
}),
},
methods: {
sh() {
this.$store.dispatch('showRegisterLogin/show');
}
}
}
/ store / modules / showRegisterLogin.js
// States
const state = {
show: false,
};
// Getters
const getter = {
show (state) {
return state.show;
}
};
// Mutations
const mutation = {
showPage (state) {
return state.show = true;
},
hidePage (state) {
return state.show = false;
}
};
// Actions
const action = {
show({ commit }) {
commit('showPage');
},
hide({ commit }) {
commit('hidePage');
}
};
export default {
namespaced: true,
state,
getter,
mutation,
action
}
/ store / store.js
'use strict';
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
import showRegisterLogin from "./modules/showRegisterLogin";
export default new Vuex.Store({
modules: {
showRegisterLogin,
}
});
I also imported the store.js file into app.js and registered it in new vue
The structure of the store, module, and component are fine, except for the name of the store objects in your module:
getter should be getters
mutation should be mutations
action should be actions
Probably just typos. Those can't be arbitrarily named since Vuex looks specifically for those keys.

vuejs 2.0 components failed to access action methods with module vuex

I'm testing Vuejs 2.0 & Vuex with modules design but components can't access to action methods.
my component :
import {mapGetters, mapActions} from 'vuex'
export default {
computed: mapGetters({
clients: 'clients',
fields: 'fields'
}),
methods: mapActions({
init: 'init'
}),
created: () => {
console.log(this.init)
}
}
my module :
const state = {
'fields': [
{
'field': 'name',
'label': 'Nom'
},
{
'field': 'adresse',
'label': 'Adresse'
},
{
'field': 'amount',
'label': 'Amount'
},
{
'field': 'contact',
'label': 'Contact'
}
],
items : []
}
export const SET_CLIENTS = 'SET_CLIENTS'
const mutations = {
[SET_CLIENTS] (state, clients) {
state.items = clients;
}
}
const actions = {
init: ({ commit }, payload) => {
let clients = []
for(let i = 0; i < 100; i++){
clients.push({
'name': 'Client '+i,
'adresse': '14000 Caen',
'amount': '1000',
'contact': 'contact#client'+i+'.com'
})
}
commit(SET_CLIENTS, { clients })
}
}
const getters = {
clients (state) {
return state.items;
},
fields (state) {
return state.fields;
}
}
export default {
state,
mutations,
getters,
actions
}
the store creation :
import Vuex from 'vuex'
import clients from './modules/clients'
import filters from './modules/filters'
import Vue from 'vue'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
clients,
filters
}
})
All the project code is available here :https://github.com/robynico/vuejs-2.0-modules
If you test it, you will see that init method is undefined at component creation.
Thanks in advance!
I think you are exporting your store modules wrong. Try this:
Inside your module.js:
export default {
state: {}, // define your state here
getter: {}, // define your getters here
actions: {}, // define your actions here
mutations: {} // define your mutations here
}
Then inside your store:
import Vue from 'vue'
import Vuex from 'vuex'
import module from './modules/module.js'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
module // your moudle
}
})
export default store

Categories

Resources