Mocking just part of getters when importing the global store - vuejs2

Any idea if it is possible to mock just a getter from the global store ?
I tried this code but It does not work:
import store from '#/store';
import Vuex from "vuex";
const localVue = createLocalVue();
localVue.use(VueRouter);
localVue.use(Vuex);
const wrapper = mount(App, {
mocks: {
$store: {
getters: {
isLoggedIn: () => true // This is always returning false. I need this getter to return true value
},
}
},
store, // this is the global store for my application
localVue,
router,
});

It would be much easier just to use mocks property while mounting the component without calling localVue.use(Vuex) and without creating store instance:
const wrapper = mount(App, {
localVue,
router,
mocks: {
$store: {
getters: {
isLoggedIn: () => () => true,
}
}
}
});

I solved my problem with inspiration from the Vue Testing Handbook examples here.
import * as otherNameThanStore from '#/store'; // we need to change the name to anyone other than store
import Vuex from "vuex";
const localVue = createLocalVue();
localVue.use(VueRouter);
localVue.use(Vuex);
const store = new Vuex.Store( // attribute name must be store, otherwise typescript will throw this error: is not assignable to parameter of type 'FunctionalComponentMountOptions<Vue>'
{
state: {
...otherNameThanStore.default.state
},
getters: {
...otherNameThanStore.default.getters,
isLoggedIn: (state) => () => true,
},
}
)
const wrapper = mount(App, {
store,
localVue,
router,
});
Hope it helps other people :)

Related

Is there a way to make my vue jest test with mock vuex instead of the app store

const localVue = createLocalVue();
localVue.use(Vuex);
describe('Dashboard component', () => {
let store;
let userDataStore;
beforeEach(() => {
userDataStore = {
namespaced: true,
state: {
sessionId: 'k5gv7lc3jvol82o91tddjtoi35kv16c3',
},
};
store = new Vuex.Store({
modules: {
userDataStore: userDataStore,
},
});
});
it('it renders the header component if there is a session id', () => {
const wrapper = shallowMount(DashboardPage, {
store,
localVue,
});
const headerComponent = wrapper.findComponent({ name: 'DashboardPage' });
expect(headerComponent.exists()).toBe(true);
});
});
but it keeps trying to access the app's main vuex and it should instead make use of the test mockup.

vuex unknown action type: 'auth/Signup'

I was trying to create a signup page using my auth module in vuex. I posted an api for signing up from action in the module. When I tried this code, it said "[vuex] unknown action type: auth/signUp" in the console. Did I do anything wrong? Can anyone solve this?
This is my vuex auth module
// store/auth/index.jx
import auth from '#/API/API_Auth'
const state = () => ({})
const getters=()=>({})
const mutations = () => ({})
const actions = () => ({
signUp({commit},data){
return auth.signUp(data)
.then(res=>{
console.log(res)
})
.catch(err=>{
console.log(err)
})
}
})
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
My vuex store.
// store/index.js
import Vue from "vue";
import Vuex from "vuex"
import auth from './module/auth'
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
auth,
},
state:{},
getters:{},
mutations:{},
actions:{},
})
I imported the store and router in main.js
// main.js
import store from "./store"
import router from "./router";
new Vue({
store,
router,
render: (h) => h(App),
}).$mount("#app");
This is my sign up component where I call the action.
// src/component/signup.vue
<script>
export default {
data() {
return {
name: "",
telNumber: "",
};
},
methods: {
handleSubmit() {
let name= this.name
let telNumber= this.telNumber
this.$store.dispatch("auth/signUp", {name,telNumber})
.then(res=>{
this.$router.push({path: 'otp'});
})
.catch(err=>{console.log(err)})
}
}
}
};
</script>
Your Vuex module incorrectly sets actions, mutations, and getters as functions. Only state should be a function, and the rest should be objects:
const state = () => ({}) // ✅ function
const getters = {} // ✅ object
const mutations = {} // ✅ object
const actions = { // ✅ object
signUp({ commit }, data) {}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}

Mock of store action of vuex does not mocked

I have small vue component that on created hook dispatch some action
#Component
export default class SomeComponent extends Vue {
created() {
store.dispatch('module/myAction', { root: true });
}
}
and I wrote next test
const localVue = createLocalVue();
localVue.use(Vuex);
localVue.use(VueRouter);
const localRouter = new VueRouter();
describe('SomeComponent.vue Test', () => {
let store: any;
beforeEach(() => {
store = new Vuex.Store({
modules: {
module: {
namespaced: true,
actions: {
myAction: jest.fn()
}
}
}
});
});
it('is component created', () => {
const wrapper = shallowMount(SomeComponent, {
localVue,
store,
propsData: {}
});
expect(wrapper.isVueInstance()).toBeTruthy();
});
});
but for some reason the "real" code are executed and I got a warning
isVueInstance() is deprecated. In your test you should mock $store object and it's dispatch function. I fixed typo in created(), here's my version of SomeComponent and working test, hope that would help.
#Component
export default class SomeComponent extends Vue {
created () {
this.$store.dispatch('module/myAction', { root: true })
}
}
import { shallowMount, Wrapper } from '#vue/test-utils'
import SomeComponent from '#/components/SomeComponent/SomeComponent.vue'
let wrapper: Wrapper<SomeComponent & { [key: string]: any }>
describe('SomeComponent.vue Test', () => {
beforeEach(() => {
wrapper = shallowMount(SomeComponent, {
mocks: {
$store: {
dispatch: jest.fn()
}
}
})
})
it('is component created', () => {
expect(wrapper.vm.$store.dispatch).toBeCalled()
expect(wrapper.vm.$store.dispatch).toBeCalledWith('module/myAction', { root: true })
})
})
Also keep in mind that when you test SomeComponent or any other component you should not test store functionality, you should just test, that certain actions/mutations were called with certain arguments. The store should be tested separately. Therefore you don't need to create real Vuex Store when you test components, you just need to mock $store object.

