Testing Vue Components
Set up unit tests for Vue components with Vitest and Vue Test Utils, and end-to-end tests with Playwright or Cypress.
Levels of Testing
Unit Tests
Test one component or composable in isolation — fast and focused.
Integration Tests
Test how several components work together, like a form and its parent.
End-to-End Tests
Drive a real browser through your app exactly as a user would.
Setting Up Vitest
Vitest is Vite's companion test runner, and can be selected automatically during project scaffolding.
npm install --save-dev vitest @vue/test-utils jsdomMounting a Component with Vue Test Utils
Vue Test Utils' mount() function renders a component in an isolated test environment, giving you a wrapper object to inspect and interact with.
// Counter.test.jsimport { mount } from '@vue/test-utils';import Counter from './Counter.vue';
test('renders the initial count', () => { const wrapper = mount(Counter, { props: { initialValue: 5 } }); expect(wrapper.text()).toContain('5');});Simulating User Interaction
test('increments the count when clicked', async () => { const wrapper = mount(Counter); await wrapper.find('button').trigger('click'); expect(wrapper.text()).toContain('1');});Vue batches DOM updates, so the DOM doesn't reflect a state change instantly — await wrapper.find(...).trigger('click') (or nextTick()) before asserting on the resulting output.
Testing Pinia Stores
Since a Pinia store is essentially a plain composable, you can test its actions and getters directly, or provide a test-specific Pinia instance for components that use one.
import { createPinia, setActivePinia } from 'pinia';import { useCartStore } from '../stores/cart';
beforeEach(() => { setActivePinia(createPinia());});
test('addItem adds an item to the cart', () => { const cart = useCartStore(); cart.addItem({ id: 1, name: 'Mouse', price: 25 }); expect(cart.items).toHaveLength(1);});End-to-End Testing
Playwright or Cypress drive a real browser against your running app, verifying full flows — navigation, form submission — the way an actual visitor would experience them.
import { test, expect } from '@playwright/test';
test('user can add an item to the cart', async ({ page }) => { await page.goto('/shop'); await page.click('text=Add to Cart'); await expect(page.getByText('1 item in cart')).toBeVisible();});FAQs
For most real projects, yes — unit tests catch logic bugs cheaply, while end-to-end tests catch integration issues that only surface in a real browser.
Yes — pass a test router instance (or a stub) via the global.plugins mounting option to provide the routing context a component expects.
Summary
Vitest and Vue Test Utils cover unit and integration testing, with Playwright or Cypress rounding out full end-to-end coverage. Next, you'll look at performance optimization techniques specific to Vue.