You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When it comes to building reliable applications, tests can play a critical role in an individual or team's ability to build new features, refactor code, fix bugs, etc. While there are many schools of thought with testing, there are three categories often discussed in the context of Vue applications:
9
+
When it comes to building reliable applications, automated tests can play a critical role in an individual or team's ability to build new features, refactor code, and fix bugswith confidence.
10
10
11
-
- Unit Testing
12
-
- Component Testing
13
-
- End-To-End (E2E) Testing
11
+
In a Vue application, there are different types of concerns that can be covered by automated tests:
14
12
15
-
We will briefly discuss what each of these are concerned with, and provide some general recommendations.
13
+
-**Logic**: verify non-UI rendering logic is implemented correctly. This typically involves application-wide business logic (e.g. state management stores) and utility functions.
14
+
15
+
-**Visual**: given certain input props / state, verify that an isolated component or component tree is rendering the correct visual output.
16
+
17
+
-**Interaction**: given a simulate user behavior such as click or input, verify that an isolated component or component tree renders correct, updated output.
18
+
19
+
-**User Flow**: given a sequence of user interactions that are necessary to complete an actual user task, whether the application as a whole is working as expected.
20
+
21
+
For different testing concerns, we need to use different testing techniques:
22
+
23
+
-**Unit Testing** covers **Logic** tests.
24
+
-**Component Testing** covers **Visual** and **Interaction** tests.
We will briefly discuss what each of these are, how they can be implemented for Vue applications, and provide some general recommendations.
16
28
17
29
## Unit Testing
18
30
19
-
- Small, isolated units
20
-
- Focus on logical correctness that can be easily validated
21
-
- See [testing composables](#testing-composables) below
31
+
Unit tests are written to verify that small, isolated units of code are working as expected. They focus on logical correctness that can be easily validated. The most common example of a unit test is testing whether a function returns expected values based on different input arguments.
32
+
33
+
As mentioned previously, unit testing is typically applied to application-wide business logic or utility functions that do not involve actual UI rendering. These are typically plain JavaScript / TypeScript modules living outside of Vue components. Therefore, writing unit tests in Vue applications does not differ significantly from applications using other frameworks.
34
+
35
+
One category of functions specific to Vue applications are [Composables](/guide/reusability/composables.html), which may require special handling during tests.
36
+
See [Testing Composables](#testing-composables) below for more details.
22
37
23
38
### Recommendation
24
39
25
40
-[Vitest](https://vitest.dev/)
26
41
42
+
Since the official setup created by `create-vue` is based on [Vite](https://vitejs.dev/), we recommend using a unit testing framework that can leverage the same configuration and transform pipeline directly from Vite. [Vitest](https://vitest.dev/) is a unit testing framework designed specifically for this purpose, created and maintained by Vue / Vite team members. It integrates with Vite-based projects with minimal effort, and is blazing fast.
43
+
44
+
:::warning In Active Development
45
+
Vitest is relatively new and is still undergoing rapid development. While it is not considered stable yet, the team is working hard to get it to production ready state.
46
+
:::
47
+
27
48
### Other Options
28
49
29
-
-[Peeky](https://peeky.dev/)
30
-
- Jest
31
-
-Mocha
50
+
-[Peeky](https://peeky.dev/) is another fast unit test runner with first-class Vite integration. It is also created by a Vue core team member and offers a GUI-based testing interface.
51
+
52
+
-[Jest](https://jestjs.io/) is a popular unit testing framework, and can be made to work with Vite via the [vite-jest](https://github.com/sodatea/vite-jest) package. However, we only recommend Jest if you have an existing Jest test suite that needs to be migrated over to a Vite-based project, as Vitest offers a more seamless integration and better performance.
32
53
33
54
## Component Testing
34
55
35
-
- Component testing is a form of integration testing
36
-
- Test the interfaces (props and events), not the internals
56
+
In Vue applications, components are the main building blocks of the UI. Components are therefore the natural unit of isolation when it comes to visual and interaction tests. From a granularity perspective, component testing sits somewhere above unit testing and can be considered a form of integration testing. In some cases we will be testing a single component, but in other cases we could be testing a tree of components to make sure they are integrated correctly.
57
+
58
+
Component tests should focus on the component's public interfaces rather than internal implementation details. Or, in other words, **test what a component does, not how it does it**.
59
+
60
+
-**DO**
61
+
62
+
- For **Visual** tests: assert correct render output based on input props and slots.
63
+
- For **Interaction** tests: assert correct render updates or emitted events in response to user input events.
64
+
65
+
-**DON'T**
66
+
67
+
Assert the private state of a component instance or test the private methods of a component. Testing implementation details makes the tests brittle, as they are more likely to break and require updates when the implementation changes.
68
+
69
+
The component's ultimate job is rendering the correct DOM output, so the tests focusing on the DOM output provides the same level of correctness assurance (if not more) while being more robust and resistant to change.
70
+
71
+
If a method needs to be tested, extract it into a standalone utility function and write a dedicated unit test for it. If it cannot be extracted cleanly, it should be tested as a part of an interaction test that invokes it.
37
72
38
73
### Recommendation
39
74
40
-
- Vitest
41
-
- Cypress Component Testing
75
+
-[Vitest](https://vitest.dev/) or other unit test frameworks mentioned above can be used for component testing by simulating the DOM in Node.js. See [Adding Vitest to a Project](#adding-vitest-to-a-project) for more details.
Component testing often involves mounting the component being tested in isolation, triggering simulated user input events, and asserting the rendered DOM output. There are dedicated utility libraries that make these tasks simpler.
80
+
81
+
-[`@testing-library/vue`](https://github.com/testing-library/vue-testing-library) is a Vue testing library focused on testing components without relying on implementation details. Built with accessibility in mind, its approach also makes refactoring a breeze. Its guiding principle is that the more tests resemble the way software is used, the more confidence they can provide.
82
+
83
+
-[`@vue/test-utils`](https://github.com/vuejs/vue-test-utils) is the official low-level component testing library that was written to provide users access to Vue specific APIs. It's also the lower-level library `@testing-library/vue` is built on top of.
84
+
85
+
We recommend using `@testing-library/vue` for testing components in applications, as its focus aligns better with the testing priorities of applications. Use `@vue/test-utils` only if you are building advanced components that require testing Vue-specific internals.
47
86
48
87
### Other Options
49
88
50
-
- Nightwatch Component Testing
89
+
-[Cypress](https://www.cypress.io/) is an E2E test solution, but it also supports [Component Testing](https://docs.cypress.io/guides/component-testing/introduction) which can test components in real browsers with a GUI that shows the actual DOM state during tests.
90
+
91
+
-[Nightwatch v2](https://v2.nightwatchjs.org/) is another E2E test runner with Vue Component Testing support in v2 (currently beta - [Exmaple Project](https://github.com/nightwatchjs-community/todo-vue)).
51
92
52
93
## E2E Testing
53
94
95
+
While unit tests provide developers with some degree of confidence, unit and component tests are limited in their abilities to provide holistic coverage of an application when deployed to production. As a result, end-to-end (E2E) tests provide coverage on what is arguably the most important aspect of an application: what happens when users actually use your applications.
96
+
97
+
In other words, E2E tests validate all of the layers in your application. This not only includes your frontend code, but all associated backend services and infrastructure that are more representative of the environment that your users will be in. By testing how user actions impact your application, E2E tests are often the key to higher confidence in whether an application is functioning properly or not.
98
+
99
+
### Choosing an E2E Testing Solution
100
+
101
+
While end-to-end (E2E) testing on the web has gained a negative reputation for unreliable (flaky) tests and slowing down development processes, modern E2E tools have made strides forward to create more reliable, interactive, and useful tests. When choosing an E2E testing framework, the following sections provide some guidance on things to keep in mind when choosing a testing framework for your application.
102
+
103
+
#### Cross-browser testing
104
+
105
+
One of the primary benefits that end-to-end (E2E) testing is known for is its ability to test your application across multiple browsers. While it may seem desirable to have 100% cross-browser coverage, it is important to note that cross browser testing has diminishing returns on a team's resources due the additional time and machine power required to run them consistently. As a result, it is important to be mindful of this trade-off when choosing the amount of cross-browser testing your application needs.
106
+
107
+
#### Faster feedback loops
108
+
109
+
One of the primary problems with end-to-end (E2E) tests and development is that running the entire suite takes a long time. Typically, this is only done in continuous integration and deployment (CI/CD) pipelines. Modern E2E testing frameworks have helped to solve this by adding features like parallelization, which allows for CI/CD pipelines to often run magnitudes faster than before. In addition, when developing locally, the ability to selectively run a single test for the page you are working on while also providing hot reloading of tests can help to boost a developer's workflow and productivity.
110
+
111
+
#### First class debugging experience
112
+
113
+
While developers have traditionally relied on scanning logs in a terminal window to help determine what went wrong in a test, modern end-to-end (E2E) test frameworks allow developers to leverage tools that they are already familiar with, e.g. browser developer tools.
114
+
115
+
#### Visibility in headless mode
116
+
117
+
When end-to-end (E2E) tests are run in continuous integration / deployment pipelines, they are often run in headless browsers (i.e., no visible browser is opened for the user to watch). As a result, when errors occur, a critical feature that modern E2E testing frameworks provide 1st class support for is the ability to see snapshots and/or videos of your applications during various testing stages in order to provide insight into why errors are happening. Historically, it was tedious to maintain these integrations.
118
+
54
119
### Recommendation
55
120
56
121
-[Cypress](https://www.cypress.io/)
57
122
123
+
Overall, we believe Cypress provides the most complete E2E solution with features like an informative graphical interface, excellent debuggability, built-in assertions and stubs, flake-resistance, parallelization, and snapshots. As mentioned above, it also provides support for [Component Testing](https://docs.cypress.io/guides/component-testing/introduction). However, it only supports Chromium-based browsers and Firefox.
124
+
58
125
### Other Options
59
126
60
-
-[Playwright](https://playwright.dev/)
61
-
-[Nightwatch](https://nightwatchjs.org/)
127
+
-[Playwright](https://playwright.dev/) is also a great E2E testing solution with a wider range of browser support (mainly WebKit). See [Why Playwright](https://playwright.dev/docs/why-playwright) for more details.
128
+
129
+
-[Nightwatch v2](https://v2.nightwatchjs.org/) is an E2E testing solution based on [Selenium WebDriver](https://www.npmjs.com/package/selenium-webdriver). This gives it the widest browser support range.
Next, update the Vite configuration to add the `test` option block:
142
+
143
+
```js{6-12}
144
+
// vite.config.js
145
+
import { defineConfig } from 'vite'
146
+
147
+
export default defineConfig({
148
+
// ...
149
+
test: {
150
+
// enable jest-like global test APIs
151
+
global: true,
152
+
// simulate DOM with happy-dom
153
+
// (requires installing happy-dom as a peer dependency)
154
+
environment: 'happy-dom'
155
+
}
156
+
})
157
+
```
158
+
159
+
Then create a file ending in `*.test.js` in your project. You can place all test files in a test directory in project root, or in test directories next to your source files. Vitest will automatically search for them using the naming convention.
160
+
161
+
```js
162
+
// MyComponent.test.js
163
+
import { render } from'@vue/testing-library'
164
+
importMyComponentfrom'./MyComponent.vue'
165
+
166
+
test('it should work', () => {
167
+
const { getByText } =render(MyComponent, {
168
+
props: {
169
+
/* ... */
170
+
}
171
+
})
172
+
173
+
// assert output
174
+
getByText('...')
175
+
})
176
+
```
177
+
178
+
Finallym, update `package.json` to add the test script and run it:
179
+
180
+
```json{4}
181
+
{
182
+
// ...
183
+
"scripts": {
184
+
"test": "vitest"
185
+
}
186
+
}
187
+
```
188
+
189
+
```sh
190
+
> npm test
191
+
```
192
+
65
193
### Testing Composables
66
194
67
-
- Composables without Side Effects
195
+
> This section assumes you have read the [Composables](/guide/reusability/composables.html) section.
196
+
197
+
When it comes to testing composables, we can divide them into two categories: composables that do not rely on a host component instance, and composables that do.
198
+
199
+
A composable depends on a host component instance when it uses the following APIs:
200
+
201
+
- Lifecycle hooks
202
+
- Provide / Inject
203
+
204
+
If a composable only uses Reactivity APIs, then it can be tested by directly invoking it and asserting its returned state / methods:
205
+
206
+
```js
207
+
// counter.js
208
+
import { ref } from'vue'
209
+
210
+
exportfunctionuseCounter() {
211
+
constcount=ref(0)
212
+
constincrement= () =>count.value++
213
+
214
+
return {
215
+
count,
216
+
increment
217
+
}
218
+
}
219
+
```
220
+
221
+
```js
222
+
// counter.test.js
223
+
import { useCounter } from'./counter.js'
224
+
225
+
test('useCounter', () => {
226
+
const { count, increment } =useCounter()
227
+
expect(count.value).toBe(0)
228
+
229
+
increment()
230
+
expect(count.value).toBe(1)
231
+
})
232
+
```
233
+
234
+
A composable that relies on lifecycle hooks or Provide / Inject needs to be wrapped in a host component to be tested. We can create a helper like the following:
235
+
236
+
```js
237
+
// test-utils.js
238
+
import { createApp } from'vue'
239
+
240
+
exportfunctionwithSetup(composable) {
241
+
let result
242
+
constapp=createApp({
243
+
setup() {
244
+
result =composable()
245
+
// suppress missing template warning
246
+
return () => {}
247
+
}
248
+
})
249
+
app.mount(document.createElement('div'))
250
+
// return the result and the app instance
251
+
// for testing provide / unmount
252
+
return [result, app]
253
+
}
254
+
```
255
+
```js
256
+
import { withSetup } from'./test-utils'
257
+
import { useFoo } from'./foo'
258
+
259
+
test('useFoo', () => {
260
+
const [result, app] =withSetup(() =>useFoo(123))
261
+
// mock provide for testing injections
262
+
app.provide(...)
263
+
// run assertions
264
+
expect(result.foo.value).toBe(1)
265
+
// trigger onUnmounted hook if needed
266
+
app.unmount()
267
+
})
268
+
```
68
269
69
-
- Composables with Side Effects or Provide / Inject
270
+
For more complex composables, it could also be easier to test it by writing tests against the wrapper component using [Component Testing](#component-testing) techniques.
70
271
71
272
<!-- TODO link to this from composables page -->
72
273
73
274
<!--
74
-
TODO more testing recipes can be added in the future
75
-
e.g. mocking, CI setup, etc.
275
+
TODO more testing recipes can be added in the future e.g.
0 commit comments