@cypress/vue is a Vue.js component testing library that enables browser-based component testing for Vue 3 applications within the Cypress testing framework. It provides a mount utility that allows developers to mount Vue components directly in Cypress tests with full access to Vue's reactive system, component lifecycle, and ecosystem features including Vue Router, Vuex, and i18n.
Note: This package is bundled with the
cypresspackage and should not need to be installed separately. Installing and importingmountfrom@cypress/vueshould only be done for advanced use-cases.
npm install @cypress/vue)import { mount } from "@cypress/vue";For Vue Test Utils access:
import { mount, VueTestUtils } from "@cypress/vue";import { mount } from "@cypress/vue";
import MyComponent from "./MyComponent.vue";
describe("MyComponent", () => {
it("renders correctly", () => {
mount(MyComponent, {
props: { message: "Hello World" }
});
cy.get('[data-testid="message"]').should("contain", "Hello World");
});
});@cypress/vue is built around several key components:
The primary capability for mounting Vue components in Cypress tests with full type safety and Vue ecosystem support.
/**
* Mounts a Vue component and returns a Cypress chainable containing the wrapper and component
* @param componentOptions - Vue component to mount
* @param options - Mounting options including props, global configuration, etc.
* @returns Cypress chainable with wrapper and component access
*/
function mount<T>(
componentOptions: T,
options?: CyMountOptions<any>
): Cypress.Chainable<{
wrapper: VueWrapper<ComponentPublicInstance>;
component: ComponentPublicInstance;
}>;Access to Vue Test Utils functionality with Cypress-specific modifications.
/**
* Vue Test Utils re-exports with mount and shallowMount excluded
* Provides utilities like config, flushPromises, enableAutoUnmount, etc.
*/
const VueTestUtils: {
config: GlobalConfigOptions;
flushPromises(): Promise<void>;
enableAutoUnmount(hook: Function): void;
disableAutoUnmount(): void;
createWrapperError(message: string): Error;
[key: string]: any;
};Access mounted components through Cypress global properties.
/**
* Global Cypress extensions for Vue components
*/
declare global {
namespace Cypress {
interface Cypress {
/** VueWrapper instance for the currently mounted component */
vueWrapper: VueWrapper<ComponentPublicInstance>;
/** Vue component instance (VM) for direct access */
vue: ComponentPublicInstance;
}
}
}Helper function for mounting components in test hooks. Removed as of Cypress 11.0.0.
/**
* @deprecated Removed as of Cypress 11.0.0. Use mount() directly in tests instead.
* Helper function for mounting a component quickly in test hooks.
* @param component - Vue component to mount
* @param options - Mounting options
* @returns Function that throws error when called
*/
function mountCallback(
component: any,
options?: CyMountOptions<any>
): () => void;interface CyMountOptions<Props, Data = {}> {
/** Component props */
props?: Props;
/** Global configuration (plugins, components, etc.) */
global?: {
plugins?: Array<Plugin>;
components?: Record<string, Component>;
directives?: Record<string, Directive>;
mixins?: Array<ComponentOptionsMixin>;
mocks?: Record<string, any>;
provide?: Record<string | symbol, any>;
config?: Partial<AppConfig>;
};
/** Slots for the component */
slots?: Record<string, any>;
/** Attributes to apply to component */
attrs?: Record<string, any>;
/** Data for the component */
data?: () => Data;
/** Whether to log mount in Cypress command log (default: true) */
log?: boolean;
/** @deprecated Use global instead */
extensions?: {
use?: Array<Plugin>;
mixin?: Array<ComponentOptionsMixin>;
plugins?: Array<Plugin>;
mixins?: Array<ComponentOptionsMixin>;
};
}/**
* Vue component wrapper providing testing utilities
*/
interface VueWrapper<T extends ComponentPublicInstance> {
/** Component instance */
vm: T;
/** Set component props */
setProps(props: Record<string, any>): Promise<void>;
/** Set component data */
setData(data: Record<string, any>): Promise<void>;
/** Trigger a DOM event */
trigger(event: string, options?: Record<string, any>): Promise<void>;
/** Find elements by selector */
find(selector: string): DOMWrapper<Element>;
/** Find all elements by selector */
findAll(selector: string): DOMWrapper<Element>[];
/** Get component HTML */
html(): string;
/** Get component text */
text(): string;
/** Check if wrapper exists */
exists(): boolean;
/** Unmount the component */
unmount(): void;
}
/**
* Vue 3 component public instance
*/
interface ComponentPublicInstance {
/** Component props */
$props: Record<string, any>;
/** Component data */
$data: Record<string, any>;
/** Component methods */
[key: string]: any;
/** Emit custom events */
$emit(event: string, ...args: any[]): void;
/** Access parent component */
$parent: ComponentPublicInstance | null;
/** Access root component */
$root: ComponentPublicInstance;
/** Component lifecycle hooks */
$nextTick(fn?: () => void): Promise<void>;
}
/**
* Vue plugin interface
*/
interface Plugin {
install(app: any, ...options: any[]): void;
}
/**
* Vue component type
*/
type Component = any;
/**
* Vue directive interface
*/
interface Directive {
beforeMount?(el: Element, binding: any): void;
mounted?(el: Element, binding: any): void;
beforeUpdate?(el: Element, binding: any): void;
updated?(el: Element, binding: any): void;
beforeUnmount?(el: Element, binding: any): void;
unmounted?(el: Element, binding: any): void;
}
/**
* Vue component options mixin
*/
type ComponentOptionsMixin = Record<string, any>;
/**
* Vue app configuration
*/
interface AppConfig {
errorHandler?: (err: any, vm: any, info: string) => void;
warnHandler?: (msg: string, vm: any, trace: string) => void;
globalProperties?: Record<string, any>;
performance?: boolean;
}
/**
* DOM wrapper for testing utilities
*/
interface DOMWrapper<ElementType extends Element> {
element: ElementType;
text(): string;
html(): string;
exists(): boolean;
trigger(event: string, options?: Record<string, any>): Promise<void>;
setValue(value: any): Promise<void>;
}
/**
* Vue Test Utils global configuration options
*/
interface GlobalConfigOptions {
global?: {
plugins?: Array<Plugin>;
components?: Record<string, Component>;
directives?: Record<string, Directive>;
mixins?: Array<ComponentOptionsMixin>;
};
}import { mount } from "@cypress/vue";
import Counter from "./Counter.vue";
it("increments counter", () => {
mount(Counter, {
props: { initialValue: 5 }
});
cy.get('[data-testid="count"]').should("contain", "5");
cy.get('[data-testid="increment"]').click();
cy.get('[data-testid="count"]').should("contain", "6");
});import { mount } from "@cypress/vue";
import router from "./router";
import store from "./store";
import MyPage from "./MyPage.vue";
it("renders page with router and store", () => {
mount(MyPage, {
global: {
plugins: [router, store],
components: {
CustomButton: ButtonComponent
}
}
});
cy.get('[data-testid="page-title"]').should("be.visible");
});import { mount } from "@cypress/vue";
import FormComponent from "./FormComponent.vue";
it("validates form programmatically", () => {
mount(FormComponent);
// Access component through global Cypress object
cy.then(() => {
Cypress.vue.validateForm();
expect(Cypress.vue.isValid).to.be.false;
});
});import { mount } from "@cypress/vue";
import AsyncComponent from "./AsyncComponent.vue";
it("handles async operations", () => {
mount(AsyncComponent);
cy.get('[data-testid="load-button"]').click();
// Use Vue Test Utils for async handling
cy.then(async () => {
await Cypress.vueWrapper.vm.$nextTick();
// Component state updated
});
});import { mount } from "@cypress/vue";
import { h } from "vue";
it("mounts functional component", () => {
mount(() => h("div", { "data-testid": "functional" }, "Hello"));
cy.get('[data-testid="functional"]').should("contain", "Hello");
});import { mount } from "@cypress/vue";
import CardComponent from "./CardComponent.vue";
it("renders component with slots", () => {
mount(CardComponent, {
slots: {
header: '<h2 data-testid="header">Card Title</h2>',
default: '<p data-testid="content">Card content</p>',
footer: '<button data-testid="action">Action</button>'
}
});
cy.get('[data-testid="header"]').should("contain", "Card Title");
cy.get('[data-testid="content"]').should("contain", "Card content");
cy.get('[data-testid="action"]').should("be.visible");
});import { mount } from "@cypress/vue";
import ChildComponent from "./ChildComponent.vue";
it("provides context to component", () => {
mount(ChildComponent, {
global: {
provide: {
theme: "dark",
api: mockApiService
}
}
});
cy.get('[data-testid="themed-element"]').should("have.class", "dark-theme");
});@cypress/vue includes built-in error handling for common issues:
Common error scenarios:
// This will throw a helpful error
cy.mount(MyComponent).find('.selector'); // Wrong - can't chain VTU methods
// Correct approach
cy.mount(MyComponent).then(({ wrapper }) => {
wrapper.find('.selector');
});For users migrating from older versions:
mountCallback function is deprecated as of Cypress 11.0.0extensions option is deprecated in favor of global