React Testing Library로 테스트할 요소를 선택하는 방법

Testing Library를 사용해 React 컴포넌트를 테스트할 때, 렌더링된 요소를 잘 선택해 오기 위한 팁을 소개합니다.

2024-02-17에 씀
프론트엔드 테스트 가이드 시리즈의 다른 글
  1. jest로 비동기 함수 테스트하기
  2. Storybook Interaction Test를 활용한 바텀시트 시각적 테스트
  3. React Testing Library로 테스트할 요소를 선택하는 방법
  4. 프론트엔드 TDD 튜토리얼 with React & Testing Library

웹 프론트엔드 테스트 코드를 작성할 때, 컴포넌트를 렌더링한 후에 필요한 요소를 어떻게 선택해와야 할지 고민해 보신 적이 있으신가요?

Testing Library는 웹 페이지와 사용자가 상호 작용하는 방식과 최대한 유사한 테스트를 작성하는 것을 원칙으로 하고 있습니다. 요소를 선택할 때도 사용자가 웹 페이지와 상호 작용하는 방식과 유사한 방식을 택할수록 신뢰할 수 있는 테스트를 작성할 수 있습니다.

이 글에서는 Testing Library를 활용해 테스트를 작성할 때 렌더링 된 요소를 잘 선택하는 방법을 소개합니다.

어떤 요소를 기준으로 검색할까?

요소를 찾기 위해서는 어떤 요소부터 검색을 시작할지 정해야 합니다. render 함수가 반환하는 view 객체를 기준으로 쿼리할 수도 있지만, Testing Library에서 제공하는 screen 객체를 기준으로 쿼리를 수행하는 것이 좋습니다. 요소가 body 밖에 렌더링되는 것이 아니라면, screen 객체를 사용하세요.

Screen 객체

Testing Library에서는 document.body를 감싸서 확장한 screen 객체를 제공하고 있습니다. screen 객체를 활용하면 document.body에서 사용할 수 있는 모든 쿼리를 사용할 수 있습니다.

1import { screen } from "@tesiting-library/react";

render 호출 시 반환되는 container 객체로 요소를 선택하는 것과 screen을 사용해 요소를 선택했을 때의 결과는 똑같습니다. 그럼에도 screen을 사용하는 것이 권장되는 이유는, render를 발생시키는 방식과 요소를 선택하는 방식을 분리할 수 있기 때문입니다.

render와 요소의 선택이 분리되면, 테스트 코드 내에서 render를 발생시키는 부분이 변경되어도 요소를 선택하는 부분은 영향을 받지 않게 해서 테스트 코드의 변경을 최소화할 수 있습니다.

render의 역할

Testing Library는 render를 수행할 때 렌더링할 컴포넌트를 div 요소로 한 번 감싸 주는데, 이 div 요소를 container라고 부릅니다. render 함수를 호출했을 때 반환되는 객체의 container 프로퍼티가 이 container 요소입니다.

Testing Library에서 제공하는 render 함수를 사용해 특정 React Element를 렌더링하면, DOM 트리는 아래와 같이 구성됩니다.

1body
2ㄴ div (container)
3 ㄴ render의 인자로 넘어온 Element

render는 호출될 때마다 body 하위에 렌더링할 요소를 추가해서 렌더링합니다. 그래서 render를 여러번 호출하면 아래 캡처와 같이 body 하위에 여러개의 container div 요소가 존재할 수 있습니다.

1render(<HashtagList hashtagList={hashtags} maxHastagCount={3} />);
2render(<HashtagList hashtagList={hashtags} maxHastagCount={3} />);
3render(<HashtagList hashtagList={hashtags} maxHastagCount={3} />);
4
5screen.debug();

만약 특정 container에 렌더링된 요소를 교체하고 싶다면, render가 반환하는 객체의 rerender 메서드를 호출하면 됩니다.

1const view = render(<HashtagList hashtagList={hashtags} maxHastagCount={3} />);
2view.rerender(<HashtagList hashtagList={hashtags} maxHastagCount={4} />);
3view.rerender(<HashtagList hashtagList={hashtags} maxHastagCount={5} />);

screen.debug()

