Vue: Test utils vue composition - root.$route - vue.js

Versions
Test utils
1.0.3
Vue
2.6.11
Vue router
3.20
Vue compsotion API
1.0.0-beta.8
I have some difficulties developing a component test because of root.$route.
In the component, I have a watch, which will be aware when the route changes, in order to change some variables of the component.
My component
<script>
export default {
setup ( _, { root }) {
// behavior
...
watch( () => root.$route,
({ query, meta }) => {
foo = 'bar';
}, {
immediate: true
});
}
};
</script>
My test
import { shallowMount, createLocalVue } from '#vue/test-utils';
import VueCompositionAPI from '#vue/composition-api';
import Component from '#/components/bundles/layout/Component';
import router from '#/router/';
const localVue = createLocalVue();
localVue.use( VueCompositionAPI );
localVue.use( router );
describe( 'Component', () => {
it( 'Insert', () => {
const wrapper = shallowMount( Component, {
mocks: {
$t: () => ({})
},
localVue,
router
});
console.log( wrapper.html() );
});
});
Error
TypeError: Cannot destructure property 'query' of 'undefined' as it is undefined.
I've tried to mock the router, but without effect.
I tried in the following ways:
1:
...
describe( 'Component', () => {
it( 'Insert', () => {
const wrapper = shallowMount( Component, {
mocks: {
$t: () => ({}),
$route: { query: '', meta: '' }
},
localVue,
router
});
console.log( wrapper.html() );
});
});
2:
import router from '#/router/';
jest.mock( '#/router/', () => ({
currentRoute: {
meta: {},
query: {}
},
push: jest.fn( () => Promise.resolve() )
}) );
Some help?

Related

Vue unit test is holds old component code in wrapper

I am doing unit test of vue component methods through vue-test-utils and facing an weird issue. wrapper.vm.somemthod() is executing old code that was written earlier inside the method. It's printing old console.log statements. If I put new console.log statement, it's not printing that at all. Am I missing something?
import { mount, shallowMount } from '#vue/test-utils'
import TestComponent from '#/components/TestComponent.vue'
const mockMixin = {
methods: {
InnerMethod() {
return 2;
},
}
}
describe('Test Screen', () => {
let wrapper;
let mock;
beforeAll(() => {
mock = new MockAdapter(api);
})
beforeEach(() => {
jest.resetModules();
wrapper = mount(TestComponent, {
i18n,
vuetify,
mixins: [mockMixin],
data() {
},
mocks: {
$t: (msg) => msg,
$config: (value) => value,
$store: (value) => value,
$route: (value) => value,
}
});
})
afterEach(() => {
mock.reset();
wrapper.destroy();
wrapper = null;
});
describe('Component Test', () => {
it('getdata', async () => {
expect(wrapper.vm.somedata.length).toBe(0);
const spy = jest.spyOn(wrapper.vm, 'InnerMethod');
wrapper.vm.someMethod();
expect(spy).toBeCalledTimes(1);
expect(wrapper.vm.somedata.length).toBe(2);
});
});
});

Buefy error when testing with jest - vuejs

Im geting this error:
[Vue warn]: Unknown custom element: <b-taginput> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
on this test:
import MultipleChoice from '#/components/MultipleChoice';
import Buefy from 'buefy';
const localVue = createLocalVue();
localVue.use(Buefy);
describe('MultipleChoice.vue', () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(MultipleChoice, {
propsData: {
choices: ['en', 'de', 'it'],
}
});
});
test('renders correctly', () => {
expect(wrapper).toMatchSnapshot();
});
});
the test itself passes, but this warning keeps showing up.
This is my component:
<b-taginput
v-model="value"
:data="filteredData"
expanded
autocomplete
open-on-focus
clear-on-select
field="display_name"
icon="label"
#input="update()" />
does anybody knows what is going on?
I figured it out. What was missing:
import MultipleChoice from '#/components/MultipleChoice';
import Buefy from 'buefy';
const localVue = createLocalVue();
localVue.use(Buefy);
describe('MultipleChoice.vue', () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(MultipleChoice, {
propsData: {
choices: ['en', 'de', 'it'],
},
stubs: {
transition: false,
'b-taginput': true
}
});
});
test('renders correctly', () => {
expect(wrapper).toMatchSnapshot();
});
});

Jest : TypeError: Cannot read property 'variable' of undefined

