티스토리 뷰

근본없는 개발자가 무작정 개발하고 테스트하려니

매번 별것도 아닌 곳에서 막힌다.

 

아래와 같은 코드가 있다고 하자.

Vue.component('example', {
  template: '<button @click="onButtonClick" :disabled="!value">{{ value }}</button>',
  data () {
    return {
      value: false
    }
  },
  methods: {
    onButtonClick () {
      this.$router.push('home')
    }
  }
})

버튼을 클릭하면 $router.push 가 호출되는 간단한 예제이다.

단, 버튼에는 disabled 속성이 value 라는 변수와 바인딩 되어있다.

만약 value에 true 를 주게되면 당연히 버튼은 활성화 될 것이다.

 

그렇다면 아래와 같은 테스트코드를 짤 수 있다. (mount 부분은 생략하겠다.)

wrapper.setData({
  value: true
})
wrapper.find('button').trigger('click')
expect(wrapper.vm.$router.push).toHaveBeenCalled() // 실패...

value를 true로 해줬으니 버튼은 활성화가 되었을테고,

click을 trigger 해줬으니 메소드가 잘 실행됐겠거니 했지만... fail 이다...

 

뭔 개같은 경우인가 싶었고 추가적인 삽질을 해본 결과... 근본없는 개발자는 충격을 받게된다.

...

Vue의 화면 갱신은 비동기라는 점이었다.

 

왜 비동기인가...?

Vue는 불필요한 화면 갱신을 방지하기 위해

동일한 이벤트 루프 내에서 발생하는 모든 데이터 변경을 버퍼에 담는다.

그리고 다음 tick 에서 해당 버퍼를 비우면서 중복을 제거한 최종 연산을 수행하며 화면을 렌더링한다.

결론은 컴포넌트가 재렌더링 될 때 한 tick 을 소요한다는 것이다.

 

위의 예제에서 내가 setData로 value의 값을 바꾼 것은 맞지만,

즉시 재렌더링을 하지는 않았기 때문에 버튼의 disabled는 변경되지 않는다는 것이다.

데이터 변경에 의한 렌더의 수행을 기다려줘야했던 것이다.

 

해당 테스트 코드는 아래와같이 수정되면 정상동작한다.

await wrapper.setData({
  value: true
})
wrapper.find('button').trigger('click')
expect(wrapper.vm.$router.push).toHaveBeenCalled() // 성공

혹은 이렇게 해도 된다.

wrapper.setData({
  value: true
})
await wrapper.vm.$nextTick()
wrapper.find('button').trigger('click')
expect(wrapper.vm.$router.push).toHaveBeenCalled() // 성공

 

나와같이 근본없이 Vue를 개발하고 있을 누군가에게 도움이 되길 바라며...

이만...

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함