테스트를 하다 보면, 렌더링 후에 어떤 DOM 구조를 가지고 있는지 확인하고 싶을 때가 있습니다. 그럴 때는 screen.debug() 를 호출해 주면 해당 시점에 렌더링된 DOM을 테스트 결과에 출력해 줍니다. 아래 캡처는 컴포넌트 렌더링 후 screen.debug()를 호출했을 때의 테스트 결과 화면의 일부입니다.

어떤 함수를 사용할까?

Testing Library에서는 크게 세 종류의 쿼리 API를 제공합니다. 각 쿼리 API는 아래와 같은 특징이 있습니다.

구분getBy…queryBy…findBy…
요소 발견 시 반환값찾은 Element찾은 Element 찾은 Element를 resolve하는 Promise
해당되는 요소가 없다면에러 발생null 반환Promise를 reject
권장되는 사용법일반적인 경우

요소가 존재하지 않는 것을 확인하고 싶은 경우

waitFor를 사용해서 요소를 찾고 싶은 경우
재시도가 필요한 경우

일반적인 경우에는 getBy… 를 사용하면 됩니다.

만약 어떤 요소가 DOM 상에 존재하지 않는다는 것을 확인해야 한다면, queryBy…를 아래와 같은 방식으로 사용할 수 있습니다.

1expect(screen.queryByText("텍스트")).not.toBeInTheDocument();

findBy…는 timeout으로 설정된 시간동안 요소를 찾으려고 시도합니다. findBy…를 호출하면 시간 안에 요소를 찾으면 해당 요소를 resolve하고, 찾지 못했다면 reject하는 Promise를 반환합니다. timeout 시간은 기본적으로 1000ms로 설정되어 있습니다. 컴포넌트 렌더링 후 바로 렌더링되지 않을 수도 있는 요소를 찾아야 한다findBy…를 사용하세요.

요소의 어떤 속성으로 찾을까?

이제 요소가 가진 속성을 활용해 스크린 안에서 요소를 찾아야 합니다. 이때 가장 권장되는 방법은 접근성이나 시맨틱과 관련된 속성을 활용하는 것입니다.

  1. 접근성 - 유저가 시각적으로 볼 수 있거나 스크린 리더를 통해 접근할 수 있는 방식으로 선택하기
    1. getByRole - accessibility tree 상의 모든 요소에 사용 가능. role attribute를 주거나, 해당 태그의 role을 사용하기
    2. getByLabelText - form 필드에서 주로 사용
    3. getByPlaceholderText
    4. getByText - 상호작용이 없는 요소를 찾는 데 사용 가능
    5. getByDisplayValue
  2. 시맨틱 - HTML5, ARIA 속성 사용하기
    1. getByAltText
    2. getByTitle
  3. Test ID
    1. getByTestId - 사용자가 볼 수 없는 값이므로, 최후의 수단으로 사용

이런 속성을 활용해서 요소를 선택하기 위해서 마크업 시 웹 표준을 준수하는 것이 좋습니다. 적절한 ARIA 속성과 시맨틱 태그를 활용해 마크업하면 좋은 사용자 경험을 제공할 수 있을 뿐만 아니라 테스트 작성에도 큰 도움이 됩니다.

접근성이나 시맨틱과 관련된 속성을 주기 어려운 요소를 선택해야 한다면, data-testid 속성을 활용할 수 있습니다. 이 속성이 있는 요소는 getByTestId 메서드로 요소를 선택할 수 있습니다. 하지만 data-testid 속성은 사용자가 상호작용을 하기 위해 사용되는 값은 아니기 때문에, data-testid를 사용하는 것은 최후의 수단으로 남겨두는 게 좋습니다.

참고자료

프론트엔드 테스트 가이드 시리즈의 다른 글
  1. jest로 비동기 함수 테스트하기
  2. Storybook Interaction Test를 활용한 바텀시트 시각적 테스트
  3. React Testing Library로 테스트할 요소를 선택하는 방법
  4. 프론트엔드 TDD 튜토리얼 with React & Testing Library
프로필 사진

조예진

이전 포스트
유데미(Udemy) 기술블로그로 알아보는 테크니컬 라이팅 수강 후기
다음 포스트
프론트엔드 TDD 튜토리얼 with React & Testing Library