Vue.js testing utilities for Vue 3 applications providing component mounting, wrapper classes, and test utilities
—
Helper functions and utilities for common testing scenarios, including promise resolution, component lifecycle management, server-side rendering, and error handling.
Utility for flushing all pending promises in the microtask queue, essential for testing async operations.
/**
* Flush all pending promises in the microtask queue
* Ensures all async operations complete before continuing test execution
* @returns Promise that resolves after all pending promises are flushed
*/
function flushPromises(): Promise<void>;Usage Examples:
import { mount, flushPromises } from "@vue/test-utils";
test('async operation handling', async () => {
const wrapper = mount(AsyncComponent);
// Trigger async operation
await wrapper.find('button').trigger('click');
// Wait for all promises to resolve
await flushPromises();
// Now safe to make assertions on async results
expect(wrapper.text()).toContain('Async data loaded');
});
test('API call with delay', async () => {
const wrapper = mount(ApiComponent);
// Component makes API call on mount
await flushPromises();
// API response should now be processed
expect(wrapper.find('.loading').exists()).toBe(false);
expect(wrapper.find('.data').exists()).toBe(true);
});Utilities for automatically unmounting components after tests to prevent memory leaks and test interference.
/**
* Enable automatic unmounting of components after each test
* Integrates with test framework hooks to ensure cleanup
* @param hook - Test framework hook function (e.g., afterEach)
*/
function enableAutoUnmount(hook: (callback: () => void) => void): void;
/**
* Disable automatic unmounting and clear tracked instances
* Useful when you need manual control over component lifecycle
*/
function disableAutoUnmount(): void;Usage Examples:
import { enableAutoUnmount, disableAutoUnmount } from "@vue/test-utils";
// Jest integration
enableAutoUnmount(afterEach);
// Vitest integration
import { afterEach } from 'vitest';
enableAutoUnmount(afterEach);
// Mocha integration
enableAutoUnmount(afterEach);
// Manual control
describe('manual cleanup tests', () => {
beforeAll(() => {
disableAutoUnmount();
});
afterEach(() => {
// Manual cleanup when needed
wrapper?.unmount();
});
});Utility for testing Vue components in server-side rendering contexts.
/**
* Render a Vue component to HTML string for SSR testing
* Uses Vue's server renderer without DOM attachment
* @param component - Vue component to render
* @param options - Mounting options (attachTo not supported)
* @returns Promise resolving to HTML string
*/
function renderToString<T>(
component: T,
options?: SSRMountingOptions<T>
): Promise<string>;
interface SSRMountingOptions<T> {
/** Component props */
props?: ComponentProps<T>;
/** Component slots */
slots?: Record<string, any>;
/** Global configuration */
global?: GlobalMountOptions;
/** Component attributes */
attrs?: Record<string, unknown>;
/** Component data override */
data?(): Record<string, unknown>;
// Note: attachTo is not supported in SSR
}Usage Examples:
import { renderToString } from "@vue/test-utils";
test('SSR rendering', async () => {
const html = await renderToString(MyComponent, {
props: {
title: "SSR Test",
items: ["item1", "item2"]
},
slots: {
default: "Slot content"
}
});
expect(html).toContain("SSR Test");
expect(html).toContain("item1");
expect(html).toContain("Slot content");
expect(html).not.toContain("data-v-"); // No scoped CSS in SSR
});
test('SSR with global config', async () => {
const html = await renderToString(MyComponent, {
global: {
provide: {
theme: 'dark'
},
components: {
'GlobalComponent': StubComponent
}
}
});
expect(html).toContain('theme-dark');
});Utility for creating error wrapper proxies that provide better error messages for failed element queries.
/**
* Create error wrapper proxy for failed find operations
* Provides helpful error messages and supports method chaining
* @param selector - The selector that failed to match
* @returns Proxy that throws on method calls except exists()
*/
function createWrapperError(selector: string): WrapperLike;
interface WrapperLike {
/** Returns false for error wrappers */
exists(): boolean;
/** Throws error for any other method calls */
[key: string]: any;
}Usage Examples:
import { mount } from "@vue/test-utils";
test('error wrapper behavior', () => {
const wrapper = mount(MyComponent);
// This creates an error wrapper since selector doesn't exist
const errorWrapper = wrapper.find('.non-existent');
// exists() returns false without throwing
expect(errorWrapper.exists()).toBe(false);
// Other methods throw helpful errors
expect(() => errorWrapper.text()).toThrow(
'Cannot call text on an empty wrapper'
);
expect(() => errorWrapper.trigger('click')).toThrow(
'Cannot call trigger on an empty wrapper'
);
});
// Practical usage with conditional logic
test('conditional element testing', () => {
const wrapper = mount(MyComponent);
const optionalElement = wrapper.find('.optional-element');
if (optionalElement.exists()) {
expect(optionalElement.text()).toBe('Optional content');
}
});Pre-built stub component for Vue Router's RouterLink to simplify router testing.
/**
* Stub component for Vue Router's RouterLink
* Provides mock router functionality for testing without requiring actual router
* Renders as anchor tag by default, supports custom rendering with custom prop
*/
const RouterLinkStub: Component & {
props: {
/** Router link destination (route path or route object) */
to: string | RouteLocationRaw;
/** Enable custom rendering (renders slot content without wrapper) */
custom?: boolean;
};
/** Mock router link composable values */
setup(): {
/** Mock route object */
route: RouteLocationNormalizedLoaded;
/** Mock href value */
href: string;
/** Mock active state */
isActive: boolean;
/** Mock exact active state */
isExactActive: boolean;
/** Mock navigation function */
navigate: (e?: MouseEvent) => void;
};
};Usage Examples:
import { mount, RouterLinkStub } from "@vue/test-utils";
test('router link interaction', async () => {
const wrapper = mount(MyComponent, {
global: {
stubs: {
'router-link': RouterLinkStub
}
}
});
const routerLink = wrapper.findComponent(RouterLinkStub);
expect(routerLink.props('to')).toBe('/target-route');
// RouterLinkStub provides mock router functionality
await routerLink.trigger('click');
expect(routerLink.emitted('navigate')).toHaveLength(1);
});
// Global stub configuration
import { config, RouterLinkStub } from "@vue/test-utils";
config.global.stubs = {
'router-link': RouterLinkStub
};Common patterns for integrating utilities with different testing frameworks.
import { enableAutoUnmount, flushPromises } from "@vue/test-utils";
// Global setup
enableAutoUnmount(afterEach);
// In tests
beforeEach(async () => {
// Ensure clean state
await flushPromises();
});import { enableAutoUnmount, flushPromises } from "@vue/test-utils";
import { afterEach, beforeEach } from 'vitest';
enableAutoUnmount(afterEach);
beforeEach(async () => {
await flushPromises();
});import { mount, flushPromises } from "@vue/test-utils";
// Custom helper combining mounting and promise flushing
export async function mountAndFlush(component, options = {}) {
const wrapper = mount(component, options);
await flushPromises();
return wrapper;
}
// Custom helper for SSR testing
export async function renderAndTest(component, options = {}) {
const html = await renderToString(component, options);
return {
html,
contains: (text) => html.includes(text),
hasClass: (className) => html.includes(`class="${className}"`),
hasAttribute: (attr, value) => html.includes(`${attr}="${value}"`)
};
}Utility functions handle errors in these scenarios:
import { flushPromises, renderToString } from "@vue/test-utils";
try {
await flushPromises();
} catch (error) {
// Handle any unhandled promise rejections
console.error('Promise flush error:', error);
}
try {
const html = await renderToString(BrokenComponent);
} catch (error) {
console.error('SSR render error:', error.message);
}Install with Tessl CLI
npx tessl i tessl/npm-vue--test-utils