Header 컴포넌트

해당 컴포넌트에서 테스트 대상으로 삼을 것은 isMatch method이다.

fullPath는 쿼리와 해시를 포함한 전체 URL을 이야기한다. 이 때 path가 regExp로 되어 있기 때문에 test 메서드를 사용할 수 있다.

isMatch 메서드는 RouterLink로 네비게이션 바를 만들 때, 만약 현재 경로($route.fullPath)가 /movie를 포함하고 있는지 여부를 boolean 값으로 리턴하는 메서드이며, 이 메서드를 사용하여 현재 path가 만약 /movie라면 nav에 active라는 클래스를 바인딩해준다.

<div
  v-for="nav in navigations"
>
  <RouterLink
    :to="nav.href"
    active-class="active"
    :class="{ active: isMatch(nav.path) }"
    class="nav-link">
    {{ nav.name }}
  </RouterLink>
	...
</div>

...
data() {
  return {
    navigations: [
      {
        name: 'Search',
        href: '/'
      },
      {
        name: 'Movie',
        href: '/movie/tt4520988',
        path: /^\\/movie/
      },
      {
        name: 'About',
        href: '/about'
      }
    ]
  }
},
methods: {
  isMatch(path) {
    if (!path) return false
    return path.test(this.$route.fullPath)
  }
}

직접 사용하는 플러그인만 테스트에 포함하자

main.js를 살펴보면 해당 뷰 앱에서 사용하는 플러그인들이 적혀져 있다. 여기서는 store, router, loadImage 세 개의 플러그인이 있다. 이 때, 우리가 보고 싶어하는 Header 컴포넌트는 store와 router만을 사용하지 loadImage를 사용하지는 않는다. 따라서 사용하지 않는 LoadImage 플러그인은 테스트 코드에 넣지 않는다.

// main.js

import { createApp } from 'vue'
import App from './App'
import store from './store'  // Same as './store/index.js'
import router from './routes' // Same as './routes/index.js'
import loadImage from './plugins/loadImage'

createApp(App)
  .use(store)
  .use(router)
  .use(loadImage)
  .mount('#app')

shallowMount를 사용하여 테스트 환경에 컴포넌트를 올리는 과정에서 global에서 사용되는 플러그인들을 등록할 수 있게 된다. 여기서 loadImage 플러그인을 넣지 않는다.

// tests/components/Header.test.js

  test('if there is no path regexp, no match', () => {
		const wrapper = shallowMount(Header, {
	    global: {
	      plugins: [
	        router,
	        store
	      ]
	    }
	  })

    const regExp = undefined
    expect(wrapper.vm.isMatch(regExp)).toBe(false)
  })

테스트가 한 번만 일어난다면 상관없겠지만, 만약 여러 번 반복된다면? 그 때마다 테스트 코드에 wrapper 객체를 shallowMount하는 코드를 일일이 작성해주는 것은 비효율적이다. wrapper 객체를 각 테스트별로 써 주지 않고 바깥에서 마치 글로벌처럼 사용할 수 있지 않을까?

describe('components/Header.vue test', () => {
  const wrapper = shallowMount(Header, {
    global: {
      plugins: [
        router,
        store
      ]
    }
  })

  test('if there is no path regexp, no match', () => {
    const regExp = undefined
    expect(wrapper.vm.isMatch(regExp)).toBe(false)
  })

  test('path regexp should be matched', () => {

  })
})

하지만, 만약 이전 테스트에서 wrapper 객체에 영향을 주어 바뀐 후에 다음 테스트에서 사용되는 경우, 뒤 테스트는 오염된 wrapper 객체를 가지고 테스트를 진행하게 되는 경우가 생긴다.

늘 주의해야 하는 것은 각 테스트가 고유한 환경에서 작동되어야 한다는 것이다.

따라서 이 때 beforeEach를 사용하여 매 테스트 실행 전 컴포넌트를 마운트하는 코드를 작성하는 것이 가장 간결하고 안전하게 코드를 작성하는 방식이다.