I'm trying to make a test using jest with Vue.
the details below.
Problem:
- Can't mount using shallowMount option.
Situation:
- Run the test after mounting the component using shallowMount option that provides in Vue-test-utils.
- Throw error "Cannot read property 'XXXX' of undefined
This is my test code.
import myComponent from '@/~';
import Vuex from 'vuex';
import Vuelidate from 'vuelidate';
import { shallowMount, createLocalVue } from '@vue/test-utils';
const localVue = createLocalVue();
localVue.use(Vuex);
localVue.use(Vuelidate);
describe('myComponent~', () => {
let store;
beforeEach(() => {
store = new Vuex.Store({
modules: {
user: {
namespaced: true,
getters: {
profile: () => {
const profile = { name: 'blahblah' };
return profile;
},
},
},
},
});
});
describe('profile.name is "blahblah"', () => {
it('return something~', () => {
const wrapper = shallowMount(myComponent, {
localVue,
store,
mocks: {
$api: {
options: {
testMethod() {
return new Promise((resolve, reject) => {
resolve('test');
});
},
},
},
$i18n: {
t() {
return {
EN: 'EN',
KO: 'KO',
JP: 'JA',
SC: 'zh-CN',
TC: 'tw-CN',
};
},
},
},
});
expect(wrapper.find('.profile').text()).toBe('blahblah');
});
I think the problem is that property isn't set as a specified value or an empty value like an array or object.
But I don't know how I set properly the properties in my logic.
For example,
when the error yields "Cannot read property 'images' of undefined",
I add to a wrapper in the relevant method like this.
exampleMethod() {
this.something = this.something.map(item => {
if (item.detailContent.images) { // <-- the added wrapper is here
~~~logic~~~~
}
})
}
But the undefined properties are so many, I also think this way is not proper.
How I do solve this problem?
added
These are details about the above example method:
exampleMethod() {
this.something = this.something.map(item => {
let passValidation = false;
let failValidation = false;
if (item.detailContent.images) {
if (this.detail.showLanguages.includes(item.code)) {
if (this.configId !== 'OPTION1') {
item.detailContent.images = item.detailContent.images.map(element => {
return {
...element,
required: true,
}
});
}
checkValidationPass = true;
} else {
if (this.configId !== 'OPTION1') {
item.detailContent.images = item.detailContent.images.map(element => {
return {
...element,
required: false,
}
});
}
checkValidationPass = false;
}
return {
...item,
required: passValidation,
warning: failValidation,
}
}
});
if (this.configId === 'OPTION2') {
this.checkOption2Validation();
} else if (this.configId === 'OPTION3') {
this.checkOption3Validation();
} else {
this.checkOption1Validation();
}
},
And this is 'this.something':
data() {
return {
something: []
}
}
The detailContent is set here.
setMethod() {
this.something = [
...this.otherthings,
];
this.something = this.something.map(item => {
let details1 = {};
if (this.configId === 'OPTION2') {
details1 = {
images: [
{ deviceType: 'PC', titleList: [null, null], imageType: 'IMAGE' },
{ deviceType: 'MOBILE', titleList: [null, null, null] }
]
};
} else if (this.configId === 'OPTION3') {
details1 = {
images: [
{ deviceType: 'PC' },
{ deviceType: 'MOBILE' }
],
links: { linkType: 'EMPTY' },
};
}
let details2 = {
mainTitle: {
content: null,
}
}
let checkValidation = false;
this.detail.detailLanguages.forEach(element => {
if (element.language === item.code) {
details1 = { ...element };
if (!!element.mainTitle) {
details2 = { ...element };
} else {
details2 = {
...details2,
...element
};
}
if (this.configId !== 'OPTION1') {
details1.images = details1.images.map(image => {
return {
...image,
required: true,
}
});
}
checkValidation = true;
}
});
return {
...item,
detailContent: this.configId !== 'OPTION1' ? details1 : details2,
required: false,
warning: false,
}
});
},