Cannot access axios.all in vue component - vue.js

I initialize my axios instance in one file and attempt to use it in another but I cannot seem to get all working:
// axios.js
import axios from 'axios'
const baseURL = "http://api.lvh.me:3000/api";
const token = '';
export default axios.create({
baseURL: baseURL,
headers: { 'authentication': token }
});
I then use this instance in my components:
// component
import axios from "../axios"
export default {
data() {
startDate: null,
endDate: null
},
created() {
const g_sheet = axios.get(`/dashboards/google_sheets.json?&start_date=${ this.startDate }&end_date=${ this.endDate }`)
const leads = axios.get(`/dashboards/potential_clients/simple?&start_date=${ this.startDate }&end_date=${ this.endDate }`)
axios.all([g_sheet, leads]).then(axios.spread((...responses) => {
const g_response = responses[0]
const lead_response = responses[1]
console.log(g_response, lead_response)
})).catch(errors => {
console.log(errors)
})
}
Calls like get have been working, but all has not. I see the error:
vue.runtime.esm.js?2b0e:1888 TypeError: _axios__WEBPACK_IMPORTED_MODULE_8__.default.all is not a function

Related

vue-axios: Cannot read property 'post' of undefined

I try to send login data using axios and I get this error:
[Vue warn]: Error in v-on handler: "TypeError: Cannot read property
'post' of undefined"
TypeError: Cannot read property 'post' of undefined
I used this.$http.post from documentation.
main.js
import Vue from "vue";
import App from "./App.vue";
import axios from "axios";
import VueAxios from "vue-axios";
import router from "./router/router";
import store from "./store/index";
import vuetify from "./plugins/vuetify";
Vue.config.productionTip = false;
Vue.use(VueAxios, axios);
new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount("#app");
store/index.js
import Vue from "vue";
import Vuex from "vuex";
import account from "./account.module";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
account
}
});
stroe/account/module.js
import jwt_decode from "jwt-decode";
import accountService from "../services/account.service";
const token = localStorage.getItem("token");
const user = token ? jwt_decode(token) : null;
const state = token
? { loggedIn: true, user }
: { loggedIn: false, user };
const getters = {
}
const actions = {
login({ commit }, user) {
return accountService.login(user).then(
data => {
if (data.status == "success") {
const user = jwt_decode(data.token);
commit("loginSuccess", user);
} else {
commit("loginFailure");
}
return data;
});
}
}
const mutations = {
loginSuccess(state, user) {
state.loggedIn = true;
state.user = user;
},
loginFailure(state) {
state.loggedIn = false;
state.user = null;
},
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
services/account.service.js
const apiUrl = "***";
export default {
login(user) {
return this.$http.post(apiUrl + "login", {
login: user.login,
password: user.password
}).then(response => {
if (response.data.status == "success") {
localStorage.setItem("token", response.data.token);
}
return response.data;
});
}
}
VueAxios only creates a wrapper around the passed in axios, so this.$http.post() is the same as axios.post().
Thus, you could use axios directly in your services file:
import axios from 'axios'; 👈
const apiUrl = "***";
export default {
login(user) {
👇
return axios.post(apiUrl + "login", {
login: user.login,
password: user.password
}).then(/*...*/);
}
}

Axios - get data from api in vuex actions?

How to correctly transfer or rewrite the function in actions that will receive the first photo from each album in?
my photos models:
import { api } from "#/apis/config";
const endPoint = 'photos'
const state = {
photos: []
}
const getters = {}
const mutations = {
SET_PHOTOS(state, data) {
state.photos = data
}
}
const actions = {
loadMore(id) {
api.get(`photos?albumId=${id}`).then(response => {
return response.data[0].thumbnailUrl;
});
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
};
And my album component:
...
<script>
import {mapActions} from "vuex";
export default {
name: "GridAlbums",
props: ['album'],
data() {
return {
loading: true,
errored: false,
photo: null
}
},
mounted() {
this.photo = this.loadMore(this.album.id)
},
methods: {
...mapActions("photos", ["loadMore"])
}
}
</script>
...
Here is my configuration file for api, where VUE_APP_HOST is https://jsonplaceholder.typicode.com/
import axios from 'axios'
export const api = axios.create({
baseURL: process.env.VUE_APP_HOST,
})
api.interceptors.response.use(
response => {
return response
},
error => {
return Promise.reject(error)
}
)
If you get the data this way, then everything turns out as it should:
Try adding async / await in vuex actions, because actions must be asynchronous and store and mutations synchronous.
Also use try / catch instead Promise that way you keep your code cleaner

How can I test actions within a Vuex module?

I want to test a vuex module called user.
Initially, I successfully registered my module to Vuex. Its works as expected.
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
user
}
})
export default store
My user module is defined as follows
store/modules/user.js
const state = {
token: getToken() || '',
}
export const getters = {
token: state => state.token,
}
const mutations = {
[SET_TOKEN]: (state, token) => {
state.token = token
}
}
const actions = {
[LOGIN] ({ commit }, body) {
return new Promise((resolve, reject) => {
login(body).then(response => { //login is an api method, I'm using axios to call it.
const { token } = response.data
setToken(token)
commit(SET_TOKEN, token)
resolve()
}).catch(error => {
reject(error)
})
})
}
}
export default {
state,
getters,
mutations,
actions
}
login api
api/auth.js
import request from '#/utils/request'
export function login (data) {
return request({
url: '/auth/login',
method: 'post',
data
})
}
axios request file
utils/request
import axios from 'axios'
import store from '#/store'
import { getToken } from '#/utils/auth'
const request = axios.create({
baseURL: process.env.VUE_APP_BASE_API_URL,
timeout: 5000
})
request.interceptors.request.use(
config => {
const token = getToken()
if (token) {
config.headers['Authentication'] = token
}
return config
}
)
export default request
When I want to write some test (using Jest), for example login action as shown above.
// user.spec.js
import { createLocalVue } from '#vue/test-utils'
import Vuex from 'vuex'
import actions from '#/store/modules/user'
const localVue = createLocalVue()
localVue.use(Vuex)
test('huhu', () => {
expect(true).toBe(true)
// implementation..
})
How can I write test for my Login action? Thanks. Sorry for my beginner question.
EDIT: SOLVED Thank you Raynhour for showing to me right direction :)
import { LOGIN } from '#/store/action.types'
import { SET_TOKEN } from '#/store/mutation.types'
import { actions } from '#/store/modules/user'
import flushPromises from 'flush-promises'
jest.mock('#/router')
jest.mock('#/api/auth.js', () => {
return {
login: jest.fn().mockResolvedValue({ data: { token: 'token' } })
}
})
describe('actions', () => {
test('login olduktan sonra tokeni başarıyla attı mı?', async () => {
const context = {
commit: jest.fn()
}
const body = {
login: 'login',
password: 'password'
}
actions[LOGIN](context, body)
await flushPromises()
expect(context.commit).toHaveBeenCalledWith(SET_TOKEN, 'token')
})
})
Store it's just a javascript file that will export an object. Not need to use vue test util.
import actions from '../actions'
import flushPromises from 'flush-promises'
jest.mock('../api/auth.js', () => {
return {
login: jest.fn()..mockResolvedValue('token')
}; // mocking API.
describe('actions', () => {
test('login should set token', async () => {
const context = {
commit: jest.fn()
}
const body = {
login: 'login',
password: 'password'
}
actions.login(context, body)
await flushPromises() // Flush all pending resolved promise handlers
expect(context.commit).toHaveBeenCalledWith('set_token', 'token')
})
})
but you need to remember that in unit tests all asynchronous requests must be mocked(with jest.mock or something else)

vuex store state update value in middleware check-auth.js, but can't get the updated value in vue view

I am using nuxtjs for myProject, i useing axios to get auth information in minddleware/check-auth.js and commit the flag to store.state.isSEPCNavFlag;
But i can't get the updated isSEPCNavFlag value in vue view, the value is always null.
anyone can help me? please...
store/index.js
import axios from 'axios'
import echarts from 'echarts'
import Vue from 'vue'
import Vuex from 'vuex'
import { saveToken, delToken } from '#/utils/auth'
Vue.use(Vuex)
export const strict = true
export const state = () => ({
authUser: null,
user: '',
locale: null,
locales: ['zh', 'en'],
isMenuHidden: true,
isSEPCNavFlag:null,
})
export const mutations = {
SET_SEPCFLAG: function (state, isSEPCNavFlag) {
state.isSEPCNavFlag = isSEPCNavFlag
},
SET_TOKEN: function (state, token) {
state.authUser = token
},
SET_USER: function (state, user) {
state.user = user
},
SET_MENUS: function (state, menus) {
state.menus = menus
},
SET_LANG (state, locale) {
if (state.locales.indexOf(locale) !== -1) {
state.locale = locale
}
},
TOGGLE_MENU_HIDDEN: function (state) {
state.isMenuHidden = !state.isMenuHidden
}
}
minddleware/check-auth.js
async function toNavTO(token,store) {
var returnData = await funcAsync(token)
var ACNameIndex = returnData.data.indexOf("<AccountName>");
var navFlag = true;
if(ACNameIndex == -1){
navFlag=false
}
store.commit('SET_SEPCFLAG', navFlag)
}
index.vue
mounted(){
this.login();
},
methods: {
login(){
let navFlag = this.$store.state.isSEPCNavFlag;
console.log(navFlag);
this.$store.state.isSEPCNavFlag value always null.
mutations SET_SEPCFLAG console.log

Set axios authorization header depends on store changes

I am new to Vue (I am a react person) and I am having this problem.
axios.js
import store from '../../store/index';
import axios from 'axios'
const API_URL = process.env.API_URL;
const token = store.getters.auth.token;
export default axios.create({
baseURL: API_URL,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
})
store/index.js
import auth from './modules/auth'
Vue.use(Vuex);
const debug = process.env.NODE_ENV !== 'production'
export default new Vuex.Store({
state: {},
getters : {},
mutations: {},
actions:{},
modules: {
auth
},
strict: debug,
})
modules/auth
import { AUTH_SUCCESS, AUTH_GUEST } from '../actions/auth'
import axios from '../../util/axios/axios'
import Vue from "vue";
const state = {
token: localStorage.token || '',
};
const getters = {
token: state => state.token
};
const actions = {
[AUTH_GUEST]: async ({commit}) => {
await axios.post('auth/register',)
.then(response => {
commit(AUTH_SUCCESS, response);
})
.catch(error => {
console.log(error);
});
},
};
const mutations = {
[AUTH_SUCCESS]: (state, resp) => {
state.token = resp.data.token;
},
}
export default {
state,
getters,
actions,
mutations,
}
when trying to get the store from store/index it returns undefined.
probably the axios has been called before the store has been initialized.
but how can I deal with it?
the flow of the app is.
user register->get token->update store with this token->add to the axios header.
so for now on, all calls to the api will have the token provided.
First of all, you should be careful with Vue's reactivity caveats which affect Vuex aswell. In your case, you're adding a new property inside an object in a mutation.
Back to the main issue, your axios.js file is being executed before the Store instance is built, that's why you cannot access to it and you get undefined.
What I'd do is:
axios.js
import axios from 'axios';
const API_URL = process.env.API_URL;
export default (store) => axios.create({
baseURL: API_URL,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${store.getters.auth.token}`
}
});
and then in your main file, where you have the main Vue instantiation I'd just run the function there, exporting the return of that function.