I have a vuejs modal component that shows the modal of team members (avatar, full_name & description). I need to test it.
teamMembers.js looks like :
<template lang="pug">
.col-lg-4.col-md-6.team_member_wrapper
a(href="javascript:;" data-toggle="modal" data-target="#TeamMemberModal" #click="$emit('clicked', item)" )
.team_member
.team_member_image
img(:src="item.avatar")
.team_member_name {{item.full_name}}
.team_member_status {{item.status}}
.team_member_shadow
</template>git status
<script>
export default {
name: "TeamMember",
props: {
item: {},
}
};
</script>
my test code is :
import Vue from 'vue'
import TeamMember from '#/components/TeamMember.vue'
import { mount } from '#vue/test-utils'
const wrapper = mount(TeamMember, {
context: {
props : {
item : {
avatar : 'path/to_image.png',
full_name: "Robocop"
}
}
}
});
I need to validate that the template generated the correct html
- while the Wrapper must contain a Vue instance. I did this :
wrapper.setProps({ avatar: 'path/to_image.png' }),
expect(wrapper.vm.avatar).toBe('path/to_image.png'),
wrapper.setProps({ avatar: 'Robocop' }),
expect(wrapper.vm.full_name).toBe('Robocop')
I run my test, got the following result :
FAIL tests/unit/specs/TeamMember.spec.js
● Test suite failed to run
[vue-test-utils]: mount.context can only be used when mounting a functional component
9 | item : {
10 | avatar : 'path/to_image.png',
> 11 | full_name: "Robocop"
| ^
12 | }
13 | }
14 | }
at throwError (node_modules/#vue/test-utils/dist/vue-test-utils.js:11:9)
at createInstance (node_modules/#vue/test-utils/dist/vue-test-utils.js:2847:5)
at mount (node_modules/#vue/test-utils/dist/vue-test-utils.js:5639:18)
at Object.<anonymous> (tests/unit/specs/TeamMember.spec.js:11:36)
what mistake in my code, & how can I correct it ?
Thanks
The options you are passing should be on the root level of the object, and props data is set with the propsData option:
const wrapper = mount(TeamMember, {
propsData: {
item: {
avatar: 'path/to_image.png',
full_name: 'Robocop'
}
}
})
Related
I don´t have much experience with unit testing.
What is the proper way to test a method imported from a JS file or from another component?
This is a sample component I created a localSum just to use on the test.
<template>
<div class="fixed-center text-center text-h2">
<p>{{ getSum }}</p>
</div>
</template>
<script>
import { sum } from './testComponent.js';
export default {
name: 'TestComponent',
data() {
return {
a: 10,
b: 20
}
},
computed: {
getSum() {
return sum(this.a, this.b);
}
},
methods: {
localSum(a, b) {
return a + b;
}
}
};
</script>
The JS file:
export function sum(a, b) {
return a + b;
}
This is the test, maybe I should not be using wrapper.vm to access the method?
One note: On the real component I don't want to test the method directly, which is why I did not import sum from the JS file.
import { mount } from '#vue/test-utils';
import TestComponent from '#components/TestComponent.vue';
describe('Testing component', () => {
test('Testing local method', () => {
const wrapper = mount(TestComponent);
expect(wrapper.vm.localSum(10, 20)).toBe(30);
});
test('Testing method from js file', () => {
const wrapper = mount(TestComponent);
expect(wrapper.vm.getSum(10, 20)).toBe(30);
});
});
Test result:
Testing component
✓ Testing local method (6 ms)
✕ Testing method from js file (2 ms)
● Testing component › Testing method from js file
TypeError: wrapper.vm.getSum is not a function
Thanks!
In your example getSum() is a computed property that doesn't take any argument.
Therefore to test it you probably just need to do:
expect(wrapper.vm.getSum).toBe(30);
instead of:
expect(wrapper.vm.getSum(10, 20)).toBe(30);
I'm new using Vuejs so I have a simple page with an input and button like
<input type="text" value="10" v-model="model.rowsPerPage">
<button #click="setNewValue()"> </button>
<script lang="ts">
import { useContact } from '#/composition/useContact'
import { ContactModel } from '#/services/modules/contact/contact'
import { defineComponent, reactive } from '#vue/composition-api'
export default defineComponent({
name: 'Contact',
setup() {
const model = reactive<ContactModel>({
pageNumber: 1,
rowsPerPage: 10,
searchBy: null,
staringDate: null,
endingDate: null,
})
const {
data: contactList,
totalItems: totalItems,
isLoading: isLoading,
error: error,
} = useContact(model)
return {
contactList,
model,
isLoading,
totalItems,
error,
}
},
methods: {
setNewValue() {
model.rowsPerPage = 20
},
},
})
</script>
So what I want to do, is update the input value by 10 if the button is clicked, so as you can see I add a method at the end of the script
methods: {
setNewValue() {
model.rowsPerPage = 20
},
},
But it throws me an error:
Cannot find name model
Why I can't access to const model declared at the top of script? How can I solve this? Regards
inside the methods you need to reference the "this" object to have access to what's returned in data or setup
but if you're using vue 3 with the composition api, you can simply define the function inside setup and return it, your template will then have access to it
(also, I think you should keep your component html inside a template tag)
I installed Vue-gl in my app.js as
const { VglRenderer, VglScene } = require('vue-gl');
Object.keys(VueGL).forEach((name) => Vue.component(name, VueGL[name]));
Then in my parent component I have a child component:
<scene :positionItem="positionItem"></scene>
import scene from "./../components/scene";
Having this code:
export default {
name: "configurator",
components :{
scene
},
data: function(){
return {
positionItem: -4,
}
},
methods:{
updatePosition(){
this.$root.$emit("input", {
positionItem :this.$refs.positionItem.value
})
}
},
mounted() {
this.$root.$on('input', data => {
this.positionItem = data;
});
}
}
The child component "scene" is
<template>
<vgl-renderer >
<vgl-sphere-geometry name="sphere"></vgl-sphere-geometry>
<vgl-scene name="main">
<!-- Re-rendering will be triggered when zCoordinate changes. -->
<vgl-mesh :position="`0 0 ${positionItem}`" geometry="sphere"></vgl-mesh>
</vgl-scene>
<vgl-perspective-camera orbit-position="12 0 0" name="camera"></vgl-perspective-camera>
</vgl-renderer>
<script lang="ts">
export default {
props: ["positionItem"],
data: function () {
return {
}
},
}
</script>
The renders works but I got 2 errors about missing props camera and scene:
vue.esm.js?efeb:628 [Vue warn]: Missing required prop: "camera"
found in
--->
at src/components/scene.vue
at src/components/configurator.vue
at src/App.vue
How to fix it?
I had the exact same problem. The vgl-renderer component needs to be given a name and a screne property of type string. These components must be present in the scene with the same names. Otherwise vue-gl will throw another error. I can't find anything about these required properties on the vue-gl documentation. Maybe it's outdated. I managed to get it working like this ...
<template>
<vgl-renderer
camera= "camera"
scene= "scene"
class="getting-started"
>
<vgl-box-geometry name="box"></vgl-box-geometry>
<vgl-scene name="scene">
<vgl-mesh geometry="box"></vgl-mesh>
</vgl-scene>
<vgl-perspective-camera name="camera" orbit-position="3 1 0.5"></vgl-perspective-camera>
</vgl-renderer>
</template>
<script>
const { VglRenderer, VglScene, VglBoxGeometry, VglMesh, VglPerspectiveCamera } = require('vue-gl');
export default {
components : {
VglRenderer, VglScene, VglBoxGeometry, VglMesh, VglPerspectiveCamera
}
}
</script>
I can't get my click-event test to work.
I'm using a Vuetify component: v-btn, but my click-event doesn't seem to dispatch. I tried using a normal button tag, but that had the same outcome. I'm new at testing, this is actually my first run, so tips and pointer are welcome.
This is my component being tested:
<template>
<div>
<div class="marked">
<h2>Clicks: {{ counter }}</h2>
</div>
<v-btn #click="addOne" :style="buttonStyle">Counter</v-btn>
</div>
</template>
<script>
export default {
name: "UnitTesting",
data() {
return {
counter: 0
};
},
computed: {
count() {
return this.counter;
},
buttonStyle() {
return {
border: "solid 2px blue",
background: "black",
padding: "5px 12px",
color: "white",
borderRadius: "8px"
};
}
},
methods: {
addOne() {
this.counter++;
}
}
};
</script>
I have a simple test here to see if the component does mount, checks the content of the title, and tries to dispatch an event for the button, failing:
// Library
import Vue from "vue"
import Vuetify from "vuetify";
// Utils
import UnitTesting from "../UnitTesting.vue";
import { mount, createLocalVue } from '#vue/test-utils'
const localVue = createLocalVue()
Vue.use(Vuetify);
describe("UnitTesting.vue", () => {
let vuetify;
beforeEach(() => {
vuetify = new Vuetify()
})
it("Testing UnitTesting Component", () => {
const wrapper = mount(UnitTesting, {
localVue,
vuetify,
});
expect(wrapper).toBeTruthy()
});
it("Testing button", () => {
const wrapper = mount(UnitTesting, {
localVue, vuetify
});
const event = jest.fn();
const button = wrapper.find(".v-btn");
expect(button.text()).toContain("Counter")
const title = wrapper.find(".marked");
expect(title.text()).toContain("Clicks: 0");
button.vm.$on("action-btn:clicked", event);
expect(event).toHaveBeenCalledTimes(0);
button.trigger("click");
expect(event).toHaveBeenCalledTimes(1);
})
})
As you can see, my test breaks when it expects the click-event to have been dispatched:
FAIL src/views/__tests__/UnitTesting.spec.js
● UnitTesting.vue › Testing button
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
37 | expect(event).toHaveBeenCalledTimes(0);
38 | button.trigger("click");
> 39 | expect(event).toHaveBeenCalledTimes(1);
| ^
40 | })
41 | })
at Object.<anonymous> (src/views/__tests__/UnitTesting.spec.js:39:19)
Test Suites: 1 failed, 1 passed, 2 total
Tests: 1 failed, 2 passed, 3 total
Snapshots: 0 total
Time: 2.249 s
Did I do something wrong?
The problem seems to be the event name you're listening to. There is no action-btn:clicked event from v-btn. However, there is a click event. Changing your event name resolves the issue:
//button.vm.$on("action-btn:clicked", event); // DON'T DO THIS
button.vm.$on("click", event);
Try mocking like addOne instead of event
You need to mock the actual event instead you are creating new one which component is not aware of
wrapper.vm.addOne = jest.fn();
expect(wrapper.vm.addOne).toHaveBeenCalledTimes(1);
I have created a project in vuetify and now trying to unit test it using jest.
I have button that I have created using v-btn, which toggles the value of a boolean variable.
To check whether the button has been clicked, I tried to get hold of the button using the class name I gave to v-btn, but its not working
I have tried using shallow mounting and plain mounting. I tried to capture the tag (v-btn) itself, but it didn't work
some.vue
<template>
<div>
<v-btn class="profile-button" #click="isProfile = !isProfile">Profile</v-btn>
<v-btn icon color="#fff" class="expand" small fab absolute right #click="mini = !mini">
<v-icon color="#fcbc00">chevron_right</v-icon>
</v-btn>
</div>
</template>
<script>
export default {
data() {
return {
isProfile: true,
mini: true
}
}
}
</script>
some.spec.js
import { shallowMount } from '#vue/test-utils';
import Profile from '#/components/Profile.vue';
import Vue from 'vue'
import Vuetify from 'vuetify'
describe('Profile.vue', () => {
Vue.use(Vuetify)
it('Profile is a vue instance', () => {
const wrapper = shallowMount(Profile);
expect(wrapper.isVueInstance()).toBeTruthy()
});
it('Profile Button exists', () => {
const wrapper = shallowMount(Profile);
expect(wrapper.contains('.profile-button')).toBe(true)
});
it('Profile Button is clicked', () => {
const wrapper = shallowMount(Profile);
expect(wrapper.contains('.profile-button')).trigger('click')
});
it('Has an expand button', () => {
const wrapper = shallowMount(Profile)
wrapper.find('expand').trigger('click')
})
});
All the tests should be passed. But I receive the following error:
expect(received).toBe(expected) // Object.is equality
Expected: true
Received: false
19 |
20 | it('Profile Button exists', () => {
> 21 | expect(wrapper.contains('.profile-button')).toBe(true)
| ^
22 | })
[vue-test-utils]: find did not return expand, cannot call trigger()
on empty Wrapper
16 | it('Has an expand button', () => {
17 | const wrapper = shallowMount(SideDrawer)
> 18 | wrapper.find('expand').trigger('click')
| ^
19 | })
20 | });
What should I do? I have many such buttons that I need to test and I am stuck, as I tried everything.
Got the solution!
I was asserting the value of wrapper.find('.profile-button') with true.
It should be changed to:
(wrapper.find('.profile-button').exists()).toBe(true)
(wrapper.find('.profile-button').exists()) returns a boolean value, which is what we want to assert.