# Jest DOM 테스트

![](https://597303073-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MUfqhMWK9ILIx0SXJTa%2F-MVMES49gLlR_PcxgS7-%2F-MVMEmdIKskQcbcPmPBV%2Fimage.png?alt=media\&token=b5cb5350-c08f-48ef-a201-43f5a39d0d2e)

## Jest DOM <a href="#jest-test" id="jest-test"></a>

RTL은 [jest-dom](https://testing-library.com/docs/ecosystem-jest-dom) 라이브러리의 [사용법](https://github.com/testing-library/jest-dom#usage)에 따라 매처(matchers)를 추가해 테스트를 수행합니다. 테스트 스위트(Suite)는 여러 테스트 케이스(Case)를 포함할 수 있지만, **케이스가 반드시 스위트 안에 포함되어야 하는 것은 아닙니다.**

```javascript
describe('테스트 스위트(Suite)', () => {
  test('테스트 케이스(Case)', () => {
    // 테스트 내용
  })
})
```

아래 코드는 테스트 스위트 안에 테스트 케이스를 포함하는 간단한 예입니다.

```javascript
// SUITE
describe('진실은 진실하고, 거짓은 거짓이다.', () => {
  
  // CASE 1
  test('진실은 진실하다.', () => {
    expect(true).toBe(true);
  })
 
  // CASE 2
  test('거짓은 거짓이다.', () => {
    expect(false).toBe(false);
  })

})
```

## 테스트 시나리오 <a href="#test-scenario" id="test-scenario"></a>

만들어야 할 로직을 테스트 하는 파일을 먼저 만듭니다.

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

```javascript
import shoppingList from './shoppingList'

test('쇼핑리스트 기본 품목 중에는 `맥주`가 포함되어 있다.', () => {
  expect(shoppingList()).toContain('맥주')
})
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
[.toContain()](https://jestjs.io/docs/en/expect#tocontainitem) 메서드는 배열 아이템 포함 여부를 검사할 때 사용합니다.
{% endhint %}

테스트 결과는 `FAIL`이 나올겁니다. 아직 로직을 짜기 전이기 때문이죠.

{% tabs %}
{% tab title="테스트 명령 실행" %}

```bash
npm test

[FAIL]  shoppingList.test.js
✕ 쇼핑리스트 기본 품목 중에는 `맥주`가 포함되어 있다. (2 ms)

● 쇼핑리스트 기본 품목 중에는 `맥주`가 포함되어 있다.

    expect(received).toContain(expected) // indexOf

    Expected value: "맥주"
    Received array: []
```

{% endtab %}
{% endtabs %}

테스트 결과가 `PASS`가 되도록 코드 로직을 작성합니다.

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

```javascript
const shoppingList = (...items) => [...items, '맥주']
```

{% endtab %}
{% endtabs %}

테스트 결과 `PASS` 되면 성공입니다. 테스트를 통해 "기대" 값과 "실제" 값이 같음을 입증했고, 신뢰할 수 있습니다.

{% tabs %}
{% tab title="테스트 명령 실행" %}

```bash
npm test

[PASS]  shoppingList.test.js
 ✓ 쇼핑리스트 기본 품목 중에는 `맥주`가 포함되어 있다. (1 ms)
```

{% endtab %}
{% endtabs %}

## 테스팅 파일 이름 규칙 <a href="#testing-file-name-rules" id="testing-file-name-rules"></a>

Jest는 다음의 이름 규칙으로 테스트 파일을 찾아 테스팅을 수행합니다.

* `__tests__` 폴더 안의 `.js` 접미사가 있는 파일
* `.test.js` 접미사가 있는 파일
* `.spec.js` 접미사가 있는 파일

{% hint style="info" %}

#### 테스트 파일 위치

테스트 할 함수와 동일한 위치에 테스트 파일을 포함하는 것이 좋습니다. 테스트 할 파일에서 테스팅 할 파일을 불러오는 경로가 단순해져 관리가 쉽기 때문입니다.

```python
src/utils/
 └── shoppingList/
     ├── shoppingList.js
     └── shoppingList.test.js
```

{% code title="shoppingList.test.js" %}

```jsx
// 같은 위치에 있는 함수를 불러오는 경로가 복잡하지 않습니다.
import shoppingList from './shoppingList'
```

{% endcode %}
{% endhint %}

## 어설션(Assertion) 함수

[toBeNull()](https://jestjs.io/docs/en/expect#tobenull), [toBeInTheDocument()](#tobeinthedocument)와 같은 어설션 함수를 말합니다. 각 어설션 함수(커스텀 매처)에 대한 상세한 사용법은 [Custom Matchers ](https://github.com/testing-library/jest-dom#custom-matchers)문서를 참고하세요.

### toBeDisabled()

비할성(disabled) 요소인지 여부를 검사합니다.&#x20;

```jsx
<button data-testid="button" type="submit" disabled>전송</button>
<fieldset disabled><input type="text" data-testid="input" /></fieldset>
<a href="..." disabled>링크</a>
```

```jsx
expect(getByTestId('button')).toBeDisabled() // true

expect(getByTestId('input')).toBeDisabled() // false

expect(getByText('링크')).not.toBeDisabled() // false
```

### toBeEnabled()

`not.toBeDisabled()`와 동일합니다.

```javascript
expect(getByText('링크')).toBeEnabled()
```

### toBeEmpty()

요소가 포함하는 자식 노드를 포함하지 않는 지 여부를 검사합니다.

```jsx
<span data-testid="not-empty">
  <span data-testid="empty"></span>
</span>
```

```jsx
expect(getByTestId('empty')).toBeEmpty() // true
expect(getByTestId('not-empty')).not.toBeEmpty() // true
```

### toBeEmptyDOMElement()

요소에 표시되는 콘텐츠가 없는 지 여부를 검사합니다. 주석은 무시하지만, 요소에 공백이 있으면 실패합니다.

```jsx
<span data-testid="not-empty"><span data-testid="empty"></span></span>
<span data-testid="with-whitespace"> </span>
<span data-testid="with-comment"><!-- comment --></span>
```

```jsx
expect(getByTestId('empty')).toBeEmptyDOMElement() // true
expect(getByTestId('not-empty')).not.toBeEmptyDOMElement() // true
expect(getByTestId('with-whitespace')).not.toBeEmptyDOMElement() // true
expect(getByTestId('with-comment')).toBeEmptyDOMElement() // true
```

### toBeInTheDocument()

문서에 요소가 포함되어 있는 지 여부를 검사합니다.

```jsx
<span data-testid="html-element">
  <span>Html Element</span>
</span>
<svg data-testid="svg-element"></svg>
```

```jsx
expect(
  getByTestId(document.documentElement, 'html-element')
).toBeInTheDocument() // true

expect(
  getByTestId(document.documentElement, 'svg-element')
).toBeInTheDocument() // true

expect(
  queryByTestId(document.documentElement, 'does-not-exist')
).not.toBeInTheDocument() // true
```

### toBeInvalid()

요소가 유효한 지 여부를 검사합니다. 값이 없는[`aria-invalid` 속성](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-invalid_attribute)을 가지고 있거나 `"true"` 값이 설정된 경우,  [checkValidity()](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation) 결과 값이 `false`인 경우 요소가 유효하지 않은 것으로 판단합니다.

```jsx
<input data-testid="no-aria-invalid" />
<input data-testid="aria-invalid" aria-invalid />
<input data-testid="aria-invalid-value" aria-invalid="true" />
<input data-testid="aria-invalid-false" aria-invalid="false" />

<form data-testid="valid-form">
  <input />
</form>

<form data-testid="invalid-form">
  <input required />
</form>
```

```jsx
expect(getByTestId('no-aria-invalid')).not.toBeInvalid() // true
expect(getByTestId('aria-invalid')).toBeInvalid() // true
expect(getByTestId('aria-invalid-value')).toBeInvalid() // true
expect(getByTestId('aria-invalid-false')).toBeInvalid() // false

expect(getByTestId('valid-form')).not.toBeInvalid()
expect(getByTestId('invalid-form')).toBeInvalid()
```

### toBeRequired()

폼 요소가 필수 입력을 요구하는 지 여부를 검사합니다. `required` 또는 `aria-required="true"` 속성을 가진 경우 검사를 통과합니다.

```jsx
<input data-testid="required-input" required />
<input data-testid="aria-required-input" aria-required="true" />
<input data-testid="conflicted-input" required aria-required="false" />
<input data-testid="aria-not-required-input" aria-required="false" />
<input data-testid="optional-input" />
<input data-testid="unsupported-type" type="image" required />
<select data-testid="select" required></select>
<textarea data-testid="textarea" required></textarea>
<div data-testid="supported-role" role="tree" required></div>
<div data-testid="supported-role-aria" role="tree" aria-required="true"></div>
```

```jsx
expect(getByTestId('required-input')).toBeRequired()
expect(getByTestId('aria-required-input')).toBeRequired()
expect(getByTestId('conflicted-input')).toBeRequired()
expect(getByTestId('aria-not-required-input')).not.toBeRequired()
expect(getByTestId('optional-input')).not.toBeRequired()
expect(getByTestId('unsupported-type')).not.toBeRequired()
expect(getByTestId('select')).toBeRequired()
expect(getByTestId('textarea')).toBeRequired()
expect(getByTestId('supported-role')).not.toBeRequired()
expect(getByTestId('supported-role-aria')).toBeRequired()
```

### toBeValid()

요소가 유효한 지 여부를 검사합니다. 값이 없는[`aria-invalid` 속성](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-invalid_attribute)을 가지고 있지 않거나 `"false"` 값이 설정된 경우,  [checkValidity()](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation) 결과 값이 `true`인 경우 요소가 유효한 것으로 판단합니다.

```jsx
<input data-testid="no-aria-invalid" />
<input data-testid="aria-invalid" aria-invalid />
<input data-testid="aria-invalid-value" aria-invalid="true" />
<input data-testid="aria-invalid-false" aria-invalid="false" />

<form data-testid="valid-form">
  <input />
</form>

<form data-testid="invalid-form">
  <input required />
</form>
```

```jsx
expect(getByTestId('no-aria-invalid')).toBeValid()
expect(getByTestId('aria-invalid')).not.toBeValid()
expect(getByTestId('aria-invalid-value')).not.toBeValid()
expect(getByTestId('aria-invalid-false')).toBeValid()

expect(getByTestId('valid-form')).toBeValid()
expect(getByTestId('invalid-form')).not.toBeValid()
```

### toBeVisible()

요소가 사용자에게 보이는 지 여부를 검사합니다. 다음 요건에 모두 충족하면 검사를 통과합니다.

* 요소가 문서에 포함되어 있습니다.
* 요소의 `display` 스타일 속성 값이 `none`이 아닙니다.
* 요소의 `visibility` 스타일 속성 값이 `hidden` 또는 `collapse`가 아닙니다.
* 요소의 `opacity` 스타일 속성 값이 `0` 보다 큽니다.
* 요소에 [hidden](https://developer.mozilla.org/ko/docs/Web/HTML/Global_attributes/hidden) 속성이 설정되지 않았습니다.
* 요소를 포함하는 상위 요소가 문서에 포함되고, 보여야 합니다.
* \<details /> 요소의 `open` 속성이 설정되어 있습니다.

```jsx
<div data-testid="zero-opacity" style="opacity: 0">Zero Opacity Example</div>
<div data-testid="visibility-hidden" style="visibility: hidden">
  Visibility Hidden Example
</div>
<div data-testid="display-none" style="display: none">Display None Example</div>
<div style="opacity: 0">
  <span data-testid="hidden-parent">Hidden Parent Example</span>
</div>
<div data-testid="visible">Visible Example</div>
<div data-testid="hidden-attribute" hidden>Hidden Attribute Example</div>
```

```jsx
expect(getByText('Zero Opacity Example')).not.toBeVisible()
expect(getByText('Visibility Hidden Example')).not.toBeVisible()
expect(getByText('Display None Example')).not.toBeVisible()
expect(getByText('Hidden Parent Example')).not.toBeVisible()
expect(getByText('Visible Example')).toBeVisible()
expect(getByText('Hidden Attribute Example')).not.toBeVisible()
```

### toContainElement()

요소가 다른 요소를 포함하는 지 여부를 검사합니다.

```jsx
<span data-testid="ancestor">
  <span data-testid="descendant"></span>
</span>
```

```jsx
const ancestor = getByTestId('ancestor')
const descendant = getByTestId('descendant')
const nonExistantElement = getByTestId('does-not-exist')

expect(ancestor).toContainElement(descendant)
expect(descendant).not.toContainElement(ancestor)
expect(ancestor).not.toContainElement(nonExistantElement)
```

### toContainHTML()

요소가 HTML 요소를 표현하는 문자열을 포함하는 지 여부를 검사합니다.

```jsx
<span data-testid="parent">
  <span data-testid="child"></span>
</span>
```

```jsx
expect(getByTestId('parent')).toContainHTML('<span data-testid="child"></span>')
```

{% hint style="warning" %}

#### 아마도 이 매치를 사용할 필요가 없을 것입니다.

사용자가 브라우저에서 앱을 인식하는 관점에서 테스트를 권장합니다. 그러므로 특정 DOM 구조에 대한 테스트는 수행하지 않는 것이 좋습니다. 사용자가 제어하는 DOM 구조를 확인하는 데 사용해서는 안 됩니다. 대신 [toContainElement()](#tocontainelement)를 사용하세요.

테스트 중인 코드가 외부 소스에서 가져온 HTML을 렌더링하고 해당 HTML 코드가 의도한 대로 사용되었는지 확인하는 경우에 유용할 수 있습니다.
{% endhint %}

### toHaveAttribute()

요소가 특정 속성을 포함하는 지 여부를 검사합니다. [expect.stringContaining](https://jestjs.io/docs/expect#expectstringcontainingstring) 또는 [expect.stringMatching](https://jestjs.io/docs/expect#expectstringmatchingstring--regexp)을 사용해 속성에 특정 기대 값 또는 부분 일치가 있는지 선택적으로 확인할 수 있습니다.

```jsx
<button data-testid="ok-button" type="submit" disabled>ok</button>
```

```jsx
const button = getByTestId('ok-button')

expect(button).toHaveAttribute('disabled')
expect(button).toHaveAttribute('type', 'submit')
expect(button).not.toHaveAttribute('type', 'button')

expect(button).toHaveAttribute('type', expect.stringContaining('sub'))
expect(button).toHaveAttribute('type', expect.not.stringContaining('but'))
```

### toHaveClass()

요소가 특정 `class` 이름을 가지고 있는 지 여부를 검사합니다. (정확한 검사가 필요한 경우 `{exact: true}` 설정)

```jsx
<button data-testid="delete-button" class="btn extra btn-danger">
  Delete item
</button>
<button data-testid="no-classes">No Classes</button>
```

```jsx
const deleteButton = getByTestId('delete-button')
const noClasses = getByTestId('no-classes')

expect(deleteButton).toHaveClass('extra')
expect(deleteButton).toHaveClass('btn-danger btn')
expect(deleteButton).toHaveClass('btn-danger', 'btn')
expect(deleteButton).not.toHaveClass('btn-link')

expect(deleteButton).toHaveClass('btn-danger extra btn', {exact: true}) // 요소에 클래스 집합이 정확히 있는지 확인합니다.
expect(deleteButton).not.toHaveClass('btn-danger extra', {exact: true}) // 예상(expect)보다 많은 경우 실패합니다.

expect(noClasses).not.toHaveClass()
```

### toHaveFocus()

요소에 현재 포커스(초점) 이동이 되어 있는 지 여부를 검사합니다.

```jsx
<div><input type="text" data-testid="element-to-focus" /></div>
```

```jsx
const input = getByTestId('element-to-focus')

input.focus()
expect(input).toHaveFocus()

input.blur()
expect(input).not.toHaveFocus()
```

### toHaveFormValues()

폼에 `name` 속성이 지정된 폼 컨트롤을 포함하고 있고, 지정된 값을 가지고 있는 지 여부를 검사합니다.

```jsx
<form data-testid="login-form">
  <input type="text" name="username" value="jane.doe" />
  <input type="password" name="password" value="12345678" />
  <input type="checkbox" name="rememberMe" checked />
  <button type="submit">Sign in</button>
</form>
```

```jsx
expect(getByTestId('login-form')).toHaveFormValues({
  username: 'jane.doe',
  rememberMe: true,
})
```

{% hint style="info" %}
자세한 사용법은 공식 문서에서 안내하는 [toHaveFormValue()](https://github.com/testing-library/jest-dom#tohaveformvalues)를 참고하세요.
{% endhint %}

### toHaveStyle()

요소에 특정 값이 적용 된 특정 CSS 속성이 있는 지 여부를 검사합니다. 요소 중 일부가 아닌, 모든 예상 속성이 적용되는 경우에만 일치합니다.

```jsx
<button
  data-testid="delete-button"
  style="display: none; background-color: red"
>
  Delete item
</button>
```

```jsx
const button = getByTestId('delete-button')

expect(button).toHaveStyle('display: none')
expect(button).toHaveStyle({display: 'none'})
expect(button).toHaveStyle(`
  background-color: red;
  display: none;
`)
expect(button).toHaveStyle({
  backgroundColor: 'red',
  display: 'none',
})
expect(button).not.toHaveStyle(`
  background-color: blue;
  display: none;
`)
expect(button).not.toHaveStyle({
  backgroundColor: 'blue',
  display: 'none',
})
```

{% hint style="info" %}

#### 계산 된 CSS 스타일 결과 값 반영

문서에서 현재 사용 중인 스타일시트에 정의 된 일부 규칙이 클래스 이름을 통해 요소에 적용되는 규칙에서도 작동합니다. 일반적인 CSS 우선 순위 규칙이 적용됩니다.
{% endhint %}

### toHaveTextContent()

요소에 텍스트 내용이 포함되어 있는 지 여부를 검사합니다. 문자열 인자가 전달되면 요소 내용에 대해 부분 대/소문자를 구분하는 매치가 수행됩니다. 대/소문자를 구분하지 않는 매치를 수행하려면 정규 표현 식을 사용합니다.

```jsx
<span data-testid="text-content">Text Content</span>
```

```jsx
const element = getByTestId('text-content')

expect(element).toHaveTextContent('Content')
expect(element).toHaveTextContent(/^Text Content$/) // 전체 내용 매칭
expect(element).toHaveTextContent(/content$/i) // 대/소문자 구분 없이 매칭
expect(element).not.toHaveTextContent('content')
```

### toHaveValue()

폼 컨트롤 요소에 지정 된 값이 있는지 여부를 검사합니다.

```jsx
<input type="text" value="text" data-testid="input-text" />
<input type="number" value="5" data-testid="input-number" />
<input type="text" data-testid="input-empty" />
<select multiple data-testid="select-number">
  <option value="first">First Value</option>
  <option value="second" selected>Second Value</option>
  <option value="third" selected>Third Value</option>
</select>
```

```jsx
const textInput = getByTestId('input-text')
const numberInput = getByTestId('input-number')
const emptyInput = getByTestId('input-empty')
const selectInput = getByTestId('select-number')

expect(textInput).toHaveValue('text')
expect(numberInput).toHaveValue(5)
expect(emptyInput).not.toHaveValue()
expect(selectInput).not.toHaveValue(['second', 'third'])
```

### toHaveDisplayValue()

폼 컨트롤 요소에 지정 된 표시 값(사용자에게 보여지는 값)을 포함하는 지 여부를 검사합니다.

```markup
<label for="input-example">First name</label>
<input type="text" id="input-example" value="Luca" />

<label for="textarea-example">Description</label>
<textarea id="textarea-example">An example description here.</textarea>

<label for="single-select-example">Fruit</label>
<select id="single-select-example">
  <option value="">Select a fruit...</option>
  <option value="banana">Banana</option>
  <option value="ananas">Ananas</option>
  <option value="avocado">Avocado</option>
</select>

<label for="multiple-select-example">Fruits</label>
<select id="multiple-select-example" multiple>
  <option value="">Select a fruit...</option>
  <option value="banana" selected>Banana</option>
  <option value="ananas">Ananas</option>
  <option value="avocado" selected>Avocado</option>
</select>
```

```jsx
const input = screen.getByLabelText('First name')
const textarea = screen.getByLabelText('Description')
const selectSingle = screen.getByLabelText('Fruit')
const selectMultiple = screen.getByLabelText('Fruits')

expect(input).toHaveDisplayValue('Luca')
expect(input).toHaveDisplayValue(/Luc/)
expect(textarea).toHaveDisplayValue('An example description here.')
expect(textarea).toHaveDisplayValue(/example/)
expect(selectSingle).toHaveDisplayValue('Select a fruit...')
expect(selectSingle).toHaveDisplayValue(/Select/)
expect(selectMultiple).toHaveDisplayValue([/Avocado/, 'Banana'])
```

### toBeChecked()

폼 컨트롤(radio, checkbox) 요소가 체크된 상태인 지 여부를 검사합니다.

```markup
<input type="checkbox" checked data-testid="input-checkbox-checked" />
<input type="checkbox" data-testid="input-checkbox-unchecked" />
<div role="checkbox" aria-checked="true" data-testid="aria-checkbox-checked" />
<div
  role="checkbox"
  aria-checked="false"
  data-testid="aria-checkbox-unchecked"
/>

<input type="radio" checked value="foo" data-testid="input-radio-checked" />
<input type="radio" value="foo" data-testid="input-radio-unchecked" />
<div role="radio" aria-checked="true" data-testid="aria-radio-checked" />
<div role="radio" aria-checked="false" data-testid="aria-radio-unchecked" />
<div role="switch" aria-checked="true" data-testid="aria-switch-checked" />
<div role="switch" aria-checked="false" data-testid="aria-switch-unchecked" />
```

```jsx
const inputCheckboxChecked = getByTestId('input-checkbox-checked')
const inputCheckboxUnchecked = getByTestId('input-checkbox-unchecked')
const ariaCheckboxChecked = getByTestId('aria-checkbox-checked')
const ariaCheckboxUnchecked = getByTestId('aria-checkbox-unchecked')
expect(inputCheckboxChecked).toBeChecked()
expect(inputCheckboxUnchecked).not.toBeChecked()
expect(ariaCheckboxChecked).toBeChecked()
expect(ariaCheckboxUnchecked).not.toBeChecked()

const inputRadioChecked = getByTestId('input-radio-checked')
const inputRadioUnchecked = getByTestId('input-radio-unchecked')
const ariaRadioChecked = getByTestId('aria-radio-checked')
const ariaRadioUnchecked = getByTestId('aria-radio-unchecked')
expect(inputRadioChecked).toBeChecked()
expect(inputRadioUnchecked).not.toBeChecked()
expect(ariaRadioChecked).toBeChecked()
expect(ariaRadioUnchecked).not.toBeChecked()

const ariaSwitchChecked = getByTestId('aria-switch-checked')
const ariaSwitchUnchecked = getByTestId('aria-switch-unchecked')
expect(ariaSwitchChecked).toBeChecked()
expect(ariaSwitchUnchecked).not.toBeChecked()
```

### toBePartiallyChecked()

폼 컨트롤(checkbox) 요소가 부분적으로 체크되었는 지 여부를 검사합니다.

```markup
<input type="checkbox" aria-checked="mixed" data-testid="aria-checkbox-mixed" />
<input type="checkbox" checked data-testid="input-checkbox-checked" />
<input type="checkbox" data-testid="input-checkbox-unchecked" />
<div role="checkbox" aria-checked="true" data-testid="aria-checkbox-checked" />
<div
  role="checkbox"
  aria-checked="false"
  data-testid="aria-checkbox-unchecked"
/>
<input type="checkbox" data-testid="input-checkbox-indeterminate" />
```

```jsx
const ariaCheckboxMixed = getByTestId('aria-checkbox-mixed')
const inputCheckboxChecked = getByTestId('input-checkbox-checked')
const inputCheckboxUnchecked = getByTestId('input-checkbox-unchecked')
const ariaCheckboxChecked = getByTestId('aria-checkbox-checked')
const ariaCheckboxUnchecked = getByTestId('aria-checkbox-unchecked')
const inputCheckboxIndeterminate = getByTestId('input-checkbox-indeterminate')

expect(ariaCheckboxMixed).toBePartiallyChecked()
expect(inputCheckboxChecked).not.toBePartiallyChecked()
expect(inputCheckboxUnchecked).not.toBePartiallyChecked()
expect(ariaCheckboxChecked).not.toBePartiallyChecked()
expect(ariaCheckboxUnchecked).not.toBePartiallyChecked()

inputCheckboxIndeterminate.indeterminate = true
expect(inputCheckboxIndeterminate).toBePartiallyChecked()
```

### toHaveDescription()

요소에 설명이 있는 지 여부를 검사합니다. [aria-describedby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-describedby_attribute) 속성에 연결된 요소가 설명 내용을 포함합니다.

```markup
<button aria-label="Close" aria-describedby="description-close">X</button>

<!-- 설명 -->
<div id="description-close">Closing will discard any changes</div>

<button>Delete</button>
```

```jsx
const closeButton = getByRole('button', {name: 'Close'})

expect(closeButton).toHaveDescription('Closing will discard any changes')
expect(closeButton).toHaveDescription(/will discard/) // 일부 매칭
expect(closeButton).toHaveDescription(expect.stringContaining('will discard')) // 일부 매칭
expect(closeButton).toHaveDescription(/^closing/i) // 대/소문자 구분 없이 매칭
expect(closeButton).not.toHaveDescription('Other description')

const deleteButton = getByRole('button', {name: 'Delete'})
expect(deleteButton).not.toHaveDescription()
expect(deleteButton).toHaveDescription('') // 설명이 없거나, 비어 있으면 항상 빈 문자열
```
