0
# Testing Utilities
1
2
Helper functions and utilities for common testing scenarios, including promise resolution, component lifecycle management, server-side rendering, and error handling.
3
4
## Capabilities
5
6
### Promise Resolution
7
8
Utility for flushing all pending promises in the microtask queue, essential for testing async operations.
9
10
```typescript { .api }
11
/**
12
* Flush all pending promises in the microtask queue
13
* Ensures all async operations complete before continuing test execution
14
* @returns Promise that resolves after all pending promises are flushed
15
*/
16
function flushPromises(): Promise<void>;
17
```
18
19
**Usage Examples:**
20
21
```typescript
22
import { mount, flushPromises } from "@vue/test-utils";
23
24
test('async operation handling', async () => {
25
const wrapper = mount(AsyncComponent);
26
27
// Trigger async operation
28
await wrapper.find('button').trigger('click');
29
30
// Wait for all promises to resolve
31
await flushPromises();
32
33
// Now safe to make assertions on async results
34
expect(wrapper.text()).toContain('Async data loaded');
35
});
36
37
test('API call with delay', async () => {
38
const wrapper = mount(ApiComponent);
39
40
// Component makes API call on mount
41
await flushPromises();
42
43
// API response should now be processed
44
expect(wrapper.find('.loading').exists()).toBe(false);
45
expect(wrapper.find('.data').exists()).toBe(true);
46
});
47
```
48
49
### Automatic Component Cleanup
50
51
Utilities for automatically unmounting components after tests to prevent memory leaks and test interference.
52
53
```typescript { .api }
54
/**
55
* Enable automatic unmounting of components after each test
56
* Integrates with test framework hooks to ensure cleanup
57
* @param hook - Test framework hook function (e.g., afterEach)
58
*/
59
function enableAutoUnmount(hook: (callback: () => void) => void): void;
60
61
/**
62
* Disable automatic unmounting and clear tracked instances
63
* Useful when you need manual control over component lifecycle
64
*/
65
function disableAutoUnmount(): void;
66
```
67
68
**Usage Examples:**
69
70
```typescript
71
import { enableAutoUnmount, disableAutoUnmount } from "@vue/test-utils";
72
73
// Jest integration
74
enableAutoUnmount(afterEach);
75
76
// Vitest integration
77
import { afterEach } from 'vitest';
78
enableAutoUnmount(afterEach);
79
80
// Mocha integration
81
enableAutoUnmount(afterEach);
82
83
// Manual control
84
describe('manual cleanup tests', () => {
85
beforeAll(() => {
86
disableAutoUnmount();
87
});
88
89
afterEach(() => {
90
// Manual cleanup when needed
91
wrapper?.unmount();
92
});
93
});
94
```
95
96
### Server-Side Rendering
97
98
Utility for testing Vue components in server-side rendering contexts.
99
100
```typescript { .api }
101
/**
102
* Render a Vue component to HTML string for SSR testing
103
* Uses Vue's server renderer without DOM attachment
104
* @param component - Vue component to render
105
* @param options - Mounting options (attachTo not supported)
106
* @returns Promise resolving to HTML string
107
*/
108
function renderToString<T>(
109
component: T,
110
options?: SSRMountingOptions<T>
111
): Promise<string>;
112
113
interface SSRMountingOptions<T> {
114
/** Component props */
115
props?: ComponentProps<T>;
116
/** Component slots */
117
slots?: Record<string, any>;
118
/** Global configuration */
119
global?: GlobalMountOptions;
120
/** Component attributes */
121
attrs?: Record<string, unknown>;
122
/** Component data override */
123
data?(): Record<string, unknown>;
124
// Note: attachTo is not supported in SSR
125
}
126
```
127
128
**Usage Examples:**
129
130
```typescript
131
import { renderToString } from "@vue/test-utils";
132
133
test('SSR rendering', async () => {
134
const html = await renderToString(MyComponent, {
135
props: {
136
title: "SSR Test",
137
items: ["item1", "item2"]
138
},
139
slots: {
140
default: "Slot content"
141
}
142
});
143
144
expect(html).toContain("SSR Test");
145
expect(html).toContain("item1");
146
expect(html).toContain("Slot content");
147
expect(html).not.toContain("data-v-"); // No scoped CSS in SSR
148
});
149
150
test('SSR with global config', async () => {
151
const html = await renderToString(MyComponent, {
152
global: {
153
provide: {
154
theme: 'dark'
155
},
156
components: {
157
'GlobalComponent': StubComponent
158
}
159
}
160
});
161
162
expect(html).toContain('theme-dark');
163
});
164
```
165
166
### Error Wrapper Creation
167
168
Utility for creating error wrapper proxies that provide better error messages for failed element queries.
169
170
```typescript { .api }
171
/**
172
* Create error wrapper proxy for failed find operations
173
* Provides helpful error messages and supports method chaining
174
* @param selector - The selector that failed to match
175
* @returns Proxy that throws on method calls except exists()
176
*/
177
function createWrapperError(selector: string): WrapperLike;
178
179
interface WrapperLike {
180
/** Returns false for error wrappers */
181
exists(): boolean;
182
/** Throws error for any other method calls */
183
[key: string]: any;
184
}
185
```
186
187
**Usage Examples:**
188
189
```typescript
190
import { mount } from "@vue/test-utils";
191
192
test('error wrapper behavior', () => {
193
const wrapper = mount(MyComponent);
194
195
// This creates an error wrapper since selector doesn't exist
196
const errorWrapper = wrapper.find('.non-existent');
197
198
// exists() returns false without throwing
199
expect(errorWrapper.exists()).toBe(false);
200
201
// Other methods throw helpful errors
202
expect(() => errorWrapper.text()).toThrow(
203
'Cannot call text on an empty wrapper'
204
);
205
206
expect(() => errorWrapper.trigger('click')).toThrow(
207
'Cannot call trigger on an empty wrapper'
208
);
209
});
210
211
// Practical usage with conditional logic
212
test('conditional element testing', () => {
213
const wrapper = mount(MyComponent);
214
const optionalElement = wrapper.find('.optional-element');
215
216
if (optionalElement.exists()) {
217
expect(optionalElement.text()).toBe('Optional content');
218
}
219
});
220
```
221
222
### RouterLink Stub Component
223
224
Pre-built stub component for Vue Router's RouterLink to simplify router testing.
225
226
```typescript { .api }
227
/**
228
* Stub component for Vue Router's RouterLink
229
* Provides mock router functionality for testing without requiring actual router
230
* Renders as anchor tag by default, supports custom rendering with custom prop
231
*/
232
const RouterLinkStub: Component & {
233
props: {
234
/** Router link destination (route path or route object) */
235
to: string | RouteLocationRaw;
236
/** Enable custom rendering (renders slot content without wrapper) */
237
custom?: boolean;
238
};
239
/** Mock router link composable values */
240
setup(): {
241
/** Mock route object */
242
route: RouteLocationNormalizedLoaded;
243
/** Mock href value */
244
href: string;
245
/** Mock active state */
246
isActive: boolean;
247
/** Mock exact active state */
248
isExactActive: boolean;
249
/** Mock navigation function */
250
navigate: (e?: MouseEvent) => void;
251
};
252
};
253
```
254
255
**Usage Examples:**
256
257
```typescript
258
import { mount, RouterLinkStub } from "@vue/test-utils";
259
260
test('router link interaction', async () => {
261
const wrapper = mount(MyComponent, {
262
global: {
263
stubs: {
264
'router-link': RouterLinkStub
265
}
266
}
267
});
268
269
const routerLink = wrapper.findComponent(RouterLinkStub);
270
expect(routerLink.props('to')).toBe('/target-route');
271
272
// RouterLinkStub provides mock router functionality
273
await routerLink.trigger('click');
274
expect(routerLink.emitted('navigate')).toHaveLength(1);
275
});
276
277
// Global stub configuration
278
import { config, RouterLinkStub } from "@vue/test-utils";
279
280
config.global.stubs = {
281
'router-link': RouterLinkStub
282
};
283
```
284
285
## Integration Patterns
286
287
Common patterns for integrating utilities with different testing frameworks.
288
289
### Jest Integration
290
291
```typescript
292
import { enableAutoUnmount, flushPromises } from "@vue/test-utils";
293
294
// Global setup
295
enableAutoUnmount(afterEach);
296
297
// In tests
298
beforeEach(async () => {
299
// Ensure clean state
300
await flushPromises();
301
});
302
```
303
304
### Vitest Integration
305
306
```typescript
307
import { enableAutoUnmount, flushPromises } from "@vue/test-utils";
308
import { afterEach, beforeEach } from 'vitest';
309
310
enableAutoUnmount(afterEach);
311
312
beforeEach(async () => {
313
await flushPromises();
314
});
315
```
316
317
### Custom Test Helpers
318
319
```typescript
320
import { mount, flushPromises } from "@vue/test-utils";
321
322
// Custom helper combining mounting and promise flushing
323
export async function mountAndFlush(component, options = {}) {
324
const wrapper = mount(component, options);
325
await flushPromises();
326
return wrapper;
327
}
328
329
// Custom helper for SSR testing
330
export async function renderAndTest(component, options = {}) {
331
const html = await renderToString(component, options);
332
return {
333
html,
334
contains: (text) => html.includes(text),
335
hasClass: (className) => html.includes(`class="${className}"`),
336
hasAttribute: (attr, value) => html.includes(`${attr}="${value}"`)
337
};
338
}
339
```
340
341
## Error Handling
342
343
Utility functions handle errors in these scenarios:
344
345
- **flushPromises**: Rarely throws, but may propagate unhandled promise rejections
346
- **enableAutoUnmount**: Throws if hook function is invalid
347
- **renderToString**: Throws if component rendering fails or options are invalid
348
- **createWrapperError**: Creates proxies that throw descriptive errors on method calls
349
350
```typescript
351
import { flushPromises, renderToString } from "@vue/test-utils";
352
353
try {
354
await flushPromises();
355
} catch (error) {
356
// Handle any unhandled promise rejections
357
console.error('Promise flush error:', error);
358
}
359
360
try {
361
const html = await renderToString(BrokenComponent);
362
} catch (error) {
363
console.error('SSR render error:', error.message);
364
}
365
```