Beyond alerting one to regressions in a code base, well-written unit tests read like simple sentences and help those working on a project to understand what individual features do. Unit tests can also serve as great templates for documentation if they are written well as they should describe what a feature does and how it reacts to different inputs.
The VueJS documentation is excellent, but recently I decided to dig even deeper and begin exploring the source code behind Vue! The first piece of the code base I visited was the tests directory. Most of you have surely heard of Test Driven Development (TDD). Well, in this series I would like to introduce you to Test Driven Learning (TDL). The idea is to begin reading through the unit tests of the framework or library you are using early in order to gain a deeper understanding of how individual features work. TDL also has a beneficial side-effect in that it will reinforce the benefits of writing unit tests in your own projects and reveal solid testing patterns.
‘v-if’ unit tests
In this second post in the series we will take a look at the
v-if directive. The unit tests in full can be found here, but we will be walking through them piece-by-piece below. Below is the beginning of the
v-if test spec.
The first thing we notice is how similar
v-if is to
v-show. They both work on truthy and falsy values. However, the key difference jumps out at us right away as well. Whereas
v-show set the CSS property
display: none to hide an element,
v-if removes the element from the DOM and replaces it with a comment (
This is a very important difference and gives us a big hint as to when we should choose
v-show and vice-versa. If we do not expect the value bound to
v-show to change often, if at all,
v-if is the best choice from an efficient rendering standpoint. However, if we expect this value to change fairly frequently (a toggle for example) then we should lean toward
v-show performs better in these situations because its
display property is simply toggled rather than the entire block of HTML being destroyed and re-rendered. This information becomes clear as you compare the
v-show unit tests before reading any documentation. Pretty cool!
Clearly the variable tied to
v-if could change throughout the lifecycle of a component. So what happens as
v-if evaluates to different values? The next set of tests explain this in detail!
The beginning of this set of tests reveals what we may have expected: as
foo is toggled from “truthy” to “falsy values ”the UI toggles from rendering the
span to removing it from the DOM. If you already checked out the
v-show post, this will all look familiar as it tests the same values.
The next set of tests introduces the
v-else directive and we see it added to the sibling of the span
v-if appears on. The tests are identical to the “truthy”/”falsy” tests we just saw above with one key difference. It appears that, thanks to the presence of
v-else, when the value bound to
v-if is “falsy”, the
span with the
v-else directive is rendered. Nice! So rather than adding a
<span v-if=”!foo”>bye</span>, we can simply utilize the
The final block of this section of tests introduces another directive:
v-else-if. This directive is bound to a different variable, in this case
bar. As we can see through the tests: if
foo is “truthy” it is rendered, if
foo is “falsy” but
bar is “truthy”
bar is rendered, and if both are “falsy” the element containing
v-else is rendered. So these tests reveal that the behavior of
v-if can be expanded by using
v-else. We can check multiple bound variables and the first one which evaluates to a “truthy” value will be rendered.
The next block of tests involve a directive we have yet to come across,
v-for. We will discuss this directive in detail in the next post in this series, but for now it is enough to know that it is used to iterate over values such as members of an array and render the element, in this case a
span, for each value. These tests simply reveal that
v-if works exactly how we would expect it to inside
v-for. “Truthy” values are rendered, “falsy” values are removed from the DOM.
The last couple tests show how
v-if works when coupled with
v-for. If the variable bound to
v-if is “falsy”, the element containing
v-else will be rendered for each “item” within the
v-for. In this case the digits “123” are rendered and then “321” is rendered after the “list” is reversed.
This next set of tests is interesting as it introduces a Vue component and tests how
v-if works on a component root. A new Vue instance is instantiated with a template containing a
test component. The “test” class is set on this component. This
test component is then defined to have an “ok” data property initially set to “true” and a template containing a
div with an id of “ok”, class of “inner”, and
v-if bound to the
ok data property.
We then test to ensure that the
div at the root of this
test component is indeed rendered by checking for the id of “ok” and both the “inner” and “test” classes. Next we flip that
ok data property to “false” and test again and find that the
test component has been removed from the DOM. Flipping
ok back to “true” renders our
test component once again. We now know how to combine
v-if with components to render or remove them from the DOM. Nice!
In this final test block we notice the mention of “unnecessary patches”. This should tip us off to the fact that we are about to learn about some efficiency optimizations of working with
First, a couple spies are created through Jasmine’s
createSpy method. At a high-level what this is doing is simply “spying” on the
destroyed methods so we can eventually test how many times they have been called (if at all). A new Vue instance is then spun up with an
ok data property set to “true”. A
test component is also created which “lives” on a sibling
div to the
destroyed events are tied to this component.
We test that
created was called once as expected. We then flip
ok to “false” and test the number of
created calls once again. We find this is still one which means when the
v-if was destroyed the
test was not re-rendered. Finally, we check that this
div was not destroyed and find that it was not through the fact that
destroyed was never called. This is pretty awesome if you think about it. As the comment within the test states:
“when the first div is toggled, the second div should be reused instead of re-created/destroyed”
That’s a very efficient way to make DOM updates, ONLY update what has changed and re-use the DOM elements which remain the same.
The v-if API docs section should make complete sense to us now that we have studied the unit tests:
As I mentioned earlier, the VueJS docs are excellent, but I would argue that reading through the unit tests behind
v-if taught us all that the docs reveal and more in just a couple minutes of reading! Also, as I mentioned, reading through the tests taught us how unit tests should be written and how thorough they should be. Writing similar tests for features within your own apps should become a priority for you and your team!
In the next post, to be published soon, we will take a deep-dive into
v-for through its unit tests!
The first post in this series covered
v-show and can be found here.
If you enjoyed this post please hit the little 💚 below to let me know you’d like more of this material! Thanks! 🤓