# 컴포넌트 요소 선택

React 컴포넌트를 렌더링 한 후, RTL는 다양한 검색 기능을 제공하여 요소를 가져오는 명령을 실행합니다. 가저온 요소는 어설션(assertion) 테스트에 사용되거나, 사용자와의 인터랙션(interaction) 테스트에 사용됩니다.

## getByText

{% tabs %}
{% tab title="app/App.test.js" %}

```jsx
import { render, screen } from '@testing-library/react'
import App from './App'

describe('App 컴포넌트', () => {
  test('React 앱 렌더링 학습 링크 포함 여부 확인', () => {
    render(<App />)
    
    // screen의 getByText()를 사용해 매칭되는 텍스트 값으로 대상(요소)을 찾을 수 있습니다.
    const linkElement = screen.getByText(/React를 배워보세요/i)
    
    expect(linkElement).toBeInTheDocument()
  })
})
```

{% endtab %}
{% endtabs %}

컴포넌트 랜더링 결과를 유추하기 어려운 경우, [`screen.debug()`](/learning-react-app/tip-and-references/react-testing-library/react-component-test.md#screen-debug)를 사용해 터미널에서 렌더링 결과를 확인합니다.

![](/files/-MVLzFZLIvLWhgElD9-7)

커스텀 매처를 사용해 [**특정 텍스트를 가진 요소가 문서에 있는지 검사**](https://github.com/testing-library/jest-dom#tobeinthedocument) 할 수 있습니다.

```jsx
test('"React 테스팅 라이브러리" 문구를 포함합니다', () => {
  render(<App />);
  
  // 특정 텍스트를 가진 요소가 문서에 포함되어 있는 지 검사합니다.
  expect(screen.getByText('React 테스팅 라이브러리')).toBeInTheDocument()
})
```

문자 값을 **정확히 특정하기 어려운 경우,** [**정규 표현식을 사용해 검사**](https://ko.javascript.info/regular-expressions) 할 수도 있습니다.

```jsx
test('App 컴포넌트 렌더링', () => {
  render(<App />);

  // 테스트 예시: ' 테스트 '

  // 실패
  expect(screen.getByText('테스팅')).toBeInTheDocument()

  // 실패
  expect(screen.getByText(' 테스팅')).toBeInTheDocument()

  // 성공!
  expect(screen.getByText(/\s?테스팅\s?/)).toBeInTheDocument()
})
```

## getByRole

[getByRole()](https://testing-library.com/docs/queries/byrole) 함수는 일반적으로 WAI-ARIA [aria-label](https://developer.mozilla.org/ko/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-label_attribute), [role ](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles)속성을 가진 요소를 검색하는 데 사용됩니다. RTL은 시각적으로 표시되는 텍스트 외에도 접근성 역할(Role)을 통해 대상(요소)를 선택할 수 있습니다. [getByText()](https://testing-library.com/docs/queries/bytext)와 함께 RTL에서 널리 사용되는 검색 함수입니다.

```jsx
test('img 요소를 포함하는 지 검사합니다.', () => {
  render(<App />)

  // 이미지(img) 역할을 가진 요소가 문서에 포함되어 있는 지 검사합니다.
  expect(screen.getByRole('img')).toBeInTheDocument()
})
```

## 다른 검색 함수 <a href="#athor-search-function" id="athor-search-function"></a>

이 외에도 RTL은 요소 별로 검색 가능한 다양한 함수를 제공합니다.

| 검색         | 함수                                                                                   | 예시 코드                                |
| ---------- | ------------------------------------------------------------------------------------ | ------------------------------------ |
| 레이블 텍스트    | [getByLabelText()](https://testing-library.com/docs/queries/bylabeltext)             | \<label htmlFor="검색" />              |
| 플레이스홀더 텍스트 | [getByPlaceholderText()](https://testing-library.com/docs/queries/byplaceholdertext) | \<input placeholder="검색어를 입력하세요." /> |
| 대체 텍스트     | [getByAltText()](https://testing-library.com/docs/queries/byalttext)                 | \<img alt="교통 안내를 하는 포돌이" />         |
| 디스플레이 값    | [getByDisplayValue()](https://testing-library.com/docs/queries/bydisplayvalue)       | \<input value="React 테스팅 라이브러리" />   |

## 변형 검색 함수 <a href="#query-or-find-search-functions" id="query-or-find-search-functions"></a>

`getBy*()` 함수 외에도, 변형 된 `queryBy*()`, `findBy*()` 함수를 사용해 대상(요소)을 찾을 수 있습니다.

#### **queryBy**

* queryByText()
* queryByRole()
* queryByLabelText()
* queryByPlaceholderText()
* queryByAltText()
* queryByDisplayValue()

#### **findBy**

* findByText()
* findByRole()
* findByLabelText()
* findByPlaceholderText()
* findByAltText()
* findByDisplayValue()

### getBy VS queryBy 비교

**getBy**로 존재하지 않는 대상을 검색할 때 다음과 같은 오류가 출력됩니다. 오류 메시지를 살펴보면 검색한 텍스트가 여러 요소로 구분되어 있어 문제가 발생한 오류임을 안내합니다.

![](/files/-MVMAwUYxH8p9EA9zaJC)

{% hint style="danger" %}
TestingLibraryElementError: Unable to find an element with the text: /React 테스팅 라이브러리/. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

/Ract 테스팅 라이브러리/ 텍스트로 요소를 찾을 수 없습니다. 이는 텍스트가 여러 요소에 의해 분할되었기 때문일 수 있습니다. 이 경우 텍스트 매처를 보다 유연하게 만드는 함수를 제공할 수 있습니다.
{% endhint %}

```jsx
test('"React 테스팅 라이브러리" 문구를 포함합니다', () => {
  render(<App />)

  // TestingLibraryElementError 오류 출력 ✔︎
  expect(screen.getByText(/React 테스팅 라이브러리/)).toBeNull()
})
```

이런 경우 `getByText` 대신, `queryByText`를 사용하면 존재하지 않는 대상을 검색해도 오류가 발생하지 않습니다.

```jsx
test('"React 테스팅 라이브러리" 문구를 포함합니다', () => {
  render(<App />)

  // TestingLibraryElementError 오류 출력 ✘
  expect(screen.queryByText(/React 테스팅 라이브러리/)).toBeNull()
})
```

{% hint style="info" %}
[toBeNull()](https://jestjs.io/docs/en/expect#tobenull)은 toBe(null)과 동일하지만, 출력되는 오류 메시지가 좀 더 명확합니다. 무언가가 null 인지 확인하고 싶을 때 사용합니다.
{% endhint %}

### findBy는 언제 사용할까? <a href="#when-using-findby" id="when-using-findby"></a>

`findByText()`는 비동기(async) 처리 과정에 사용합니다. 아례 예를 살펴보면 컴포넌트에서 초기 렌더링 시점이 아닌, 상태 변경에 따른 업데이트 시점에 문서의 대상을 찾아야 할 때 `findByText()` 검색 함수를 사용합니다.

{% tabs %}
{% tab title="UserSearch.test.js" %}

```jsx
// 비동기(async) 콜백 함수
test('UserSearch 테스트', async () => {

  render(<UserSearch />)

  // FAIL 실패! null 반환
  expect(screen.queryByText(/로그인 사용자:/)).toBeInTheDocument()
  
  // 스크린 디버깅 (초기 렌더링 된 UI)
  screen.debug()

  // PASS 통과! await 비동기 처리 후, 업데이트 된 UI에서 대상(요소)를 찾음
  expect(await screen.findByText(/로그인 사용자:/)).toBeInTheDocument();

  // 스크린 디버깅 (업데이트 된 UI)
  screen.debug(); 

})
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="UserSearch.js" %}

```jsx
/**
 * 사용자 정보 가져오기 함수
 */
function getUser() {
  // Promise 객체 반환
  return Promise.resolve({ id: 'pzke1', name: '야무' })
}

/**
 * Search 컴포넌트
 */
function Search({ value, onChange, children }) {
  return (
    <div>
      <label htmlFor="search">{children}</label>
      <input
        id="search"
        type="text"
        value={value}
        onChange={onChange}
      />
    </div>
  )
}

/**
 * UserSearch 컴포넌트
 */
class UserSearch extends React.Component {
  state = {
    search: '',
    user: null,
  }

  loadUser = async () => {
    const user = await getUser();
    this.setState({ user });
  }

  handleChange = (event) => {
    this.setState({
      search: event.target.value,
    })
  }

  componentDidMount() {
    this.loadUser();
  }

  render() {
    const { search, user } = this.state;

    return (
      <div>
        {user ? <p>로그인 사용자: {user.name}</p> : null}

        <Search value={search} onChange={this.handleChange}>검색</Search>

        <p>검색어: {search ? search : '...'}</p>
      </div>
    )
  }
}

export default UserSearch
```

{% endtab %}
{% endtabs %}

## 복수 대상 찾기 <a href="#find-multiple-target" id="find-multiple-target"></a>

앞서 `getBy`, `queryBy`, `findBy` 검색 함수를 살펴봤습니다. 3가지 유형의 함수 모두 단수(1개) 대상을 검색해 찾을 때 사용합니다. 만약 복수(2개 이상)의 대상을 검색해 찾고자 한다면? `getAllBy`, `queryAllBy`, `findAllBy` 검색 함수를 활용합니다. `All`이 들어간 검색 함수는 대상 집합(배열)을 반환합니다.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yamoo9.gitbook.io/learning-react-app/tip-and-references/react-testing-library/get-by-element.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