I am testing though Jest on the Vue 2.x, nuxtjs and #nuxtjs/composition-api.
However, the state value in the components has undefined value when testing though jest
List.spec.js
import Vue from 'vue';
import Vuetify from 'vuetify';
import { createLocalVue, shallowMount } from '#vue/test-utils';
import List from '#/components/home/list.vue';
Vue.use(Vuetify);
describe('List.vue', () => {
const localVue = createLocalVue();
let vuetify;
const $t = () => {};
const localePath = () => {};
beforeEach(() => {
vuetify = new Vuetify();
localVue.use(vuetify);
});
const mockOrder = [
{
coardshare: {
cs_id: 123,
},
},
{
talkboard: {
cs_id: 123,
},
},
];
it('11111', () => {
const wrapper = shallowMount(List, {
localVue,
vuetify,
propsData: { data: mockOrder },
mocks: { $t, localePath },
data() {
return {
data: mockOrder,
};
},
});
expect(wrapper.html()).toMatchSnapshot();
const title = wrapper.find('.v-card__title > span');
expect(title.text()).toBe('Foobar');
});
});
List.vue
<template>
...
<div v-for="item in state.data.talkboard" :key="item.cs_id">
<ListItem :item="item"></ListItem>
</div>
...
</template>
<script>
import { reactive, onMounted, useContext } from '#nuxtjs/composition-api';
import axios from 'axios';
import Header from './header';
import ListItem from './list-item.vue';
export default {
name: 'ListHome',
components: {
Header,
ListItem,
},
setup() {
const state = reactive({
data: [],
});
const { store } = useContext();
const fatch = async () => {
....
};
onMounted(fatch);
return {
state,
fatch,
};
},
};
</script>
error message
TypeError: Cannot read property 'data' of undefined
I am testing though Jest on the Vue 2.x, nuxtjs and #nuxtjs/composition-api.
However, the state value in the components has undefined value when testing though jest
why error on this ?? because of composition API that define the state with reactive() function ??
In your test file maybe you can try something like this:
it('11111', () => {
const wrapper = shallowMount(List, {
localVue,
vuetify,
propsData: { data: mockOrder },
mocks: { $t, localePath },
data: () => {
return {
data: mockOrder,
};
},
});

Vue testing with jest: $route is always undefined

I've tried a lot of things but $route seems to always be undefined and I have this error on shallowMount: TypeError: Cannot read property 'params' of undefined.
In my component, I want to check the params of the $route but it is always undefined. I've looked the documentation and mocked the $route to set it but it seems like the $route is not mocked. I've also tried using localVue.use(VueRouter), thinking that it would set $route but it didn't. Does anyone have an idea why the following doesn't work in both cases?
my-component.ts
#Component
export default class MyComponent extends Vue {
get organisationId() {
return this.$route.params.organisationId;
}
}
I've tried the 2 following tests with the solutions I've talked about:
my-component.spec.ts
import { createLocalVue, shallowMount } from '#vue/test-utils';
import MyComponent from '#/components/MyComponent.vue';
import router from '#/router';
const localVue = createLocalVue();
describe('MyComponent', () => {
let cmp: any;
beforeEach(() => {
cmp = shallowMount(MyComponent, {
localVue,
router,
mocks: {
$route: {
params: {
id: 'id'
}
}
}
});
});
it('Should render a Vue instance', () => {
expect.assertions(1);
expect(cmp.isVueInstance()).toBeTruthy();
});
});
my-component.spec.ts
import { createLocalVue, shallowMount } from '#vue/test-utils';
import MyComponent from '#/components/MyComponent.vue';
const localVue = createLocalVue();
describe('MyComponent', () => {
let cmp: any;
localVue.use(VueRouter);
const router = new VueRouter();
beforeEach(() => {
cmp = shallowMount(MyComponent, {
localVue,
router
});
});
it('Should render a Vue instance', () => {
expect.assertions(1);
expect(cmp.isVueInstance()).toBeTruthy();
});
});
You were mocking $route right in #1 test. You can access $route property of test component via wrapper.vm.$route (or cmp.vm.$route in your case). And There is example:
import { shallowMount, Wrapper } from '#vue/test-utils'
import MyComponent from '#/components/MyComponent.vue'
let wrapper: Wrapper<MyComponent>
describe('MyComponent', () => {
beforeEach(() => {
wrapper = shallowMount(MyComponent, {
mocks: {
$route: {
params: {
id: 'id'
}
}
}
})
})
it('$route has passed params', () => {
expect(wrapper.vm.$route.params.id).toBe('id')
})
})

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.