IT/기초 지식

[Jest] 프론트엔드 테스트에서 비동기 처리 다루기

개발자 두더지 2023. 3. 23. 21:19
728x90

일본의 한 블로그 글을 번역한 포스트입니다. 오역 및 의역, 직역이 있을 수 있으며 틀린 내용은 지적해주시면 감사하겠습니다.

 

왜 비동기 처리를 의식해야하는가?


 예를 들면 아래와 같은 케이스가 있다고 가정해보자.

// 화면에 Hello World를 표시한다.

expect(wrapper.text()).toMatch('Hello World')

 Hello World가 표시되는 것을 테스트하고자한다. 그러나 가정으로 //화면에 Hello World를 표시한다. 부분이 비동기 처리가 된 경우(여기서는 편의를 위해서 주석으로 처리를 설명하고 있지만 그러한 처리를 하는 코드가 작성되어 있다고 가정), Hello World가 표시되기전에 expect(wrapper.text()).toMatch('Hello World') 를 검증해버리고 만다.  즉, Hello World는 아직 표시되지 않았으나 테스트했으므로 테스트는 실패해버리고 마는 것이다.

 

 

어떨 때 비동기 처리가 될까?


 그럼 어떨 때 비동기 처리가 되는 것일까? API가 호출되는 처리가 비동기가 된 경우를 생각해보면 비교적 이미지를 떠올리기 쉬울 것이다. 그 외에도 처리가 비동기로 된 경우가 있지만, 여기서는 세 가지를 픽업해봤다.

 

trigger

 클릭 이벤트등 어떠한 이벤트를 발생시키고 싶을 때 사용한다.

wrapper.find('button').trigger('click')

 

setProps

 mount 혹은 shallowMount한 후에 props를 갱신하고 싶을 때ㅇ ㅔ사용한다.

wrapper.setProps({ hoge: 'hoge' })

 

setValue

 v-model과 연결되어 있는 input 요소의 값을 입력하고 싶을 때에 사용한다.

wrapper.find('[data-test="hoge"').setValue('test')

 

 

비동기처리를 진행시킬 방법에 대해서 검토하기


 방금 설펴본 세 가지 패턴 모두 Promise를 반환하므로 async/await를 사용하면 반영된 후의 상태에서 테스트하게 된다. 그러나, 여러 개의 비동기 처리가 겹쳐져 있는 경우 (등록 버튼을 누른 후, 등록용 API가 호출되는 등)는 이제 설명할 방법으로 명시적으로 비동기 처리를 진행시킬 필요가 있다.

 

nextTick

 nextTick은 비동기 처리를 1개만 실행시킬 수 있는 방법이다. 그러므로 비동기 처리가 2개 겹쳐져있는 경우는 nextTick도 두 번 쓸 필요가 있다.

import { nextTick } from 'vue';

test('○○가 될 것', async () => {
  // 어떠한 비동기처리

  // 비동기처리 1개 실행
  await nextTick()

  ...
});

 

flushPromises

flushPromises는 비동기처리를 모두 실행시킬 수 있다. 그러므로 여러 개의 비동기처리가 겹쳐져있는 경우에도 flushPromises는 하나만 쓰면 된다.

 그러나 flush-promies를 별도로 설치할 필요가 있다.

import { nextTick } from 'vue';

test('○○가 될 것', async () => {
  // 어떠한 비동기처리

  // 비동기처리 모두 실행
  await flushPromises()

  ...
});

 

nextTick과 flushPromises중 어떤 것을 사용하면 좋을까?

 개인적으로는 nexTick을 주로 사용한다. flushPromises를 별로 쓰지 않는 이유는 비동기 처리가 의도치 못 하게 증가했을 경우 눈치채지 못할 가능성이 있기 때문이다. 

 공식 문서를 살펴보면 다음과 같이 기재되어 있다.

  • Use await nextTick() to ensure the DOM has updated before the test continues
  • Functions that might update the DOM (like trigger and setValue) return nextTick, so you need await them.
  • Use flush-promises from Vue Test Utils to resolve any unresolved promises from non-Vue dependencies (such as API requests).

 이 내용에 따르면 DOM을 갱신하는 경우는 nextTick으로, Vue이외의 의존 관계(API를 호출하는 등) 의 경우 flushPromises를 추천하는듯 하다. 


참고자료

https://qiita.com/_kt15_/items/69186f5a314f39eac202

728x90