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