How acccess mutation from one store file for another store file? - vuex

How can I access a mutation from one file in my store folder that exists in another file in my store folder?
Here's my directory:
store/
user.js
loading.js
In user.js I have:
async googleSignInRedirect({ commit }) {
try {
const result = await this.$fire.auth.getRedirectResult()
if (result.credential) {
// const credential = result.credential
// console.log('got a credential? ', credential)
this.$router.replace('/')
commit('loading/SET_LOADING', false) //< -- what is correct way to write this ?
}
return null
} catch (error) {
console.error(error)
}
},
Here is the loading.js code:
export const state = () => ({
loading: false
})
export const mutations = {
SET_LOADING(state, payload) {
state.loading = payload
}
}
How can I access loading.js from user.js ? If I do the above style, I get the following error in console:
vuex.esm.js?2f62:791 [vuex] unknown local mutation type: loading/SET_LOADING, global type: user/loading/SET_LOADING

Just pass { root: true } as the final argument to commit, so:
async googleSignInRedirect({ commit }) {
try {
const result = await this.$fire.auth.getRedirectResult()
if (result.credential) {
this.$router.replace('/')
commit('loading/SET_LOADING', false, { root: true })
}
return null
} catch (error) {
console.error(error)
}
}
You can find more details in the Vuex documentation.

Related

How to mock vue composable functions with jest

