Component Testing

mount() and Query the DOM

Component Testing

@vue/test-utils gives you mount() and a wrapper API for finding elements, triggering events, and asserting against the rendered output.

4 min read Level 2/5 #vue#testing#components
What you'll learn
  • Install @vue/test-utils
  • Mount a component with props and slots
  • Find elements and simulate user events

For component-level tests, @vue/test-utils mounts a single component into a virtual DOM and exposes a Wrapper for assertions. Pair it with Vitest.

Install

npm i -D @vue/test-utils

You need jsdom (or happy-dom) in your Vitest config — see the previous lesson.

Mount

mount returns a wrapper with .text(), .html(), .find(), .trigger(), and more.

<!-- Greeting.vue -->
<script setup lang="ts">
const props = defineProps<{ name: string }>()
</script>

<template>
  <p>Hello {{ props.name }}!</p>
</template>
// Greeting.test.ts
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import Greeting from './Greeting.vue'

describe('Greeting', () => {
  it('renders the name', () => {
    const w = mount(Greeting, { props: { name: 'Ada' } })
    expect(w.text()).toContain('Hello Ada!')
  })
})

Events

trigger fires a DOM event and returns a promise — await to let the DOM update.

it('emits save when clicked', async () => {
  const w = mount(SaveButton)
  await w.find('button').trigger('click')
  expect(w.emitted('save')).toHaveLength(1)
})

Slots

mount(Modal, {
  slots: {
    default: '<p>Body content</p>',
    footer: '<button>OK</button>',
  },
})

Stubs

Replace a heavy child component with a stub:

mount(Parent, {
  global: { stubs: { ChildChart: true } },
})

Cypress / Playwright Component Mode

For visual or interaction-heavy components, Cypress and Playwright both ship component test runners that mount Vue components in a real browser.

End-to-End Testing →