Jest DOM
RTL은 jest-dom 라이브러리의 사용법 에 따라 매처(matchers)를 추가해 테스트를 수행합니다. 테스트 스위트(Suite)는 여러 테스트 케이스(Case)를 포함할 수 있지만, 케이스가 반드시 스위트 안에 포함되어야 하는 것은 아닙니다.
Copy describe ( '테스트 스위트(Suite)' , () => {
test ( '테스트 케이스(Case)' , () => {
// 테스트 내용
})
})
아래 코드는 테스트 스위트 안에 테스트 케이스를 포함하는 간단한 예입니다.
Copy // SUITE
describe ( '진실은 진실하고, 거짓은 거짓이다.' , () => {
// CASE 1
test ( '진실은 진실하다.' , () => {
expect ( true ) .toBe ( true );
})
// CASE 2
test ( '거짓은 거짓이다.' , () => {
expect ( false ) .toBe ( false );
})
})
테스트 시나리오
만들어야 할 로직을 테스트 하는 파일을 먼저 만듭니다.
테스트 결과는 FAIL
이 나올겁니다. 아직 로직을 짜기 전이기 때문이죠.
테스트 명령 실행
Copy npm test
[FAIL] shoppingList.test.js
✕ 쇼핑리스트 기본 품목 중에는 ` 맥주 ` 가 포함되어 있다. (2 ms )
● 쇼핑리스트 기본 품목 중에는 ` 맥주 ` 가 포함되어 있다.
expect(received ).toContain( expected ) // indexOf
Expected value: "맥주"
Received array: []
테스트 결과가 PASS
가 되도록 코드 로직을 작성합니다.
테스트 결과 PASS
되면 성공입니다. 테스트를 통해 "기대" 값과 "실제" 값이 같음을 입증했고, 신뢰할 수 있습니다.
테스트 명령 실행
Copy npm test
[PASS] shoppingList.test.js
✓ 쇼핑리스트 기본 품목 중에는 ` 맥주 ` 가 포함되어 있다. (1 ms )
테스팅 파일 이름 규칙
Jest는 다음의 이름 규칙으로 테스트 파일을 찾아 테스팅을 수행합니다.
__tests__
폴더 안의 .js
접미사가 있는 파일
테스트 파일 위치
테스트 할 함수와 동일한 위치에 테스트 파일을 포함하는 것이 좋습니다. 테스트 할 파일에서 테스팅 할 파일을 불러오는 경로가 단순해져 관리가 쉽기 때문입니다.
Copy src / utils /
└── shoppingList /
├── shoppingList . js
└── shoppingList . test . js
Copy // 같은 위치에 있는 함수를 불러오는 경로가 복잡하지 않습니다.
import shoppingList from './shoppingList'
어설션(Assertion) 함수
toBeNull() , toBeInTheDocument() 와 같은 어설션 함수를 말합니다. 각 어설션 함수(커스텀 매처)에 대한 상세한 사용법은 Custom Matchers 문서를 참고하세요.
toBeDisabled()
비할성(disabled) 요소인지 여부를 검사합니다.
Copy < button data-testid = "button" type = "submit" disabled >전송</ button >
< fieldset disabled >< input type = "text" data-testid = "input" /></ fieldset >
< a href = "..." disabled >링크</ a >
Copy expect ( getByTestId ( 'button' )) .toBeDisabled () // true
expect ( getByTestId ( 'input' )) .toBeDisabled () // false
expect ( getByText ( '링크' )). not .toBeDisabled () // false
toBeEnabled()
not.toBeDisabled()
와 동일합니다.
Copy expect ( getByText ( '링크' )) .toBeEnabled ()
toBeEmpty()
요소가 포함하는 자식 노드를 포함하지 않는 지 여부를 검사합니다.
Copy < span data-testid = "not-empty" >
< span data-testid = "empty" ></ span >
</ span >
Copy expect ( getByTestId ( 'empty' )) .toBeEmpty () // true
expect ( getByTestId ( 'not-empty' )). not .toBeEmpty () // true
toBeEmptyDOMElement()
요소에 표시되는 콘텐츠가 없는 지 여부를 검사합니다. 주석은 무시하지만, 요소에 공백이 있으면 실패합니다.
Copy < span data-testid = "not-empty" >< span data-testid = "empty" ></ span ></ span >
< span data-testid = "with-whitespace" > </ span >
< span data-testid = "with-comment" ><!-- comment --></ span >
Copy 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()
문서에 요소가 포함되어 있는 지 여부를 검사합니다.
Copy < span data-testid = "html-element" >
< span >Html Element</ span >
</ span >
< svg data-testid = "svg-element" ></ svg >
Copy 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
속성 을 가지고 있거나 "true"
값이 설정된 경우, checkValidity() 결과 값이 false
인 경우 요소가 유효하지 않은 것으로 판단합니다.
Copy < 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 >
Copy 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"
속성을 가진 경우 검사를 통과합니다.
Copy < 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 >
Copy 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
속성 을 가지고 있지 않거나 "false"
값이 설정된 경우, checkValidity() 결과 값이 true
인 경우 요소가 유효한 것으로 판단합니다.
Copy < 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 >
Copy 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
보다 큽니다.
요소를 포함하는 상위 요소가 문서에 포함되고, 보여야 합니다.
<details /> 요소의 open
속성이 설정되어 있습니다.
Copy < 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 >
Copy 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()
요소가 다른 요소를 포함하는 지 여부를 검사합니다.
Copy < span data-testid = "ancestor" >
< span data-testid = "descendant" ></ span >
</ span >
Copy 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 요소를 표현하는 문자열을 포함하는 지 여부를 검사합니다.
Copy < span data-testid = "parent" >
< span data-testid = "child" ></ span >
</ span >
Copy expect ( getByTestId ( 'parent' )) .toContainHTML ( '<span data-testid="child"></span>' )
아마도 이 매치를 사용할 필요가 없을 것입니다.
사용자가 브라우저에서 앱을 인식하는 관점에서 테스트를 권장합니다. 그러므로 특정 DOM 구조에 대한 테스트는 수행하지 않는 것이 좋습니다. 사용자가 제어하는 DOM 구조를 확인하는 데 사용해서는 안 됩니다. 대신 toContainElement() 를 사용하세요.
테스트 중인 코드가 외부 소스에서 가져온 HTML을 렌더링하고 해당 HTML 코드가 의도한 대로 사용되었는지 확인하는 경우에 유용할 수 있습니다.
toHaveAttribute()
요소가 특정 속성을 포함하는 지 여부를 검사합니다. expect.stringContaining 또는 expect.stringMatching 을 사용해 속성에 특정 기대 값 또는 부분 일치가 있는지 선택적으로 확인할 수 있습니다.
Copy < button data-testid = "ok-button" type = "submit" disabled >ok</ button >
Copy 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}
설정)
Copy < button data-testid = "delete-button" class = "btn extra btn-danger" >
Delete item
</ button >
< button data-testid = "no-classes" >No Classes</ button >
Copy 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()
요소에 현재 포커스(초점) 이동이 되어 있는 지 여부를 검사합니다.
Copy < div >< input type = "text" data-testid = "element-to-focus" /></ div >
Copy const input = getByTestId ( 'element-to-focus' )
input .focus ()
expect (input) .toHaveFocus ()
input .blur ()
expect (input). not .toHaveFocus ()
toHaveFormValues()
폼에 name
속성이 지정된 폼 컨트롤을 포함하고 있고, 지정된 값을 가지고 있는 지 여부를 검사합니다.
Copy < 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 >
Copy expect ( getByTestId ( 'login-form' )) .toHaveFormValues ({
username : 'jane.doe' ,
rememberMe : true ,
})
toHaveStyle()
요소에 특정 값이 적용 된 특정 CSS 속성이 있는 지 여부를 검사합니다. 요소 중 일부가 아닌, 모든 예상 속성이 적용되는 경우에만 일치합니다.
Copy < button
data-testid = "delete-button"
style = "display: none; background-color: red"
>
Delete item
</ button >
Copy 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' ,
})
계산 된 CSS 스타일 결과 값 반영
문서에서 현재 사용 중인 스타일시트에 정의 된 일부 규칙이 클래스 이름을 통해 요소에 적용되는 규칙에서도 작동합니다. 일반적인 CSS 우선 순위 규칙이 적용됩니다.
toHaveTextContent()
요소에 텍스트 내용이 포함되어 있는 지 여부를 검사합니다. 문자열 인자가 전달되면 요소 내용에 대해 부분 대/소문자를 구분하는 매치가 수행됩니다. 대/소문자를 구분하지 않는 매치를 수행하려면 정규 표현 식을 사용합니다.
Copy < span data-testid = "text-content" >Text Content</ span >
Copy 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()
폼 컨트롤 요소에 지정 된 값이 있는지 여부를 검사합니다.
Copy < 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 >
Copy 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()
폼 컨트롤 요소에 지정 된 표시 값(사용자에게 보여지는 값)을 포함하는 지 여부를 검사합니다.
Copy <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>
Copy 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) 요소가 체크된 상태인 지 여부를 검사합니다.
Copy <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" />
Copy 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) 요소가 부분적으로 체크되었는 지 여부를 검사합니다.
Copy <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" />
Copy 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 속성에 연결된 요소가 설명 내용을 포함합니다.
Copy <button aria-label="Close" aria-describedby="description-close">X</button>
<!-- 설명 -->
<div id="description-close">Closing will discard any changes</div>
<button>Delete</button>
Copy 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 ( '' ) // 설명이 없거나, 비어 있으면 항상 빈 문자열