When I try using wrapper.findComponent, I get the following error:
ErrorWrapper { selector: { ref: 'loginTab' } }
I have searched online but to no avail. Here is my test code:
describe('Sign-Up Test Cases', () => {
const wrapper = mount(SignUp, {
methods: {
getProv: jest.fn()
},
localVue
})
it('Dialog contains a Login Input Field', () => {
console.log(wrapper.findComponent({ ref: 'loginTab' }))
expect(wrapper.findComponent({ ref: 'loginTab' }))
})
})
localVue is already defined.
Check the it statement where I am using the findComponent function.
UPDATE: Something else I tried.
I tried this and it didn't work.
import Vuetify, {VTab} from 'vuetify/lib'
// Some Code here
console.log(wrapper.findComponent(VTab))
and it didn't work. I got the following error:
ErrorWrapper {selector: [Function: VueComponent]}
You have to import the component and use it as payload for the findComponent method:
const VTab = {
template: '<div><slot></div>
}
const wrapper = shallowMount(SignUp, {
global: {
stubs: { VTab }
},
})
wrapper.findComponent(VTab)
Related
I'm having a couple of issues with my Vue test libs. I am trying to test a mixin. It requires setting the route and mocking a function. Here is my code
MIXIN
export const CampaignNotifier = {
mounted () {
// Create tagname with dynamic currency parameter from banking app
let routeName = this.$route.name
let queryParamCurrency = (this.$route.query.currency) ? `- ${ this.$route.query.currency.toUpperCase() }` : '-'
this.campaignTagName = (BRAZE_TAG_MAPPING[routeName]) ? BRAZE_TAG_MAPPING[routeName].replace(/-/, queryParamCurrency) : null
if (this.campaignTagName) {
this.$appboy.logCustomEvent(this.campaignTagName)
}
},
}
TEST:
import { expect } from 'chai'
import { shallowMount, createLocalVue } from '#vue/test-utils'
import VueRouter from 'vue-router'
import sinon from 'sinon'
import { CampaignNotifier } from '#/mixins/campaignNotifier'
let wrapper
function factory (routeName, currency) {
let localVue = createLocalVue()
localVue.use(VueRouter)
let routes = [
{
path: routeName,
name: routeName,
query: {
currency
}
}
]
let router = new VueRouter({
routes
})
let Component = {
render () { },
mixins: [CampaignNotifier],
localVue,
router,
mocks: {
$route: {
path: routeName,
query: {
currency
}
},
$appboy: {
logCustomEvent: () => {}
}
}
}
return shallowMount(Component)
}
describe('#/mixins/campaignNotifier', () => {
it('Campaign Notifier is not called if route not configured correctly', () => {
wrapper = factory('before-begin', 'EUR')
console.log('$route ***', wrapper.vm.$route)
sinon.spy(wrapper.vm.$appboy, 'logCustomEvent')
expect(wrapper.vm.$appboy.logCustomEvent).not.toHaveBeenCalled()
})
})
Issues I am encountering:
When I mock the $route and console.log it, it returns undefined. I tried mocking it and also using VueRouter. Neither worked.
I am trying to mock the global prototype / method $appboy.logCustomEvent I get:
[Vue warn]: Error in mounted hook: "TypeError: Cannot read property 'logCustomEvent' of undefined"
Any help would be greatly appreciated. Thanks
You're incorrectly combining mounting options with the component definition itself, so your mocks aren't actually getting installed, leading to the errors you observed.
Mounting options should be passed as the second argument to shallowMount:
function factory() {
let Component = {
render() { },
mixins: [CampaignNotifier],
}
let mountingOptions = {
localVue,
router,
mocks: {
$route: {
path: routeName,
query: {
currency
}
},
$appboy: {
logCustomEvent: () => { }
}
}
}
return shallowMount(Component, mountingOptions)
}
I have the same issue than this post: Why does vitest mock not catch my axios get-requests?
I would like to test my vuex store on vuejs and it works for getters etc but not for actions part with axios get request.
I don't know if it's a good practice to test vuex store than the component in Vue ?
But I guess I need to test both, right ?
a project https://stackblitz.com/edit/vitest-dev-vitest-nyks4u?file=test%2Ftag.spec.js
my js file to test tag.js
import axios from "axios";
const actions = {
async fetchTags({ commit }) {
try {
const response = await axios.get(
CONST_CONFIG.VUE_APP_URLAPI + "tag?OrderBy=id&Skip=0&Take=100"
);
commit("setTags", response.data);
} catch (error) {
console.log(error);
return;
}
},
};
export default {
state,
getters,
actions,
mutations,
};
then my test (tag.spec.js)
import { expect } from "chai";
import { vi } from "vitest";
import axios from "axios";
vi.mock("axios", () => {
return {
default: {
get: vi.fn(),
},
};
});
describe("tag", () => {
test("actions - fetchTags", async () => {
const users = [
{ id: 1, name: "John" },
{ id: 2, name: "Andrew" },
];
axios.get.mockImplementation(() => Promise.resolve({ data: users }));
axios.get.mockResolvedValueOnce(users);
const commit = vi.fn();
await tag.actions.fetchTags({ commit });
expect(axios.get).toHaveBeenCalledTimes(1);
expect(commit).toHaveBeenCalledTimes(1);
});
});
It looks like some other peolpe have the same issues https://github.com/vitest-dev/vitest/issues/1274 but it's still not working.
I try with .ts too but I have exactly the same mistake:
FAIL tests/unit/store/apiObject/tag.spec.js > tag > actions - fetchTags
AssertionError: expected "spy" to be called 1 times
❯ tests/unit/store/apiObject/tag.spec.js:64:24
62| await tag.actions.fetchTags({ commit });
63|
64| expect(axios.get).toHaveBeenCalledTimes(1);
| ^
65| expect(commit).toHaveBeenCalledTimes(1);
66| });
Expected "1"
Received "0"
Thanks a lot for your help.
I finally found the mistake, it was on my vitest.config.ts file, I have to add my global config varaible for my api: import { config } from "#vue/test-utils";
import { defineConfig } from "vitest/config";
import { resolve } from "path";
var configApi = require("./public/config.js");
const { createVuePlugin } = require("vite-plugin-vue2");
const r = (p: string) => resolve(__dirname, p);
export default defineConfig({
test: {
globals: true,
environment: "jsdom",
},
define: {
CONST_CONFIG: configApi,
},
plugins: [createVuePlugin()],
resolve: {
alias: {
"#": r("."),
"~": r("."),
},
// alias: {
// "#": fileURLToPath(new URL("./src", import.meta.url)),
// },
},
});
I want to test my Api functions which are on separate file outside vue component. Inside this methods i call api by Vue.axios, and i can't find the way to mock and test it like in this post:
How do I test axios in jest
example method:
cancelAuction: function (auction_id) {
if (validateApiInt(auction_id)) {
return Vue.axios.delete(`/auctions/${auction_id}`);
}
return {};
},
example usage:
const response = await AuctionApi.cancelAuction(id);
Ok that was pretty obvious. I had to mock whole Vue like below:
jest.mock('vue', () => ({
axios: {
get: jest.fn()
},
}));
Just start learning Jest + #vue/test-utils. Here is a simple example for those people want to mock "vue-axios".
// #/components/Helloword.vue
<template>
<div>
<h1>Email: <span>{{ email }}</span></h1>
<button #click="fetchData">Get Random Email</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
email: '',
};
},
methods: {
async fetchData() {
const res = (await this.axios.get('https://randomuser.me/api/')).data
.results[0].email;
this.email = res;
},
},
};
</script>
--
// test/unit/example.spec.js
import { mount } from '#vue/test-utils';
import HelloWorld from '#/components/HelloWorld.vue';
import axios from 'axios';
jest.mock('axios', () => ({
get: () =>
Promise.resolve({
data: {
results: [{ email: 'mockAxios#email.com' }],
},
}),
}));
describe('HelloWorld.vue', () => {
it('click and fetch data...', async (done) => {
const wrapper = mount(HelloWorld, {
mocks: {
axios,
},
});
await wrapper.find('button').trigger('click');
wrapper.vm.$nextTick(() => {
expect(wrapper.find('h1').text()).toContain('#');
done();
});
});
});
I have a namespaced Vuex store in my Vue 2.6 app one module of which is like this:
//books.js
export default {
state: {
books: null
},
mutations: {
SET_BOOKS(state, books) {
state.books = books;
},
},
actions: {
setBooks: async function ({ commit }) {
//api call
commit('SET_BOOKS', books);
}
},
namespaced: true
};
I want to test a component that calls the setBooks action. I am using mapActions to access the actions. The relevant code is:
//Books.vue
methods: {
...mapActions("books", ["setBooks"]),
}
},
created: async function() {
await this.setBooks();
}
The problem is that my test can't find the action:
import { shallowMount } from '#vue/test-utils';
import Books from '#/views/Books';
import Vuex from 'vuex';
import flushPromises from 'flush-promises';
import { createLocalVue } from '#vue/test-utils'
const localVue = createLocalVue();
localVue.use(Vuex);
describe('Books', () => {
let actions;
let store;
let wrapper;
beforeEach(() => {
store = new Vuex.Store({
state: {
books: {
books: null
}
},
actions: {
setBooks: jest.fn()
}
});
wrapper = shallowMount(Books, { store, localVue })
});
it("renders the books", async () => {
await flushPromises();
expect(actions.setBooks).toHaveBeenCalled();
});
});
I get an error [vuex] module namespace not found in mapActions(): books/
if I try to namespace the actions code in the my test to:
actions: {
books: {
setBooks: jest.fn()
}
}
I get TypeError: Cannot read property 'setBooks' of undefined
Please help, thank you!
The docs for vue-test-utils include an example of testing with modules.
Change your beforeEach:
beforeEach(() => {
actions = { setBooks: jest.fn() }
store = new Vuex.Store({
modules: {
books: {
state: { books: null },
actions
}
}
})
...
})
Your test calls actions.setBooks, but in your original code actions was simply declared, but not used in the creation of your store.
I've been trying to test a confirmation button using jest and vue-test-utils. I'm using a debounced method to handle accidental double-clicking.
I've tried using jest.useFakeTimers() and jest.runOnlyPendingTimers(), but I'm still not seeing my button text changing in my tests. I've created an isolated test file below - any advice on what I'm doing wrong here would be greatly appreciated!
import { shallowMount, createLocalVue } from '#vue/test-utils'
import _ from 'lodash'
jest.useFakeTimers()
const myComponent = {
data(){
return {
confirming: false
}
},
computed: {
state(){
return this.confirming ? 'are you sure?' : 'default'
}
},
template: `<div #click="changeState">{{ state }}</div>`,
methods: {
changeState(){
this.doConfirm()
},
doConfirm: _.debounce(function(){
if(!this.confirming){
this.confirming = true
}else{
this.confirming = false
}
}, 500)
}
}
describe('Testing debounce methods', () => {
let $wrapper
beforeEach(() => {
$wrapper = shallowMount(myComponent)
})
test('Check default state', () => {
expect($wrapper.text()).toContain('default')
})
test('Check state changes with click', () => {
$wrapper.trigger('click')
jest.runOnlyPendingTimers()
expect($wrapper.text()).toContain('are you sure?')
})
})