I'm using vue2 with composition Api, vuex and apollo client to request a graphql API and I have problems when mocking composable functions with jest
// store-service.ts
export function apolloQueryService(): {
// do some graphql stuff
return { result, loading, error };
}
// store-module.ts
import { apolloQueryService } from 'store-service'
export StoreModule {
state: ()=> ({
result: {}
}),
actions: {
fetchData({commit}) {
const { result, loading, error } = apolloQueryService()
commit('setState', result);
}
},
mutations: {
setState(state, result): {
state.result = result
}
}
}
The Test:
// store-module.spec.ts
import { StoreModule } from store-module.ts
const store = StoreModule
describe('store-module.ts', () => {
beforeEach(() => {
jest.mock('store-service', () => ({
apolloQueryService: jest.fn().mockReturnValue({
result: { value: 'foo' }, loading: false, error: {}
})
}))
})
test('action', async ()=> {
const commit = jest.fn();
await store.actions.fetchData({ commit });
expect(commit).toHaveBeenCalledWith('setData', { value: 'foo' });
})
}
The test fails, because the commit gets called with ('setData', { value: undefined }) which is the result from the original apolloQueryService. My Mock doesn't seem to work. Am I doing something wrong? Appreciate any help, thanks!
Try this :
// store-module.spec.ts
import { StoreModule } from store-module.ts
// first mock the module. use the absolute path to store-service.ts from the project root
jest.mock('store-service');
// then you import the mocked module.
import { apolloQueryService } from 'store-service';
// finally, you add the mock return values for the mock module
apolloQueryService.mockReturnValue({
result: { value: 'foo' }, loading: false, error: {}
});
/* if the import order above creates a problem for you,
you can extract the first step (jest.mock) to an external setup file.
You should do this if you are supposed to mock it in all tests anyway.
https://jestjs.io/docs/configuration#setupfiles-array */
const store = StoreModule
describe('store-module.ts', () => {
test('action', async ()=> {
const commit = jest.fn();
await store.actions.fetchData({ commit });
expect(commit).toHaveBeenCalledWith('setData', { value: 'foo' });
})
}

Error "[vuex] unknown action type:" with vuejs

Created a new service .js called room.module.js
and inside my Vue view I have the following event on form submit:
submit: function(e) {
e.preventDefault();
var name = this.$refs.name.value;
var capacity = this.$refs.places.value;
// dummy delay
setTimeout(() => {
// send update request
this.$store.dispatch(CREATE_ROOM, {
"name": name,
"places": capacity
});
}, 2000);
and my service room.module.js:
// action types
import ApiService from "#/core/services/api.service";
import JwtService from "#/core/services/jwt.service";
export const CREATE_ROOM = "createNewRoom";
// mutation types
export const SET_ROOM_INFO = "setRoomInfo";
const state = {
room_info: {
name: "Room 1",
places: 10,
status: 1
}
};
const getters = {
currentRoomInfo(state) {
return state.room_info;
}
};
const actions = {
[CREATE_ROOM](context, payload) {
if (JwtService.getToken()) {
ApiService.setHeader();
ApiService.put("/room/create", payload).then(({ data }) => {
context.commit(SET_ROOM_INFO, payload);
return data;
});
}
}
};
const mutations = {
[SET_ROOM_INFO](state, room_info) {
state.room_info = room_info;
}
};
export default {
state,
actions,
mutations,
getters
};
but when I submit the form, the following error occurs:
[vuex] unknown action type: createNewRoom
I know I'm missing something, but can't figure out what.
Any ideas? Thank you!
It seems it needs to be added to the Vuex store.

Error: [vuex] Do not mutate vuex store state outside mutation handlers with Firebase Auth Object

I have been trying to solve this problem for a few hours now to no avail. Could someone help me spot the problem?
The error I am getting is:
Error: [vuex] Do not mutate vuex store state outside mutation handlers
Here is my login script section with the offending function in login()
<script>
import { auth, firestoreDB } from "#/firebase/init.js";
export default {
name: "login",
props: {
source: String
},
////////
layout: "login",
data() {
return {
show1: false,
password: "",
rules: {
required: value => !!value || "Required.",
min: v => v.length >= 8 || "Min 8 characters",
emailMatch: () => "The email and password you entered don't match"
},
email: null,
feedback: null
};
},
methods: {
login() {
if (this.email && this.password) {
auth
.signInWithEmailAndPassword(this.email, this.password)
.then(cred => {
//this.$router.push("/");
this.$store.dispatch("user/login", cred);
console.log()
this.$router.push("/forms")
console.log("DONE")
})
.catch(err => {
this.feedback = err.message;
});
} else {
this.feedback = "Please fill in both fields";
}
},
signup() {
this.$router.push("signup");
}
}
};
</script>
import { auth, firestoreDB } from "#/firebase/init.js";
export const state = () => ({
profile: null,
credentials: null,
userID: null
})
export const getters = {
getinfo:(state) =>{
return state.credentials
},
isAuthenticated:(state)=>{
if (state.credentials != null) {
return true
} else {
return false
}
}
}
export const mutations = {
commitCredentials(state, credentials) {
state.credentials = credentials
},
commitProfile(state, profile) {
state.profile = profile
},
logout(state){
state.credentials = null,
state.profile = null
}
}
export const actions = {
login({commit},credentials) {
return firestoreDB.collection("Users").where('email', '==', auth.currentUser.email).get()
.then(snapshot => {
snapshot.forEach(doc => {
let profile = {...doc.data()}
commit("commitCredentials", credentials)
commit("commitProfile", profile)
})
}).catch((e) => {
console.log(e)
})
},
credentials({ commit }, credentials) {
commit("commitCredentials",credentials)
},
logout() {
commit("logout")
},
}
I have checked that there is no where else that is directly calling the store state.
I have worked out that if I don't do the commitCredentials mutation which mutates credentials, the problem doesn't happen.
Another note to add, the error keeps printing to console as if it were on a for loop. So my console is flooded with this same message.
I am pretty sure this is to do with the firebase auth sign in and how the Credential object is being changed by it without me knowing, but I can't seem to narrow it down.
Any help would be very much welcomed.
Found the answer.
https://firebase.nuxtjs.org/guide/options/#auth
signInWithEmailAndPassword(this.email, this.password)
.then(cred)
"Do not save authUser directly to the store, since this will save an object reference to the state which gets directly updated by Firebase Auth periodically and therefore throws a vuex error if strict != false."
Credential object is constantly being changed by the firebase library and passing the credential object is just passing a reference not the actual values itself.
The solution is to just save the values within the object.

useMutation not mutating the local state

I'm getting this error while trying to mutate the local state in apollo.
errInvariant Violation: Expecting a parsed GraphQL document. Perhaps you need to wrap the query string in a "gql" tag? http://docs.apollostack.com/apollo-client/core.html#gql
Initial state
registration: {
__typename: 'Registration',
tempMerchantId: '',
authorizeProfile: {
__typename: 'AuthorizePersonProfile',
nid_front: '',
nid_back: '',
authorized_person_photo: ''
}
}
My mutation
export const setAuthorizePersonQuery = gql`
mutation setAuthorizePersonProfileInfo($authorizePerosnData: Object!){
setAuthorizePersonProfileInfo(authorizePersonData: $authorizePerosnData) #client
}
`;
My resolver
export const setAuthorizePersonProfileInfo = (
_, { authorizePersonData }, { cache }
) => {
try {
const prevData = cache.readQuery({ getAuthorizePersonProfileQuery });
cache.writeQuery({
getAuthorizePersonProfileQuery,
data: {
registration: {
__typename: 'Registration',
authorizeProfile: {
__typename: 'AuthorizePersonProfile',
...prevData.registration.authorizeProfile,
...authorizePersonData
}
}
}
});
} catch (e) {
console.log(`err${e}`);
}
return null;
};
I'm trying to mutate the local state on button press, the function is
const handlePressedNext = () => {
Promise.all([
setAuthorizePersonProfileInfo({
variables: { authorizePersonData: generateNidData() }
})
])
.then(() => {
navigation.navigate('Photograph');
});
};
generateNidData function is like bellow
const generateNidData = () => ({
nid_front: nidFrontImage,
nid_back: nidBackImage
});
I'm new to apollo client. I can not understand what I'm doing wrong. Can anyone help me figure out the problem?
getAuthorizePersonProfileQuery is not a valid option for readQuery. Presumably, you meant use query instead.

Vuex state module structure

I adopted the file structure on vuex with modules. Originally I just had everything in one store file (I don't know what I was thinking). Now that I refactored the code to a better more maintainable structure I am having issues with how to mimic the state that I had before.
My previous state for the user field was just a user object like this:
user: {...}
Now that I used this format
const state = {
}
const mutations = {
fetchUser(state,user){
console.log(user)
state = user;
}
};
const actions = {
currentUser: ({commit}) => {
axios.get('/user').then(response => {
if(response.status == 200){
commit('fetchUser', response.data.data);
}
}).catch(response => {
});
}
}
My state translates to :
user:{}
with an empty object. Shouldn't this assign the user into that user state object or am I missing something.
From docs:
Inside a module's mutations and getters, the first argument received will be the module's local state.
So your mutation should access the module object:
const mutations = {
setUser(state, user){
state.user = user; // Assuming you have a user module **
}
};
** Assuming you have a user module this way:
const store = new Vuex.Store({
modules: {
user: moduleUser,
// more modules ...
}
})
Mutations should only modified the state. You should change your logic to fetch user data from an action only and not from your mutation itself, for example:
const actions = {
currentUser: ({commit}) => {
axios.get('/user').then(response => {
if(response.status == 200){
var response = response.data.data;
commit('setUser', response);
}
}).catch(response => {
});
}
}