Vue 3.0/03.SFC와 Vite

[vue 3] 08. VTU를 이용한 vue test

  • -

이번 포스트에서는 VTU를 이용한 vue component test에 대해서 살펴보자.

 

VTU(Vue Test Utils)

 

VTU란?

VTU란 vue test utils의 약자로 vue component를 테스트하기 위한 도구들이다. vitest는 사실 vue와 상관없이 vite라는 환경에서 javascript의 동작을 테스트하기 위한 것이어서 vue를 테스트하기에는 한계가 있기 때문에 VTU가 추가로 필요하다. (vitest가 Junit이라면 VTU는 @ExtendWith(SpringExtension) 정도로 생각하면 쉽겠다)

https://test-utils.vuejs.org/

 

Vue Test Utils

The official testing suite utils for Vue.js 3

test-utils.vuejs.org

vtu는 프로젝트를 생성하면서 Vitest를 선택하면 자동으로 설치된다. 만약 직접 설치해야 한다면 다음의 명령을 이용하자.

npm i @vue/test-utils

 

주요 API

 

mount와 shallowMount

테스트를 위해 가장 먼저 할 일은 Vue Component를 생성하는 일이다. mount()테스트할 대상인 Vue Component에 대한 wrapper인 VueWrapper를 반환해준다. mount를 호출하면서 options 객체를 통해 data, props 등 여러 가지 정보를 전달할 수 있다.

interface MountingOptions<Props, Data = {}> {
  attachTo?: HTMLElement | string
  attrs?: Record<string, unknown>
  data?: () => {} extends Data ? any : Data extends object ? Partial<Data> : any
  props?: (RawProps & Props) | ({} extends Props ? null : never)
  slots?: { [key: string]: Slot } & { default?: Slot }
  global?: GlobalMountOptions
  shallow?: boolean
}

function mount(Component, options?: MountingOptions): VueWrapper

여기서 반환된 Component는 mount와 rendering이 끝난 상태이다.

mount()와 아주 유사하게 shallowMount() 함수로 제공이 된다. 사실 shallowMount()는 mount(component, {shallow:true})와 동일하다.

이 둘의 차이점은 mount()연결된 모든 자식 component까지 다 구성하는 반면 shallowMount()자식 component를 제외한 상태로 wrapper를 생성한다. 사실 단위테스트라는 것이 다른 요소와의 상호 작용 없이 테스트하는 것을 선호하기 때문에 단위테스트라는 개념에는 shallowMount()가 훨씬 적절하다.

option 중 global 속성은 개별 컴포넌트를 위해서 제공되는 내용이 아닌 모든 컴포넌트가 영향을 받을 수 있는 내용들이 작성된다. 예를 들어 props는 개별 컴포넌트에 전달되지만 provide는 모든 컴포넌트에 inject로 참조할 수 있다. 전역 컴포넌트등도 비슷한 개념이다.

type GlobalMountOptions = {
  plugins?: (Plugin | [Plugin, ...any[]])[]
  config?: Partial<Omit<AppConfig, 'isNativeTag'>>
  mixins?: ComponentOptions[]
  mocks?: Record<string, any>
  provide?: Record<any, any>
  components?: Record<string, Component | object>
  directives?: Record<string, Directive>
  stubs?: Stubs = Record<string, boolean | Component> | Array<string>
  renderStubDefaultSlot?: boolean
}

 

요소 검색

component가 로딩되면 다음에 할 일은 화면을 구성하는 element를 조회해서 DOMWarpper로 반환 받아야 한다.  DOMWrapperDOM 객체를 감싸는 객체로 그냥 DOM을 쓰는 것보다는 다양한 기능을 제공한다. 만약 순수한 DOM 객체를 사용하려는 경우 DOMWrapper의 wrapperElement 속성을  사용하면 된다.

함수명 설명
find 하나의 element 찾아서 DOMWrapper 형태로 반환

find(selector: string): DOMWrapper<Element>
find<T extends Node = Node>(selector: string | RefSelector): DOMWrapper<T>;
findAll find와 유사한데 DOMWrapper의 배열을 반환

findAll<T extends Element>(selector: string): DOMWrapper<T>[]
findAll(selector: string): DOMWrapper<Element>[]
get find와 동일한데 만약 대상이 없을 경우 예외 전달

get<T extends Element>(selector: string): Omit<DOMWrapper<T>, 'exists'>
get(selector: string): Omit<DOMWrapper<Element>, 'exists'>

 

내용 조회

다음은 조회된 element의 내용을 확인하기 위한 함수이다. innerHTML, innerText등과 유사한 기능을 갖는다.

함수명 설명
html elementinnerHTML

html(): string
html(options?: { raw?: boolean }): string
text elementinnerText

text(): string
isVisible element가 보이는지 여부

isVisible(): Boolean
exists element의 존재 여부

exists(): boolean

 

기타 조회

element의 내용 외에 속성, class는 물로 다른 컴포넌트와의 통신을 위한 props 나 emited 정보도 조회가 가능하다.

함수명 설명
attributes DOM nodeattribute 목록 또는 특정 attribute 의 값


attributes(): { [key: string]: string }
attributes(key: string): string
attributes(key?: string): { [key: string]: string } | string
classes element에 적용된 class의 목록


classes(): string[]
classes(className: string): boolean
classes(className?: string): string[] | boolean
props 부모 컴포넌트로부터 전달된 props 목록 또는 특정 props의 값


props(): { [key: string]: any }
props(selector: string): any
props(selector?: string): { [key: string]: any } | any
emitted emit 시킨 이벤트들


emitted<T = unknown>(): Record<string, T[]>
emitted<T = unknown>(eventName: string): undefined | T[]
emitted<T = unknown>(eventName?: string): undefined | T[] | Record<string, T[]>

 

다양한 조작

컴포넌트가 가지는 data, props를 설정하거나 input 요소의 value 설정, element에 event triggering 등도 가능하다.

함수명 설명
setData 컴포넌트의 내부 데이터 수정:
 - composition apisetup data 수정할 수 없으며 options에서도 새로운 속성을 추가하지는 못함


setData(data: Record<string, any>): Promise<void>
setProps 컴포넌트의 props 수정:


setProps(props: Record<string, any>): Promise<void>
setValue DOM eleemntvalue 설정:
 - checkbox, radiochecked 속성이나(true/false) selectselected 로 연결됨


setValue(value: unknown, prop?: string): Promise<void>
trigger DOM element에 이벤트 강제 발생


interface TriggerOptions {   code?: String
                             key?: String
                             keyCode?: Number
                             [custom: string]: any }
trigger(eventString: string, options?: TriggerOptions | undefined): Promise<void>

주의할 점은 이 함수들은 모두 Promise를 반환하기 때문에 테스트 콜백 함수를 async로 만든 후 await 하에서 호출해야 한다.

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.