diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js index 49005c9..7b6dbd9 100644 --- a/src/.vuepress/config.js +++ b/src/.vuepress/config.js @@ -1,11 +1,15 @@ const sidebar = { guide: [ + { + title: 'Introduction', + collapsable: false, + children: ['/guide/introduction', '/guide/write-easy-test'] + }, { title: 'Essentials', collapsable: false, children: [ '/guide/installation', - '/guide/introduction', '/guide/a-crash-course', '/guide/conditional-rendering', '/guide/event-handling', @@ -71,7 +75,7 @@ module.exports = { '/api/': sidebar.api }, nav: [ - { text: 'Guide', link: '/guide/introduction' }, + { text: 'Guide', link: '/guide/installation' }, { text: 'API Reference', link: '/api/' }, { text: 'Migration from VTU 1', link: '/guide/migration' }, { text: 'GitHub', link: 'https://github.com/vuejs/vue-test-utils-next' } diff --git a/src/guide/introduction.md b/src/guide/introduction.md index 135ff5e..dc01693 100644 --- a/src/guide/introduction.md +++ b/src/guide/introduction.md @@ -1,4 +1,4 @@ -## Vue Test Utils Documentation +# What is Vue Test Utils? Welcome to Vue Test Utils, the official testing utility library for Vue.js! @@ -9,8 +9,6 @@ In short: * [Vue Test Utils 1](https://github.com/vuejs/vue-test-utils/) targets [Vue 2](https://github.com/vuejs/vue/). * [Vue Test Utils 2](https://github.com/vuejs/vue-test-utils-next/) targets [Vue 3](https://github.com/vuejs/vue-next/). -## What is Vue Test Utils? - Vue Test Utils (VTU) is a set of utility functions aimed to simplify testing Vue.js components. It provides some methods to mount and interact with Vue components in an isolated manner. Let's see an example: diff --git a/src/guide/write-easy-test.md b/src/guide/write-easy-test.md new file mode 100644 index 0000000..c66ca63 --- /dev/null +++ b/src/guide/write-easy-test.md @@ -0,0 +1,125 @@ +# Write components that are easy to test + +Vue Test Utils helps you write tests for Vue components. However, there's only so much VTU can do. + +Following is a list of suggestions to write code that is easier to test, and to write tests that are meaningful and simple to maintain. + +The following list provide general guidance and it might come in handy in common scenarios. + +## Do not test implementation details + +Think in terms of inputs and outputs from a user perspective. Roughly, this is everything you should take into account when writing a test for a Vue component: + +| **Inputs** | Examples | +| ------------ | ------------------------------------------------- | +| Interactions | Clicking, typing... any "human" interaction | +| Props | The arguments a component receives | +| Data streams | Data incoming from API calls, data subscriptions… | + +| **Outputs** | Examples | +| ------------ | ---------------------------------------------- | +| DOM elements | Any _observable_ node rendered to the document | +| Events | Emitted events (using `$emit`) | +| Side Effects | Such as `console.log` or API calls | + +### Everything else is implementation details + +Notice how this list does not include elements such as internal methods, intermediate states or even data. + +The rule of thumb is that **a test should not break on a refactor**, that is, when we change its internal implementation without changing its behavior. If that happens, the test might rely on implementation details. + +For example, let's assume a basic Counter component that features a button to increment a counter. We could write the following test: + +```vue + + + +``` + +We could write the following test: + +```js +import { mount } from '@vue/test-utils' +import Counter from './Counter.vue' + +test('counter text updates', async () => { + const wrapper = mount(Counter) + const paragraph = wrapper.find('.paragraph') + + expect(paragraph.text()).toBe('Times clicked: 0') + + await wrapper.setData({ count: 2 }) + + expect(paragraph.text()).toBe('Times clicked: 2') +}) +``` + +Notice how here we're updating its internal data, and we also rely on details (from a user perspective) such as CSS classes. + +:::tip +Notice that changing either the data or the CSS class name would make the test fail. The component would still work as expected, though. This is known as a **false positive**. +::: + +Instead, the following test tries to stick with the inputs and outputs listed above: + +```js +import { mount } from '@vue/test-utils' + +test('text updates on clicking', async () => { + const wrapper = mount(Counter) + + expect(wrapper.text()).toBe('Times clicked: 0') + + const button = wrapper.find('button') + await button.trigger('click') + await button.trigger('click') + + expect(wrapper.text()).toBe('Times clicked: 2') +}) +``` + +Libraries such as [Vue Testing Library](https://github.com/testing-library/vue-testing-library/) are build upon these principles. If you are interested in this approach, make sure you check it out. + +## Build smaller, simpler components + +A general rule of thumb is that if a component does less, then it will be easier to test. + +Making smaller components will make them more composable and easier to understand. Following is a list of suggestions to make components simpler. + +### Extract API calls + +Usually, you will perform several HTTP requests throughout your application. From a testing perspective, HTTP requests provide inputs to the component, and a component can also send HTTP requests. + +:::tip +Check out the [Making HTTP requests](../guide/http-requests.md) guide if you are unfamiliar with testing API calls. +::: + +### Extract complex methods + +Sometimes a component might feature a complex method, perform heavy calculations, or use several dependencies. + +The suggestion here is to **extract this method and import it to the component**. This way, you can test the method in isolation using Jest or any other test runner. + +This has the additional benefit of ending up with a component that's easier to understand because complex logic is encapsulated in another file. + +Also, if the complex method is hard to set up or slow, you might want to mock it to make the test simpler and faster. Examples on [making HTTP requests](../guide/http-requests.md) is a good example – axios is quite a complex library! + +## Write tests before writing the component + +You can't write untestable code if you write tests beforehand! + +Our [Crash Course](../guide/a-crash-course.md) offers an example of how writing tests before code leads to testable components. It also helps you detect and test edge cases.