Have a Vue app with axios setup and is using it as this.$http.get in the components and that is working fine.
In running the specs using Jest I get an error: Cannot read property 'get' of undefined
I know I can mock axios with maxios. How do I get Jest to recognise $http so it does not throw an error?
You'll need to create a local instance of Vue for your tests, to which you introduce the Vue Plugins you are using, such as axios.
import { createLocalVue, shallowMount } from "#vue/test-utils"
import axios from 'axios'
import VueAxios from 'vue-axios'
const localVue = createLocalVue();
localVue.use(VueAxios, axios)
and later, in your actual tests:
it('should mount the component where I want to use $http', () => {
const wrapper = shallowMount(MyApiComponent, { localVue });
... do stuff to wrapper here ...
})
Related
i install axios :
npm install axios
and import it :
import axios from "axios";
this is part of my code :
`
const fetchDataHandler=useCallback(()=>{
setLoading(true);
setCity("");
axios({
method:"GET",
url:`https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${api.key}`
}).then(res=>{
console.log(res.data)
});
},[api.key,city])
`
when i try to get data from api i have this error
please help
i tried to install latest version to axios but it did not work
I'm fairly sure you want to use:
var axios = require('axios');
not import axios from "axios" when using node.js.
Source: Postman.com
I understand that in your jest.setup.js code, you are supposed to set
Vue.config.productionTip = false;
Vue.config.devtools = false;
and I do. In fact, here is my jest.setup.js code. Notice the console.log('yo ho');
// test/setup.js
import Vue from 'vue';
import Vuetify from 'vuetify';
import { config } from '#vue/test-utils';
import VueCompositionApi from '#vue/composition-api'; // <-- Make the import
Vue.use(Vuetify);
Vue.use(VueCompositionApi);
Vue.config.productionTip = false;
Vue.config.devtools = false;
console.log('yo ho');
// https://vue-test-utils.vuejs.org/
// and this came from: https://github.com/kazupon/vue-i18n/issues/323
// it mocks out the $t function to return the key so you can test that the right key is being used
config.mocks = {
$t: (key) => 'i18n:' + key
};
So given that, I don't expect to get these warnings - ever. But I do on about 1/3 of my unit test files. Not all my unit test files, just some of them. I am really confused.
So I then added that console log statement to ensure that on the unit tests that I am getting this warning, the jest.setup.js is actually getting called. This is the output from one of my unit tests:
PASS src/components/announcement-banner.test.ts (8.255s)
● Console
console.log tests/unit/jest.setup.js:12
yo ho
console.info node_modules/Vue/dist/vue.runtime.common.dev.js:8403
Download the Vue Devtools extension for a better development experience:
https://github.com/vuejs/vue-devtools
console.info node_modules/Vue/dist/vue.runtime.common.dev.js:8412
You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html
How in the world I am I getting the Vue warning, when I am definitely executing the jest.setup?
to make these warnings go away, I have to go to the specific test file and add the config lines directly before the createLocalVue() call.
Vue.config.productionTip = false;
Vue.config.devtools = false;
const localVue = createLocalVue();
Finally solved. Looks like jest.mock('module') is importing clean Vue (into mock, behind the scenes) if Vue is imported in given file. I've solved this by creating global mock for Vue.
In root of your project (where node_modules directory is) create __mocks__/vue/index.ts (or .js if you are not using TypeScript) file with:
import Vue from 'vue'
Vue.config.productionTip = false
Vue.config.devtools = false
export default Vue
Should solve this annoying problem.
UPDATE 2022-07-04 VueI18n common error (related)
Using Vue.extend() in components will cause Jest to use version imported through this file when component is a child component of component mounted in the test. If you are using VueI18n and try to mount component or stub child component (that uses VueI18n) everything will go sideways with error _vm.$t is not a function
To avoid that, You will need to mock VueI18n in that particular file. For example by creating fake plugin (this is more advanced fake than just $t: (key) => key, you can use whatever you want):
const VueI18nStub = {
install(_Vue: typeof Vue) {
function getFormattedTranslationArgs(...args: any): string {
return args
.reduce((result: string[], arg: any) => {
result.push(typeof arg === 'object' ? JSON.stringify(arg) : arg.toString())
return result
}, [])
.join(' | ')
}
_Vue.prototype.$t = getFormattedTranslationArgs
_Vue.prototype.$tc = getFormattedTranslationArgs
_Vue.prototype.$te = () => true
},
}
Vue.use(VueI18nStub)
VueI18n is a common example, but any plugin will need to be added in this file to work, as you can't extend mock from this file inside any test.
Whole file with VueI18n stub would look like this:
import Vue from 'vue'
Vue.config.productionTip = false
Vue.config.devtools = false
const VueI18nStub = {
install(_Vue: typeof Vue) {
function getFormattedTranslationArgs(...args: any): string {
return args
.reduce((result: string[], arg: any) => {
result.push(typeof arg === 'object' ? JSON.stringify(arg) : arg.toString())
return result
}, [])
.join(' | ')
}
_Vue.prototype.$t = getFormattedTranslationArgs
_Vue.prototype.$tc = getFormattedTranslationArgs
_Vue.prototype.$te = () => true
},
}
Vue.use(VueI18nStub)
export default Vue
After upgrading to vue 2.7, all my unit tests for components using the composition-api were failing. It turns out, now that the composition-api is directly exported in the vue module, the jest mock from the accepted answer has to be updated like this:
import Vue from 'vue';
Vue.config.productionTip = false;
Vue.config.devtools = false;
export default Vue;
// this line makes available all of the non-default exports from the vue module in jest tests
export * from 'vue';
Hope this helps anyone struggling with unit tests under vue 2.7
We are building an application using VueJS, are new to its concepts. Facing an error when we try to make a call using axios from a js function.
The error is "export 'default' (imported as axios) was not found in ./axios.js"
Please let us know what we might be doing wrong. Appreciate your help.
import Vue from 'vue';
import axios from './axios.js';
export const MY_CONST = 'Vue.js';
export let memberList = new Vue({
el: '#members',
data: {
members: []
},
mounted: function () {
this.getAllMembers();
},
methods: {
getAllMembers: function () {
var me = this;
axios.get("https://xxxxx.com/services/api.php")
.then(function (response) {
me.members = response.data.members;
});
}
}
});
Assuming you've installed axios as a dependency or devDependency in your package.json and installed it via npm or yarn then I would suspect your issue is that you're looking for axios in a file called axios.js in the same directory as the calling component. You should instead look for the package axios like this:
import axios from 'axios';
If you're indeed trying to export axios from a custom file with configuration or something then you need to see what you're exporting from the file and make sure it is indeed axios. Though from the sound of your error that doesn't seem to be what your'e trying to do.
I am trying to mock following function (running fresh VueCLI based project)
foo.js:
export const bar = () => 10
but as ES6 modules are exported readOnly, this is not simple. Following does not work
foo.spec.js:
import * as testFooModule from './foo';
import sinon from 'sinon';
import { expect } from 'chai';
it('Should be mocked but is not', () => {
sinon.stub(testFooModule, 'bar').returns(1);
// bar function is not stubbed, test fails
expect(testFooModule.bar()).to.be.equal(1);
});
I am familiar with babel-plugin-rewire, but I was not able to get it working neither. I don't want to change foo.js file. How to mock bar function?
Thank you
Sinon ver: 7.2.2
Vue Cli ver: 3.0.5
I am testing with axios within a Vue application and the CLI. I've been using vue-resource and I could access it on all my components by simply passing it to Vue.use (VueResource). How can I achieve this with axios, so I do not have to import it into a component, but simply define it once in the main.js file?
In main.js you can just assign Axios to $http.
main.js
import Axios from 'axios'
Vue.prototype.$http = Axios;
By modifying the vue prototype, any vue instance will have the ability to call $http on this. (e.g. this.$http.get('https://httpbin.org/get')
Note: $http is the axios object now, so any method you can call on axios object, you can call on this.$http.
NOTE: When Vue module is installed as a package and not using through CDN then this approach works fine else if importing Vue from CDN then we have both options, first the answer here and second is to import Vue in main.js and then use Vue.prototype.{variable}=Axios
For VUE3, you need to add below code:
Syntax:
app.config.globalProperties.{variable} = value;
Example:
app.config.globalProperties.$http = Axios; // Allow axios in all componenets this.$http.get
In your main.js or app.js
/**
* Importing libraries & componenets
*/
import { createApp } from 'vue';
import { createWebHistory, createRouter } from 'vue-router';
import Axios from 'axios';
/**
* Vue initialization
*/
const app = createApp({
components: {
Index
},
});
app.use(router);
app.config.globalProperties.$http = Axios; // Allow axios in all componenets this.$http.get
app.mount('#app');
You can call the GET method same as VUE2 in your components: this.$http.get('https://httpbin.org/get')
For all those who implement from zero (whithout deprecated vue-resource), another simple and efficient way, the "Laravel way" too.
In CLI run: npm install axios
In main.js define:
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
window.axios.defaults.headers.common['Accept'] = 'application/json';
and then you can use it in any component like this:
window.axios.get('https://example.com').then(r => console.log(r.data));
and capture r.data output
(if you use the Laravel routes instead of those of Vue you can use it like this: axios.get(url).then(...)
What worked for me in the end was this:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import axios from 'axios'
import VueAxios from 'vue-axios'
const app = createApp(App).use(router)
app.use(VueAxios, axios)
app.mount('#app')
And I used this library:
vue-axios