Jest DOM 테스트

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