|
1 | 1 | # Stubs and Shallow Mount
|
2 | 2 |
|
3 |
| -Vue Test Utils provides some advanced features for _stubbing_ components. A _stub_ is where you replace an existing implementation of a custom component with a dummy component that doesn't do anything at all, which can simplify an otherwise complex test. Let's see an example. |
| 3 | +Vue Test Utils provides some advanced features for _stubbing_ components and directives. A _stub_ is where you replace an existing implementation of a custom component or directive with a dummy one that doesn't do anything at all, which can simplify an otherwise complex test. Let's see an example. |
4 | 4 |
|
5 | 5 | ## Stubbing a single child component
|
6 | 6 |
|
@@ -238,6 +238,78 @@ test('stubs async component with resolving', async () => {
|
238 | 238 | })
|
239 | 239 | ```
|
240 | 240 |
|
| 241 | +## Stubbing a directive |
| 242 | + |
| 243 | +Sometimes directives do quite complex things, like perform a lot of DOM manipulation which might result in errors in your tests (due to JSDOM not resembling entire DOM behavior). A common example is tooltip directives from various libraries, which usually rely heavily on measuring DOM nodes position/sizes. |
| 244 | + |
| 245 | +In this example, we have another `<App>` that renders a message with tooltip |
| 246 | + |
| 247 | +```js |
| 248 | +// tooltip directive declared somewhere, named `Tooltip` |
| 249 | + |
| 250 | +const App = { |
| 251 | + directives: { |
| 252 | + Tooltip |
| 253 | + }, |
| 254 | + template: '<h1 v-tooltip title="Welcome tooltip">Welcome to Vue.js 3</h1>' |
| 255 | +} |
| 256 | +``` |
| 257 | + |
| 258 | +We do not want the `Tooltip` directive code to be executed in this test, we just want to assert the message is rendered. In this case, we could use the `stubs`, which appears in the `global` mounting option passing `vTooltip`. |
| 259 | + |
| 260 | +```js |
| 261 | +test('stubs component with custom template', () => { |
| 262 | + const wrapper = mount(App, { |
| 263 | + global: { |
| 264 | + stubs: { |
| 265 | + vTooltip: true |
| 266 | + } |
| 267 | + } |
| 268 | + }) |
| 269 | + |
| 270 | + console.log(wrapper.html()) |
| 271 | + // <h1>Welcome to Vue.js 3</h1> |
| 272 | + |
| 273 | + expect(wrapper.html()).toContain('Welcome to Vue.js 3') |
| 274 | +}) |
| 275 | +``` |
| 276 | + |
| 277 | +::: tip |
| 278 | +Usage of `vCustomDirective` naming scheme to differentiate between components and directives is inspired by [same approach](https://vuejs.org/api/sfc-script-setup.html#using-custom-directives) used in `<script setup>` |
| 279 | +::: |
| 280 | + |
| 281 | +Sometimes, we need a part of directive functionality (usually because some code relies on it). Let's assume our directive adds `with-tooltip` CSS class when executed and this is important behavior for our code. In this case we can swap `true` with our mock directive implementation |
| 282 | + |
| 283 | +```js |
| 284 | +test('stubs component with custom template', () => { |
| 285 | + const wrapper = mount(App, { |
| 286 | + global: { |
| 287 | + stubs: { |
| 288 | + vTooltip: { |
| 289 | + beforeMount(el: Element) { |
| 290 | + console.log('directive called') |
| 291 | + el.classList.add('with-tooltip') |
| 292 | + } |
| 293 | + } |
| 294 | + } |
| 295 | + } |
| 296 | + }) |
| 297 | + |
| 298 | + // 'directive called' logged to console |
| 299 | + |
| 300 | + console.log(wrapper.html()) |
| 301 | + // <h1 class="with-tooltip">Welcome to Vue.js 3</h1> |
| 302 | + |
| 303 | + expect(wrapper.classes('with-tooltip')).toBe(true) |
| 304 | +}) |
| 305 | +``` |
| 306 | + |
| 307 | +We've just swapped our directive implementation with our own one! |
| 308 | + |
| 309 | +::: warning |
| 310 | +Stubbing directives won't work on functional components or `<script setup>` due to lack of directive name inside of [withDirectives](https://vuejs.org/api/render-function.html#withdirectives) function. Consider mocking directive module via your testing framework if you need to mock directive used in functional component. See https://github.com/vuejs/core/issues/6887 for proposal to unlock such functionality |
| 311 | +::: |
| 312 | + |
241 | 313 | ## Default Slots and `shallow`
|
242 | 314 |
|
243 | 315 | Since `shallow` stubs out all the content of a components, any `<slot>` won't get rendered when using `shallow`. While this is not a problem in most cases, there are some scenarios where this isn't ideal.
|
@@ -314,6 +386,6 @@ So regardless of which mounting method you choose, we suggest keeping these guid
|
314 | 386 |
|
315 | 387 | ## Conclusion
|
316 | 388 |
|
317 |
| -- use `global.stubs` to replace a component with a dummy one to simplify your tests |
| 389 | +- use `global.stubs` to replace a component or directive with a dummy one to simplify your tests |
318 | 390 | - use `shallow: true` (or `shallowMount`) to stub out all child components
|
319 | 391 | - use `global.renderStubDefaultSlot` to render the default `<slot>` for a stubbed component
|
0 commit comments