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.







