Skip to content

Component Testing ​

20.2.1. mount vs shallowMount ​

ItemmountshallowMount
Child ComponentsActually renderedStubbed
Rendering ScopeEntire component treeCurrent component only
Execution SpeedRelatively slowFast
Usage CriteriaIntegration tests, verifying child interactionsUnit tests, verifying current component logic
  • Use mount by default.
  • Use shallowMount only when child component dependencies are complex.

20.2.2. Props Testing ​

typescript
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import AlertMessage from '../AlertMessage.vue'

describe('AlertMessage', () => {
  it('should render the provided message', () => {
    const wrapper = mount(AlertMessage, {
      props: { message: 'Save completed successfully', type: 'success' },
    })
    expect(wrapper.text()).toContain('Save completed successfully')
    expect(wrapper.classes()).toContain('alert-success')
  })

  it('should correctly apply withDefaults default values', () => {
    const wrapper = mount(AlertMessage, { props: { message: 'Notice' } })
    expect(wrapper.classes()).toContain('alert-info')
  })
})
  • Default values set with withDefaults are verified by omitting the corresponding prop.

20.2.3. Emits Testing ​

typescript
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import ConfirmDialog from '../ConfirmDialog.vue'

describe('ConfirmDialog', () => {
  it('should emit a confirm event when the confirm button is clicked', async () => {
    const wrapper = mount(ConfirmDialog)
    await wrapper.find('[data-testid="btn-confirm"]').trigger('click')
    expect(wrapper.emitted('confirm')).toHaveLength(1)
  })

  it('should pass the event payload correctly', async () => {
    const wrapper = mount(ConfirmDialog, { props: { itemId: 42 } })
    await wrapper.find('[data-testid="btn-confirm"]').trigger('click')
    expect(wrapper.emitted('confirm')![0]).toEqual([42])
  })
})
  • The emitted() return value is an array keyed by event name, where each element is a payload array.

20.2.4. Event Simulation ​

typescript
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import { nextTick } from 'vue'
import SearchInput from '../SearchInput.vue'

describe('SearchInput', () => {
  it('should emit update:modelValue when input value changes', async () => {
    const wrapper = mount(SearchInput)
    await wrapper.find('input').setValue('search term')
    expect(wrapper.emitted('update:modelValue')![0]).toEqual(['search term'])
  })

  it('should update the DOM after asynchronous state changes', async () => {
    const wrapper = mount(SearchInput)
    await wrapper.find('[data-testid="btn-search"]').trigger('click')
    await nextTick()
    expect(wrapper.find('.results').exists()).toBe(true)
  })
})
  • trigger() and setValue() are asynchronous functions and must always be used with await.

20.2.5. Snapshot Testing ​

typescript
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import UserCard from '../UserCard.vue'

describe('UserCard', () => {
  it('should match the rendered result with the snapshot', () => {
    const wrapper = mount(UserCard, {
      props: { name: 'John Doe', role: 'Developer' },
    })
    expect(wrapper.html()).toMatchSnapshot()
  })
})
  • Snapshots are used to detect unintended changes to UI structure.
  • When a snapshot file changes, update it using the vitest -u command.
  • Dynamic data (dates, random values, etc.) must be mocked to exclude them from snapshots.
  • Core logic must be verified through explicit assertions, not snapshots.

TIENIPIA QUALIFIED STANDARD