Vue 3 테스트

테스트 주의 사항

컴포저블을 모킹할 때 ref 관리

Vue 3 컴포저블을 테스트할 때 일반적인 패턴은 이러한 파일에서 반환하는 ref 또는 computed 값을 모킹하는 것입니다.

다음과 같은 데모 컴포저블을 고려하십시오:

export const useCounter = () => {
  const counter = ref(1)
  const increase = () => { counter.value += 1 }

  return { counter, increase }
}

현재 이 컴포저블을 사용하고 카운터를 노출하는 컴포넌트가 있다면, 기능을 다루기 위한 테스트를 작성하고 싶을 것입니다. 이러한 간단한 예제와 같은 경우에는 컴포저블을 전혀 모킹하지 않고도 테스트할 수 있지만, Tanstack Query 래퍼나 Apollo 래퍼와 같은 더 복잡한 기능의 경우 jest.mock을 사용하는 것이 필요할 수 있습니다.

이러한 경우에는 테스트 파일에서 컴포저블을 모킹해야 합니다:

<script setup>
const { counter, increase } = useCounter()
</script>

<template>
  <p>매우 유용한 카운터: {{ counter }}</p>
  <button @click="increase">+</button>
</template>
import { ref } from 'vue'
import { useCounter } from '~/composables/useCounter'

jest.mock('~/composables/useCounter')

describe('MyComponent', () => {
  const increaseMock = jest.fn()
  const counter = ref(1)

  beforeEach(() => {
    useCounter.mockReturnValue({
      increase: increaseMock,
      counter
    })
  })

  describe('카운터가 2일 때', () => {
    beforeEach(() => {
      counter.value = 2
      createComponent()
    })

    it('...', () => {})
  })

  it('기본값은 1이어야 한다', () => {
    createComponent()

    expect(findSuperUsefulCounter().text()).toBe(1)
    // 실패
  })
})

위의 예제에서 볼 수 있듯이, 우리는 컴포저블에서 반환된 함수의 모킹과 counter ref를 모두 생성하고 있습니다 - 그러나 예제에서 매우 중요한 단계가 누락되어 있습니다.

counter 상수는 ref입니다. 즉, 매 테스트마다 이를 수정할 때 할당하는 값이 유지됩니다. 예제의 두 번째 it 블록은 counter가 이전 테스트에서 할당된 값을 유지하기 때문에 실패할 것입니다.

해결책이자 모범 사례는 가장 상위 수준의 beforeEach 블록에서 항상 ref를 재설정하는 것입니다.

import { ref } from 'vue'
import { useCounter } from '~/composables/useCounter'

jest.mock('~/composables/useCounter')

describe('MyComponent', () => {
  const increaseMock = jest.fn()

  // 추가로 조심하기 위해 `undefined`로 초기화할 수 있습니다
  const counter = ref(undefined)

  beforeEach(() => {
    counter.value = 1
    useCounter.mockReturnValue({
      increase: increaseMock,
      counter
    })
  })

  describe('카운터가 2일 때', () => {
    beforeEach(() => {
      counter.value = 2
      createComponent()
    })

    it('...', () => {})
  })

  it('기본값은 1이어야 한다', () => {
    createComponent()

    expect(findSuperUsefulCounter().text()).toBe(1)
    // 통과
  })
})