In this post, we will see the differences between shallowMount
and mount functions in vue-test-utils library and what they both offer us in terms of unit testing in Vue applications.
If you want to know how to set up unit tests for the Vue project, check my article on how to do it.
Let’s have an App.vue
and HelloWorld.vue
files and HelloWorld component is a child component of App.vue
.
The App component passes msg
as a prop to the HelloWorld component and the hello world component will display the passed message.
The above code diagram is our example for this blog post to understand mount and shallowMount functions.
The mount
function takes in the Vue component as a first argument and has options
as a second argument. The mount function will return Vue instance wrapper of the component passed in.
So, If I mount the App
component, I can have access to the child component’s DOM elements as well.
The purpose of the mount function is (per my understanding)
When changing a property or something in the parent component, If there’s a change to the DOM element in the child component, then we can assert the child element properties to see if it matches the expectation.
Here is the App.vue
component.
<template> <div id="app"> <HelloWorld :msg="msg" /> </div> </template> ... export default { name: "App", components: { HelloWorld }, data() { return { msg: "Welcome to Your Vue.js App" }; } };
Now, let’s write unit tests for App.vue
file.
import { mount } from "@vue/test-utils"; import App from "@/App.vue"; describe("App.vue Tests", () => { it("message passed from App -> Hello World should be rendered", () => { const msg = "Hello World"; const wrapper = mount(App, { data() { return { msg: msg }; } }); expect(wrapper.find("div.hello > h1").text()).toBe(msg); }); });
We set up our mount function to have our custom message(msg) in the data()
function. The msg
variable is passed on to the HelloWorld component from the App component. And our text in the H1
tag should now reflect what we have in the msg
variable in the test.
So, if you want to write tests that include testing a child component’s also, then you can use the mount function on the parent element to render the component with its children and assert what you want.
Unlike mount function, shallowMount
function will just load the component itself ignoring the child component(s).
If you want to write unit tests for a component, then shallowMount
function is the right choice.
If we replace the mount
function with shallowMount
in the above mounted tests for App component, the test will fail as the shallowMount cannot load the HelloWorld component and unable to locate the div.hello > h1
in the component.
Let me run the test by replacing mount >> shallowMount
and see what happens.
it("message passed from App -> Hello World will not be rendered", () => { const msg = "Hello World"; const wrapper = shallowMount(App, { data() { return { msg: msg }; } }); expect(wrapper.find("div.hello > h1").text()).toBe(msg); });
Here’s the output after running the test
● App.vue Tests › message passed from App -> Hello World will not be rendered [vue-test-utils]: find did not return div.hello > h1, cannot call text() on empty Wrapper 12 | } 13 | }); > 14 | expect(wrapper.find("div.hello > h1").text()).toBe(msg); | ^ 15 | }); 16 | }); 17 | at throwError (node_modules/@vue/test-utils/dist/vue-test-utils.js:1709:9) at Object.<anonymous> (tests/unit/app.spec.js:14:43)
The wrapper is empty after finding the div.hello > h1
. So, the test failed.
How to pass the above failing unit test?
Instead of testing the App.vue component, test the HelloWorld component alone by using the shallowMount function. As we are interested in checking what the HelloWorld component renders in H1
tag when a message is passed.
Before we write a test for HelloWorld component, here’s what the Hello World component looks like.
<template> <div class="hello"> <h1>{{ msg }}</h1> </div> ... </template> <script> export default { name: "HelloWorld", props: { msg: String } }; </script>
Let’s write a test for HelloWorld component.
import { shallowMount } from "@vue/test-utils"; import HelloWorld from "@/components/HelloWorld"; describe("HelloWorld.vue", () => { it("H1 tag should render what is passed into the props", () => { const msg = "Hello World again"; const wrapper = shallowMount(HelloWorld, { propsData: { msg: msg } }); expect(wrapper.find("h1").text()).toBe(msg); }); });
We will use the propsData
option to pass our data to the msg
prop and verify if we got what we have passed in using the expect
function.
If we run, the test should pass now.
If you are writing unit tests and want to test the functionality of a component individually, then setup the shallowMount
function and test it.
If you want to test a nested component, then use the mount function.
I’d recommend using shallowMount function, as it’s for unit testing a component. If you have a nested component, then write tests for the component.
Karthik is a passionate Full Stack developer working primarily on .NET Core, microservices, distributed systems, VUE and JavaScript. He also loves NBA basketball so you might find some NBA examples in his posts and he owns this blog.
In this post, we’ll see how to test gRPC Server applications using different clients. And… Read More
In this post, we'll create a new gRPC project in ASP.NET Core and see what's… Read More
In this blog post, we’ll see how to run dotnet core projects without opening visual… Read More
Programmatically evaluating policies is useful when we want to provide access or hide some data… Read More
We saw how we could set up policy-based authorization in our previous article. In this… Read More
What is policy-based authorization and how to set up policy-based authorization with handlers and policies… Read More
This website uses cookies.