VueJS unit tests as a learning tool: v-for
This is the third post in a series which dives into unit tests within the VueJS code base in order to gain a deeper understanding of how elements within the Vue ecosystem work. I recommend checking out the first post on v-show and second post on v-if before diving into this article.
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-for’ unit tests
In this third post in the series we will take a look at the v-for
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-for
test spec.
This first set of tests reveals that v-for
works much like JavaScript’s forEach
method. In these tests we see that an array is iterated over and the value of each item
in the array is rendered as a span
. Operations such as push
and splice
are applied to the array and the rendered HTML reacts as we would expect.
The final block of tests in this first section teaches us a new syntax. It appears that a second argument can be used within v-for
and it is the index
of the item
currently being iterated over. We see this index
correctly rendered and updated as the associated array is operated on.
This next set of tests is very similar to the first, but reveals that v-for
works with objects just as it works with primitives. By referencing item.value
in the interpolation, we can render the value
property in each span
.
The second argument, index
, works with objects just as it does with primitives. We are now beginning to see how powerful the v-for
directive can be, as iterating over objects is something we will most likely want to do in our application’s templates.
We begin to appreciate the flexibility of v-for
as we read through the next set of unit tests. Not only does v-for
work with arrays of both primitives and objects, but it also works with the individual properties of an object. By using the basic val in obj
syntax we can render each value within the object.
When iterating over the properties of an object, the second argument refers to the key rather than the index. We notice in the second block of tests that we can easily access and render these keys.
You may be wondering: can we still access the index somehow? Yes we can! The next block of tests reveals that the third argument is the index when iterating over the properties of an object.
The final block of tests in this section shows that we can also iterate over each of the properties of data
itself. If we apply a v-for
to $data
we can gain access to the key and value of each property on the top-level data
. Nice!
As we continue to read through the unit tests, we come across a section which reveals how v-for
and v-if
work when used on the same element. It appears that the order of v-for
and v-if
does not matter. The v-if
directive will be applied to each individual iteration whether it is placed before or after the v-for
.
This simple test highlights the fact that v-for
can be used to iterate over a range of numbers. So, for example, if we wanted to render a certain UI element ten times we could use v-for=”n in 10”
instead of adding the same element to our markup ten times.
In this next set of tests we learn how the key can be used. If a key binding is not used, DOM elements are reused in place. We see that although the msg
within the first child changes, the DOM element was simply reused. Nice and efficient!
However, when a key binding is used and a unique identifier is passed to it, in this case item.id
, the DOM element is actually moved as the data it is bound to changes.
Moving on, we find out that v-for
s can be nested and will work exactly as expected. We can access any level of our data which we need by nesting v-for
s. An array of arrays, an array of objects, an array of objects with properties which are arrays? No problem!
This next set of tests reveals that we do not need to rely on native DOM elements such as div
and span
. We can wrap an entire block of HTML markup in a template
tag and slap a v-for
on that template. This entire block of HTML will then be rendered for each iteration.
So now we know that v-for
can be applied to HTML elements such as div
s and to template
s. We’re itching for something even more powerful though. Can v-for
be applied to components? Why yes it can!
We see here that v-for
can be applied to a component and data can be passed through props
. Do not worry about props
and slot
at this point though. We will cover them in detail in future posts. The important thing to take away from this first block of tests is that v-for
can indeed be applied to a component.
Further down in this section of tests we see tests for v-for
with “dynamic components”. The :is
binding is used to determine which component is to be rendered. Again, more on this to come in future posts. The “key” point to understand here (pun intended) is that we must provide a :key
binding when using v-for
with dynamic components. Otherwise, we can expect to see the “component lists rendered with v-for should have explicit keys” error message.
This next small block of tests simply highlights the reactivity of v-for
. Changes to deeply nested data within a nested v-for
will indeed be reflected in the DOM thanks to the reactive nature of v-for
!
This final block of tests reveals one more cool fact. v-for
can be used on strings and will iterate over each character in the string passed to it. A small but interesting feature of v-for
.
‘v-for’ docs
The v-for 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-for
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!
Next up
In the next post, to be published soon, we will compare v-text
to v-html
through their unit tests!
Previous posts
If you enjoyed this post please hit the little 💚 below to let me know you’d like more of this material! Thanks! 🤓