Skip to content

컴포넌트 테스트

20.2.1. mount vs shallowMount

항목mountshallowMount
자식 컴포넌트실제 렌더링스텁 처리
렌더링 범위전체 컴포넌트 트리현재 컴포넌트만
실행 속도상대적으로 느림빠름
사용 기준통합 테스트, 자식 상호작용 검증단위 테스트, 현재 컴포넌트 로직 검증
  • 기본적으로 mount를 사용합니다.
  • 자식 컴포넌트의 의존성이 복잡한 경우에만 shallowMount를 사용합니다.

20.2.2. Props 테스트

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

describe('AlertMessage', () => {
  it('전달된 메시지를 렌더링해야 합니다', () => {
    const wrapper = mount(AlertMessage, {
      props: { message: '저장이 완료되었습니다', type: 'success' },
    })
    expect(wrapper.text()).toContain('저장이 완료되었습니다')
    expect(wrapper.classes()).toContain('alert-success')
  })

  it('withDefaults 기본값이 올바르게 적용되어야 합니다', () => {
    const wrapper = mount(AlertMessage, { props: { message: '알림' } })
    expect(wrapper.classes()).toContain('alert-info')
  })
})
  • withDefaults로 설정한 기본값은 해당 prop을 생략한 상태에서 검증합니다.

20.2.3. Emits 테스트

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

describe('ConfirmDialog', () => {
  it('확인 버튼 클릭 시 confirm 이벤트를 발생시켜야 합니다', async () => {
    const wrapper = mount(ConfirmDialog)
    await wrapper.find('[data-testid="btn-confirm"]').trigger('click')
    expect(wrapper.emitted('confirm')).toHaveLength(1)
  })

  it('이벤트 페이로드를 올바르게 전달해야 합니다', async () => {
    const wrapper = mount(ConfirmDialog, { props: { itemId: 42 } })
    await wrapper.find('[data-testid="btn-confirm"]').trigger('click')
    expect(wrapper.emitted('confirm')![0]).toEqual([42])
  })
})
  • emitted() 반환값은 이벤트명을 키로 하는 배열이며, 각 요소는 페이로드 배열입니다.

20.2.4. 이벤트 시뮬레이션

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('입력값 변경 시 update:modelValue를 발생시켜야 합니다', async () => {
    const wrapper = mount(SearchInput)
    await wrapper.find('input').setValue('검색어')
    expect(wrapper.emitted('update:modelValue')![0]).toEqual(['검색어'])
  })

  it('비동기 상태 변경 후 DOM이 갱신되어야 합니다', async () => {
    const wrapper = mount(SearchInput)
    await wrapper.find('[data-testid="btn-search"]').trigger('click')
    await nextTick()
    expect(wrapper.find('.results').exists()).toBe(true)
  })
})
  • trigger()setValue()는 비동기 함수이므로 반드시 await를 사용합니다.

20.2.5. 스냅샷 테스트

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

describe('UserCard', () => {
  it('렌더링 결과가 스냅샷과 일치해야 합니다', () => {
    const wrapper = mount(UserCard, {
      props: { name: '홍길동', role: '개발자' },
    })
    expect(wrapper.html()).toMatchSnapshot()
  })
})
  • 스냅샷은 UI 구조의 의도치 않은 변경을 감지하는 용도로 사용합니다.
  • 스냅샷 파일이 변경된 경우 vitest -u 명령으로 업데이트합니다.
  • 동적 데이터(날짜, 랜덤 값 등)는 목 처리하여 스냅샷에 포함하지 않습니다.
  • 핵심 로직은 스냅샷이 아닌 명시적 단언(assertion)으로 검증합니다.

TIENIPIA QUALIFIED STANDARD