Testing Vue Components with Vue Test Utils
You updated the cart component, but in production there's an error: the item count doesn't recalculate. Without unit tests, you learn about bugs from users, and finding the cause takes hours. Vue Test Utils — the official library for testing Vue 3 components — solves this: isolated mounting, event simulation, reactivity checks without running the full app. We, the TrueTech team, set up the complete testing cycle turnkey: from stack selection to CI pipeline. We guarantee coverage of key scenarios and team training, relying on 5+ years of experience with the Vue ecosystem and over 50 implemented projects.
Contact us to assess your current coverage and choose a testing strategy.
Why Automate Testing of Vue Components?
Manually checking every component before release is slow and unreliable. Unit tests automate verification: rendering, emits, state, edge cases. According to the official Vue Test Utils documentation, the library is designed for isolated component testing. Vue Test Utils combined with Vitest runs 5 times faster than the Cypress Component Test Runner for simple scenarios — no browser needed. Tests run locally and in CI, providing fast feedback to developers. Regression testing speeds up by 80%, and bug search time is reduced by 30% — confirmed by our project experience. In one project, we cut regression run time from 3 hours to 30 minutes (6x improvement).
How to Set Up Vue 3 Testing with Vue Test Utils?
Step-by-Step Setup Instructions
-
Install dependencies:
npm install -D @vue/test-utils vitest jsdom. - Create vitest.config.ts with the suggested configuration:
import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; export default defineConfig({ plugins: [vue()], test: { environment: 'jsdom', globals: true, }, }); - Write your first test. Example checking rendering and emit:
import { mount } from '@vue/test-utils'; import UserCard from './UserCard.vue'; describe('UserCard', () => { it('renders user name', () => { const wrapper = mount(UserCard, { props: { user: { name: 'Ivan Petrov', email: '[email protected]' } }, }); expect(wrapper.text()).toContain('Ivan Petrov'); }); it('emits delete event with user id', async () => { const wrapper = mount(UserCard, { props: { user: { id: 42, name: 'Ivan' } }, }); await wrapper.find('[data-testid="delete-btn"]').trigger('click'); expect(wrapper.emitted('delete')).toBeTruthy(); expect(wrapper.emitted('delete')![0]).toEqual([42]); }); }); - Run tests:
npx vitest.
What Scenarios Do Unit Tests Cover?
Testing store interaction. If a component depends on Pinia, initialize the store before each test:
import { setActivePinia, createPinia } from 'pinia'; import { useCartStore } from '@/stores/cart'; describe('CartButton', () => { beforeEach(() => setActivePinia(createPinia())); it('adds item to cart', async () => { const wrapper = mount(CartButton, { props: { productId: 1 }, global: { plugins: [createPinia()] }, }); const store = useCartStore(); await wrapper.find('button').trigger('click'); expect(store.items).toHaveLength(1); }); }); Asynchronous data loading. Use vi.mock() and flushPromises() to mock API:
it('loads data after API call', async () => { vi.mock('@/api', () => ({ fetchUser: vi.fn().mockResolvedValue({ name: 'Maria' }), })); const wrapper = mount(UserProfile, { props: { userId: 1 } }); expect(wrapper.find('[data-testid="loading"]').exists()).toBe(true); await flushPromises(); expect(wrapper.text()).toContain('Maria'); }); Slots and stubs. Verify slot rendering and isolate child components using shallowMount:
it('renders default slot', () => { const wrapper = mount(Card, { slots: { default: '<p data-testid="slotted">Content</p>' }, }); expect(wrapper.find('[data-testid="slotted"]').exists()).toBe(true); }); it('uses shallowMount to stub children', () => { const wrapper = shallowMount(ParentComponent); // child components are auto-stubbed }); Composables are tested without mounting — just call the function and check the result. For example, a form validation hook: pass fields, call validate(), verify errors.
How to Avoid Common Mistakes When Writing Tests?
- Don't forget to reset Pinia state in
beforeEach:setActivePinia(createPinia()). Otherwise tests will affect each other. - For async operations, always use
flushPromises()after mocking, otherwise the test may finish before execution. - Use
data-testidattributes for element selection — they are more stable than CSS classes or text. - When testing slots, remember to pass content via
slots: { default: '...' }.
Environment Setup Checklist
- @vue/test-utils, vitest, jsdom installed
- vitest config includes jsdom and globals
- At least one test written to verify the setup
- Tests run locally with
npx vitest - Tests integrated into CI (e.g., GitHub Actions)
Turnkey Testing Setup: What's Included
- Analysis of the current project and stack selection (Vitest + Vue Test Utils or Jest).
- Virtual environment setup (jsdom) and vitest configuration.
- Writing tests for 20–30 key components: mounting, events, state, async operations.
- Creating mocks for APIs and stores.
- CI integration (GitLab CI / GitHub Actions / Bitbucket Pipelines).
- Documentation for writing new tests and coverage metrics.
- Team training: a 2-hour workshop on unit test writing.
Comparison of Vue Component Testing Methods
| Method | Speed | Isolation | UI Check | Resources |
|---|---|---|---|---|
| Unit (Vue Test Utils) | High | Full | Logical | Low |
| Component (Cypress) | Medium | Partial | Visual | High |
| E2E (Playwright) | Low | None | Full | Very High |
Turnkey Testing Setup Stages
| Stage | Duration | Result |
|---|---|---|
| Analysis and stack selection | 1 day | Testing plan |
| Environment setup | 1 day | Working vitest + jsdom |
| Writing tests (20–30 components) | 2–4 days | Test suite with coverage |
| CI integration | 1 day | Auto-run on push |
| Documentation and training | 1 day | Guide and workshop |
Timeline
Environment setup, writing tests, and CI integration for a typical Vue project take from 4 to 7 days. The exact estimate depends on component complexity and legacy code volume.
Get a consultation on testing your Vue project — we'll assess current coverage, help choose a strategy, and set up a fast pipeline. 5+ years of Vue experience, dozens of complex projects. We guarantee quality and process transparency. Contact us to discuss the details.







