Chapter 3.4.6: Unit Test Utils
We create our own Unit Test Utils for convenience and to serve as a thin layer of abstraction.
Disclaimer: You are reading an early version of the text! The final version of the book will be revised and may contain additional content.
Thanks to the Bridge Pattern, we can 100% decouple our Application Tests from our test framework. When it comes to Application Tests, this offers multiple benefits:
We can swap test frameworks whenever we like.
We can enforce best practices for writing Application Tests.
We can implement multiple drivers for different use cases (e.g., Vitest for instant feedback and Cypress for its UI)
When it comes to Unit Tests, although 1. and 2. are still relevant, they're less important in this context. There are less elaborate measures we can take that enable us to make swapping test frameworks painless. Enforcing best practices, although equally desirable, is much more complicated with Unit Testing. The same is true for Component Tests.
But what about point 3? This aspect is also less relevant when it comes to Unit Testing. One of the essential characteristics of Unit Tests is that they're fast. So when choosing a Unit Test framework, we want to select one fast enough for everyday use. Consequently, there should be no need for swapping Unit Test frameworks for different use cases. Getting immediate feedback is the use case.
Still, for Component Tests, it would be nice if we could run them in Cypress when we need visual feedback. But to cut things short: as of now, it is not possible to implement a generic driver that enables us to run the same Component Test in both Vitest and Cypress. There are technical reasons for this. However, I see little benefit in examining them in great detail. Only so much: they have to do with how Cypress bundles the components under test.
But there is also a practical reason that speaks against implementing a generic Driver interface for Component Tests: a significant drawback of the Driver we came up with above is that we can't deal with return values. Because of the level of abstraction necessary to deal with async and (pseudo) sync code alike, we took a shortcut that simplifies the implementation of a generic Driver at the cost of making it impossible to deal with return values. While we can write flawless Application Tests without considering return values, when writing Unit Tests, we can't do without this capability.
Two perspectives
We write Application Tests purely from a user's perspective interacting with our application. But Component Tests are different. While for interactions (clicking, typing), it is the same as with Application Tests (we write them from a user's perspective), we also have to consider the perspective of a consumer of our component (ourselves or our fellow developer colleagues). For example, imagine mounting a component in a test: first, we must provide props. And sometimes, we want to test if the component emits a particular event when the user clicks on a specific button, for example. We, as developers, are interested in those things, but not our users.
Keep reading with a 7-day free trial
Subscribe to Good Tests for Vue Applications to keep reading this post and get 7 days of free access to the full post archives.