Can't seem to test Vuex Mutation in Vue Component

What should be pretty simple seems to be alluding me...
I have a vue component that when the correct html tag is clicked, a method is run that triggers a commit mutation.
All I want to do is see that the mutation is indeed triggered in the component. I can see the method get triggered but not the mutation that the method calls.
I am using Jest for testing
Goal: Verify the 'setEditUser' commit is called.
Dashboard
...
<tr
id="editUserTr"
class="col1"
v-for="listUser in users"
v-bind:key="listUser.email"
#click="editUser(listUser)"
>
<td>{{listUser.id}}</td>
<td>{{listUser.first_name}}</td>
...
methods: {
editUser(listUser) {
this.$store.commit("setEditUser", listUser);
this.$router.push("/editUser");
},
dashboardTest.spec.js
import { shallowMount, createLocalVue } from '#vue/test-utils';
import Dashboard from '../../src/components/Dashboard.vue';
import VueRouter from 'vue-router';
import Vuex from 'vuex';
const fb = require('../../src/firebaseConfig.js');
const sinon = require('sinon');
const localVue = createLocalVue();
localVue.use(Vuex, VueRouter);
describe('Dashboard.js', () => {
beforeEach(() => {
const mutations = {
setEditUser: jest.fn(),
};
const getters = {
userProfile: () => jest.fn(),
users: () => jest.fn(),
};
const $router = {
push: jest.fn(),
};
const store = new Vuex.Store({ mutations, getters });
});
test('Edit User function does not error out', () => {
const userProfile = {
role: ['admin'],
};
const wp = shallowMount(Dashboard, {
store,
localVue,
mocks: {
$router,
},
computed: {
userProfile() {
return userProfile;
},
users() {
return {
users: {
id: 'someEmail#email.com',
first_name: 'Stub',
},
};
},
},
});
const userInfo = wp.vm.users;
const stub = sinon.stub(wp.vm, 'editUser');
wp.findAll('td').at(0).trigger('click');
expect(mutations.setEditUser).toHaveBeenCalledWith({}, {userInfo}) // Fails. Says: Number of calls = 0
expect(stub.callCount).toBe(1);// Passes
});
});
Thanks for your help!
Edit:
Figured it out....
When I create this constant
const stub = sinon.stub(wp.vm, 'editUser');
I am messing with how the commit and router get called. Probably not passing in the proper arguments to the stub. I tried adding the proper arguments to the stub but still no go.
If I remove the stub then I can verify that the commit and push methods get called.
So... I created another unit test that just test that. Its more code then what I would like but I did solve my issue for now :)

Vue Test Mock Promise-Based Action within Module

I unfortunately can't attach all code or create a gist because the project I'm working on is related to work but I can give enough detail that I think it will work.
I'm trying to mock a call to an action that is stored in a different module but for the life of me I can't figure out how to. I'm able to create a Jest spy on the store.dispatch method but I want to be able to resolve the promise and make sure that the subsequent steps are taken.
The method in the SFC is
doSomething(data) {
this.$store.dispatch('moduleA/moduleDoSomething',{data: data})
.then(() => {
this.$router.push({name: 'RouteName'})
})
.catch(err => {
console.log(err)
alert('There was an error. Please try again.')
})
},
This is what my test looks like:
import { mount, createLocalVue } from '#vue/test-utils'
import Vuex from 'vuex'
import Vuetify from 'vuetify'
import Component from '#/components/Component'
import moduleA from '#/store/modules/moduleA'
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(Vuetify)
describe('Component.vue', () => {
let actions
let store
const $router = []
beforeEach(() => {
actions = {
moduleDoSomething: jest.fn((payload) => {
return Promise.resolve({
status: 200,
})
})
}
store = new Vuex.Store({
state: {},
modules: {
moduleA: {
actions
}
},
})
})
it('does something', () => {
const wrapper = mount(Component, {
store,
localVue,
mocks: {
$router,
},
})
let button = wrapper.find('button that calls doSomething')
button.trigger('click')
expect(actions.moduleDoSomething).toHaveBeenCalled()
expect(wrapper.vm.$router[0].name).toBe('RouteName')
})
})
The following test passes, but I don't want to just test that the action was dispatched; I also want to test things in the "then" block.
it('does something', () => {
const dispatchSpy = jest.spyOn(store, 'dispatch')
const wrapper = mount(Component, {
store,
localVue,
mocks: {
$router,
},
})
let button = wrapper.find('button that calls doSomething')
button.trigger('click')
expect(dispatchSpy).toHaveBeenCalledWith('moduleA/moduleDoSomething',{data: data})
})
})
I managed to solve this problem by simply making the module namespaced in the mocked store.
store = new Vuex.Store({
state: {},
modules: {
moduleA: {
actions,
namespaced: true
}
},
})
I'll delete the question in a little bit