- Notifications
You must be signed in to change notification settings - Fork413
🦉 Custom jest matchers to test the state of the DOM
License
testing-library/jest-dom
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
You want to usejest to write tests that assert various things about thestate of a DOM. As part of that goal, you want to avoid all the repetitivepatterns that arise in doing so. Checking for an element's attributes, its textcontent, its css classes, you name it.
The@testing-library/jest-dom library provides a set of custom jest matchersthat you can use to extend jest. These will make your tests more declarative,clear to read and to maintain.
- Installation
- Usage
- Custom matchers
toBeDisabledtoBeEnabledtoBeEmptyDOMElementtoBeInTheDocumenttoBeInvalidtoBeRequiredtoBeValidtoBeVisibletoContainElementtoContainHTMLtoHaveAccessibleDescriptiontoHaveAccessibleErrorMessagetoHaveAccessibleNametoHaveAttributetoHaveClasstoHaveFocustoHaveFormValuestoHaveStyletoHaveTextContenttoHaveValuetoHaveDisplayValuetoBeCheckedtoBePartiallyCheckedtoHaveRoletoHaveErrorMessagetoBePressedtoBePartiallyPressedtoAppearBeforetoAppearAfter
- Deprecated matchers
- Inspiration
- Other Solutions
- Guiding Principles
- Contributors
- LICENSE
This module is distributed vianpm which is bundled withnode andshould be installed as one of your project'sdevDependencies:
npm install --save-dev @testing-library/jest-domor
for installation withyarn package manager.
yarn add --dev @testing-library/jest-domNote: We also recommend installing the jest-dom eslint plugin which providesauto-fixable lint rules that prevent false positive tests and improve testreadability by ensuring you are using the right matchers in your tests. Moredetails can be found ateslint-plugin-jest-dom.
Import@testing-library/jest-dom once (for instance in yourtests setupfile) and you're good to go:
// In your own jest-setup.js (or any other name)import'@testing-library/jest-dom'// In jest.config.js add (if you haven't already)setupFilesAfterEnv:['<rootDir>/jest-setup.js']
If you are using@jest/globals withinjectGlobals: false, you will need to use a differentimport in your tests setup file:
// In your own jest-setup.js (or any other name)import'@testing-library/jest-dom/jest-globals'
If you are usingvitest, this module will work as-is, but you will need touse a different import in your tests setup file. This file should be added tothesetupFiles property in your vitest config:
// In your own vitest-setup.js (or any other name)import'@testing-library/jest-dom/vitest'// In vitest.config.js add (if you haven't already)setupFiles:['./vitest-setup.js']
Also, depending on your local setup, you may need to update yourtsconfig.json:
// In tsconfig.json"compilerOptions": {..."types": ["vitest/globals","@testing-library/jest-dom"] },"include": [..."./vitest-setup.ts" ],
If you're using TypeScript, make sure your setup file is a.ts and not a.jsto include the necessary types.
You will also need to include your setup file in yourtsconfig.json if youhaven't already:
// In tsconfig.json"include": [..."./jest-setup.ts" ],
If you are using a different test runner that is compatible with Jest'sexpectinterface, it might be possible to use it with this library:
import*asmatchersfrom'@testing-library/jest-dom/matchers'import{expect}from'my-test-runner/expect'expect.extend(matchers)
@testing-library/jest-dom can work with any library or framework that returnsDOM elements from queries. The custom matcher examples below are written usingmatchers from@testing-library's suite of libraries (e.g.getByTestId,queryByTestId,getByText, etc.)
toBeDisabled()
This allows you to check whether an element is disabled from the user'sperspective. According to the specification, the following elements can bedisabled:button,input,select,textarea,optgroup,option,fieldset, andcustom elements.
This custom matcher considers an element as disabled if the element is among thetypes of elements that can be disabled (listed above), and thedisabledattribute is present. It will also consider the element as disabled if it'sinside a parent form element that supports being disabled and has thedisabledattribute present.
<buttondata-testid="button"type="submit"disabled>submit</button><fieldsetdisabled><inputtype="text"data-testid="input"/></fieldset><ahref="..."disabled>link</a>
expect(getByTestId('button')).toBeDisabled()expect(getByTestId('input')).toBeDisabled()expect(getByText('link')).not.toBeDisabled()
This custom matcher does not take into account the presence or absence of the
aria-disabledattribute. For more on why this is the case, check#144.
toBeEnabled()
This allows you to check whether an element is not disabled from the user'sperspective.
It works likenot.toBeDisabled(). Use this matcher to avoid double negation inyour tests.
This custom matcher does not take into account the presence or absence of the
aria-disabledattribute. For more on why this is the case, check#144.
toBeEmptyDOMElement()
This allows you to assert whether an element has no visible content for theuser. It ignores comments but will fail if the element contains white-space.
<spandata-testid="not-empty"><spandata-testid="empty"></span></span><spandata-testid="with-whitespace"></span><spandata-testid="with-comment"><!-- comment --></span>
expect(getByTestId('empty')).toBeEmptyDOMElement()expect(getByTestId('not-empty')).not.toBeEmptyDOMElement()expect(getByTestId('with-whitespace')).not.toBeEmptyDOMElement()
toBeInTheDocument()
This allows you to assert whether an element is present in the document or not.
<spandata-testid="html-element"><span>Html Element</span></span><svgdata-testid="svg-element"></svg>
expect(getByTestId(document.documentElement,'html-element'),).toBeInTheDocument()expect(getByTestId(document.documentElement,'svg-element')).toBeInTheDocument()expect(queryByTestId(document.documentElement,'does-not-exist'),).not.toBeInTheDocument()
Note: This matcher does not find detached elements. The element must be addedto the document to be found by toBeInTheDocument. If you desire to search in adetached element please use:
toContainElement
toBeInvalid()
This allows you to check if an element, is currently invalid.
An element is invalid if it has anaria-invalid attributewith no value or a value of"true", or if the result ofcheckValidity()isfalse.
<inputdata-testid="no-aria-invalid"/><inputdata-testid="aria-invalid"aria-invalid/><inputdata-testid="aria-invalid-value"aria-invalid="true"/><inputdata-testid="aria-invalid-false"aria-invalid="false"/><formdata-testid="valid-form"><input/></form><formdata-testid="invalid-form"><inputrequired/></form>
expect(getByTestId('no-aria-invalid')).not.toBeInvalid()expect(getByTestId('aria-invalid')).toBeInvalid()expect(getByTestId('aria-invalid-value')).toBeInvalid()expect(getByTestId('aria-invalid-false')).not.toBeInvalid()expect(getByTestId('valid-form')).not.toBeInvalid()expect(getByTestId('invalid-form')).toBeInvalid()
toBeRequired()
This allows you to check if a form element is currently required.
An element is required if it is having arequired oraria-required="true"attribute.
<inputdata-testid="required-input"required/><inputdata-testid="aria-required-input"aria-required="true"/><inputdata-testid="conflicted-input"requiredaria-required="false"/><inputdata-testid="aria-not-required-input"aria-required="false"/><inputdata-testid="optional-input"/><inputdata-testid="unsupported-type"type="image"required/><selectdata-testid="select"required></select><textareadata-testid="textarea"required></textarea><divdata-testid="supported-role"role="tree"required></div><divdata-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()
This allows you to check if the value of an element, is currently valid.
An element is valid if it has noaria-invalid attributesor an attribute value of"false". The result ofcheckValidity()must also betrue if it's a form element.
<inputdata-testid="no-aria-invalid"/><inputdata-testid="aria-invalid"aria-invalid/><inputdata-testid="aria-invalid-value"aria-invalid="true"/><inputdata-testid="aria-invalid-false"aria-invalid="false"/><formdata-testid="valid-form"><input/></form><formdata-testid="invalid-form"><inputrequired/></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()
This allows you to check if an element is currently visible to the user.
An element is visible ifall the following conditions are met:
- it is present in the document
- it does not have its css property
displayset tonone - it does not have its css property
visibilityset to eitherhiddenorcollapse - it does not have its css property
opacityset to0 - its parent element is also visible (and so on up to the top of the DOM tree)
- it does not have the
hiddenattribute - if
<details />it has theopenattribute
<divdata-testid="zero-opacity"style="opacity: 0">Zero Opacity Example</div><divdata-testid="visibility-hidden"style="visibility: hidden"> Visibility Hidden Example</div><divdata-testid="display-none"style="display: none">Display None Example</div><divstyle="opacity: 0"><spandata-testid="hidden-parent">Hidden Parent Example</span></div><divdata-testid="visible">Visible Example</div><divdata-testid="hidden-attribute"hidden>Hidden Attribute Example</div><details><summary>Title of hidden text</summary> Hidden Details Example</details><detailsopen><summary>Title of visible text</summary><div>Visible Details Example</div></details>
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()expect(getByText('Hidden Details Example')).not.toBeVisible()expect(getByText('Visible Details Example')).toBeVisible()
toContainElement(element:HTMLElement|SVGElement|null)
This allows you to assert whether an element contains another element as adescendant or not.
<spandata-testid="ancestor"><spandata-testid="descendant"></span></span>
constancestor=getByTestId('ancestor')constdescendant=getByTestId('descendant')constnonExistantElement=getByTestId('does-not-exist')expect(ancestor).toContainElement(descendant)expect(descendant).not.toContainElement(ancestor)expect(ancestor).not.toContainElement(nonExistantElement)
toContainHTML(htmlText: string)
Assert whether a string representing a HTML element is contained in anotherelement. The string should contain valid html, and not any incomplete html.
<spandata-testid="parent"><spandata-testid="child"></span></span>
// These are valid usesexpect(getByTestId('parent')).toContainHTML('<span data-testid="child"></span>')expect(getByTestId('parent')).toContainHTML('<span data-testid="child" />')expect(getByTestId('parent')).not.toContainHTML('<br />')// These won't workexpect(getByTestId('parent')).toContainHTML('data-testid="child"')expect(getByTestId('parent')).toContainHTML('data-testid')expect(getByTestId('parent')).toContainHTML('</span>')
Chances are you probably do not need to use this matcher. We encourage testingfrom the perspective of how the user perceives the app in a browser. That'swhy testing against a specific DOM structure is not advised.
It could be useful in situations where the code being tested renders html thatwas obtained from an external source, and you want to validate that that htmlcode was used as intended.
It should not be used to check DOM structure that you control. Please use
toContainElementinstead.
toHaveAccessibleDescription(expectedAccessibleDescription?: string|RegExp)
This allows you to assert that an element has the expectedaccessible description.
You can pass the exact string of the expected accessible description, or you canmake a partial match passing a regular expression, or by usingexpect.stringContaining/expect.stringMatching.
<adata-testid="link"href="/"aria-label="Home page"title="A link to start over">Start</a><adata-testid="extra-link"href="/about"aria-label="About page">About</a><imgsrc="avatar.jpg"data-testid="avatar"alt="User profile pic"/><imgsrc="logo.jpg"data-testid="logo"alt="Company logo"aria-describedby="t1"/><spanid="t1"role="presentation">The logo of Our Company</span><imgsrc="logo.jpg"data-testid="logo2"alt="Company logo"aria-description="The logo of Our Company"/>
expect(getByTestId('link')).toHaveAccessibleDescription()expect(getByTestId('link')).toHaveAccessibleDescription('A link to start over')expect(getByTestId('link')).not.toHaveAccessibleDescription('Home page')expect(getByTestId('extra-link')).not.toHaveAccessibleDescription()expect(getByTestId('avatar')).not.toHaveAccessibleDescription()expect(getByTestId('logo')).not.toHaveAccessibleDescription('Company logo')expect(getByTestId('logo')).toHaveAccessibleDescription('The logo of Our Company',)expect(getByTestId('logo2')).toHaveAccessibleDescription('The logo of Our Company',)
toHaveAccessibleErrorMessage(expectedAccessibleErrorMessage?: string|RegExp)
This allows you to assert that an element has the expectedaccessible error message.
You can pass the exact string of the expected accessible error message.Alternatively, you can perform a partial match by passing a regular expressionor by usingexpect.stringContaining/expect.stringMatching.
<inputaria-label="Has Error"aria-invalid="true"aria-errormessage="error-message"/><divid="error-message"role="alert">This field is invalid</div><inputaria-label="No Error Attributes"/><inputaria-label="Not Invalid"aria-invalid="false"aria-errormessage="error-message"/>
// Inputs with Valid Error Messagesexpect(getByRole('textbox',{name:'Has Error'})).toHaveAccessibleErrorMessage()expect(getByRole('textbox',{name:'Has Error'})).toHaveAccessibleErrorMessage('This field is invalid',)expect(getByRole('textbox',{name:'Has Error'})).toHaveAccessibleErrorMessage(/invalid/i,)expect(getByRole('textbox',{name:'Has Error'}),).not.toHaveAccessibleErrorMessage('This field is absolutely correct!')// Inputs without Valid Error Messagesexpect(getByRole('textbox',{name:'No Error Attributes'}),).not.toHaveAccessibleErrorMessage()expect(getByRole('textbox',{name:'Not Invalid'}),).not.toHaveAccessibleErrorMessage()
toHaveAccessibleName(expectedAccessibleName?: string|RegExp)
This allows you to assert that an element has the expectedaccessible name. It is useful, for instance,to assert that form elements and buttons are properly labelled.
You can pass the exact string of the expected accessible name, or you can make apartial match passing a regular expression, or by usingexpect.stringContaining/expect.stringMatching.
<imgdata-testid="img-alt"src=""alt="Test alt"/><imgdata-testid="img-empty-alt"src=""alt=""/><svgdata-testid="svg-title"><title>Test title</title></svg><buttondata-testid="button-img-alt"><imgsrc=""alt="Test"/></button><p><imgdata-testid="img-paragraph"src=""alt=""/> Test content</p><buttondata-testid="svg-button"><svg><title>Test</title></svg></p><div><svgdata-testid="svg-without-title"></svg></div><inputdata-testid="input-title"title="test"/>
expect(getByTestId('img-alt')).toHaveAccessibleName('Test alt')expect(getByTestId('img-empty-alt')).not.toHaveAccessibleName()expect(getByTestId('svg-title')).toHaveAccessibleName('Test title')expect(getByTestId('button-img-alt')).toHaveAccessibleName()expect(getByTestId('img-paragraph')).not.toHaveAccessibleName()expect(getByTestId('svg-button')).toHaveAccessibleName()expect(getByTestId('svg-without-title')).not.toHaveAccessibleName()expect(getByTestId('input-title')).toHaveAccessibleName()
toHaveAttribute(attr:string,value?: any)
This allows you to check whether the given element has an attribute or not. Youcan also optionally check that the attribute has a specific expected value orpartial match usingexpect.stringContaining/expect.stringMatching
<buttondata-testid="ok-button"type="submit"disabled>ok</button>
constbutton=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(...classNames: string[],options?:{exact:boolean})
This allows you to check whether the given element has certain classes withinitsclass attribute. You must provide at least one class, unless you areasserting that an element does not have any classes.
The list of class names may include strings and regular expressions. Regularexpressions are matched against each individual class in the target element, andit is NOT matched against its fullclass attribute value as whole.
<buttondata-testid="delete-button"class="btn extra btn-danger"> Delete item</button><buttondata-testid="no-classes">No Classes</button>
constdeleteButton=getByTestId('delete-button')constnoClasses=getByTestId('no-classes')expect(deleteButton).toHaveClass('extra')expect(deleteButton).toHaveClass('btn-danger btn')expect(deleteButton).toHaveClass(/danger/,'btn')expect(deleteButton).toHaveClass('btn-danger','btn')expect(deleteButton).not.toHaveClass('btn-link')expect(deleteButton).not.toHaveClass(/link/)expect(deleteButton).not.toHaveClass(/btnextra/)// It does not matchexpect(deleteButton).toHaveClass('btn-danger extra btn',{exact:true})// to check if the element has EXACTLY a set of classesexpect(deleteButton).not.toHaveClass('btn-danger extra',{exact:true})// if it has more than expected it is going to failexpect(noClasses).not.toHaveClass()
toHaveFocus()
This allows you to assert whether an element has focus or not.
<div><inputtype="text"data-testid="element-to-focus"/></div>
constinput=getByTestId('element-to-focus')input.focus()expect(input).toHaveFocus()input.blur()expect(input).not.toHaveFocus()
toHaveFormValues(expectedValues:{[name:string]: any})
This allows you to check if a form or fieldset contains form controls for eachgiven name, and having the specified value.
It is important to stress that this matcher can only be invoked on aformor afieldset element.
This allows it to take advantage of the.elements property in
formandfieldsetto reliably fetch all form controls within them.This also avoids the possibility that users provide a container that containsmore than one
form, thereby intermixing form controls that are not related,and could even conflict with one another.
This matcher abstracts away the particularities with which a form control valueis obtained depending on the type of form control. For instance,<input>elements have avalue attribute, but<select> elements do not. Here's a listof all cases covered:
<input type="number">elements return the value as anumber, instead ofa string.<input type="checkbox">elements:- if there's a single one with the given
nameattribute, it is treated as aboolean, returningtrueif the checkbox is checked,falseifunchecked. - if there's more than one checkbox with the same
nameattribute, they areall treated collectively as a single form control, which returns the valueas anarray containing all the values of the selected checkboxes in thecollection.
- if there's a single one with the given
<input type="radio">elements are all grouped by thenameattribute, andsuch a group treated as a single form control. This form control returns thevalue as astring corresponding to thevalueattribute of the selectedradio button within the group.<input type="text">elements return the value as astring. This alsoapplies to<input>elements having any other possibletypeattributethat's not explicitly covered in different rules above (e.g.search,email,date,password,hidden, etc.)<select>elements without themultipleattribute return the value as astring corresponding to thevalueattribute of the selectedoption, orundefinedif there's no selected option.<select multiple>elements return the value as anarray containing allthe values of theselected options.<textarea>elements return their value as astring. The valuecorresponds to their node content.
The above rules make it easy, for instance, to switch from using a single selectcontrol to using a group of radio buttons. Or to switch from a multi selectcontrol, to using a group of checkboxes. The resulting set of form values usedby this matcher to compare against would be the same.
<formdata-testid="login-form"><inputtype="text"name="username"value="jane.doe"/><inputtype="password"name="password"value="12345678"/><inputtype="checkbox"name="rememberMe"checked/><buttontype="submit">Sign in</button></form>
expect(getByTestId('login-form')).toHaveFormValues({username:'jane.doe',rememberMe:true,})
toHaveStyle(css:string|object)
This allows you to check if a certain element has some specific css propertieswith specific values applied. It matches only if the element hasall theexpected properties applied, not just some of them.
<buttondata-testid="delete-button"style="display: none; background-color: red"> Delete item</button>
constbutton=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',})
This also works with rules that are applied to the element via a class name forwhich some rules are defined in a stylesheet currently active in the document.The usual rules of css precedence apply.
toHaveTextContent(text:string|RegExp,options?:{normalizeWhitespace:boolean})
This allows you to check whether the given node has a text content or not. Thissupports elements, but also text nodes and fragments.
When astring argument is passed through, it will perform a partialcase-sensitive match to the node content.
To perform a case-insensitive match, you can use aRegExp with the/imodifier.
If you want to match the whole content, you can use aRegExp to do it.
<spandata-testid="text-content">Text Content</span>
constelement=getByTestId('text-content')expect(element).toHaveTextContent('Content')expect(element).toHaveTextContent(/^TextContent$/)// to match the whole contentexpect(element).toHaveTextContent(/content$/i)// to use case-insensitive matchexpect(element).not.toHaveTextContent('content')
toHaveValue(value:string|string[]|number)
This allows you to check whether the given form element has the specified value.It accepts<input>,<select> and<textarea> elements with the exception of<input type="checkbox"> and<input type="radio">, which can be meaningfullymatched only usingtoBeChecked ortoHaveFormValues.
It also accepts elements with rolesmeter,progressbar,slider orspinbutton and checks theiraria-valuenow attribute (as a number).
For all other form elements, the value is matched using the same algorithm as intoHaveFormValues does.
<inputtype="text"value="text"data-testid="input-text"/><inputtype="number"value="5"data-testid="input-number"/><inputtype="text"data-testid="input-empty"/><selectmultipledata-testid="select-number"><optionvalue="first">First Value</option><optionvalue="second"selected>Second Value</option><optionvalue="third"selected>Third Value</option></select>
consttextInput=getByTestId('input-text')constnumberInput=getByTestId('input-number')constemptyInput=getByTestId('input-empty')constselectInput=getByTestId('select-number')expect(textInput).toHaveValue('text')expect(numberInput).toHaveValue(5)expect(emptyInput).not.toHaveValue()expect(selectInput).toHaveValue(['second','third'])
toHaveDisplayValue(value:string|RegExp|(string|RegExp)[])
This allows you to check whether the given form element has the specifieddisplayed value (the one the end user will see). It accepts<input>,<select> and<textarea> elements with the exception of<input type="checkbox"> and<input type="radio">, which can be meaningfullymatched only usingtoBeChecked ortoHaveFormValues.
<labelfor="input-example">First name</label><inputtype="text"id="input-example"value="Luca"/><labelfor="textarea-example">Description</label><textareaid="textarea-example">An example description here.</textarea><labelfor="single-select-example">Fruit</label><selectid="single-select-example"><optionvalue="">Select a fruit...</option><optionvalue="banana">Banana</option><optionvalue="ananas">Ananas</option><optionvalue="avocado">Avocado</option></select><labelfor="multiple-select-example">Fruits</label><selectid="multiple-select-example"multiple><optionvalue="">Select a fruit...</option><optionvalue="banana"selected>Banana</option><optionvalue="ananas">Ananas</option><optionvalue="avocado"selected>Avocado</option></select>
constinput=screen.getByLabelText('First name')consttextarea=screen.getByLabelText('Description')constselectSingle=screen.getByLabelText('Fruit')constselectMultiple=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()
This allows you to check whether the given element is checked. It accepts aninput of typecheckbox orradio and elements with arole ofcheckbox,radio orswitch with a validaria-checked attribute of"true" or"false".
<inputtype="checkbox"checkeddata-testid="input-checkbox-checked"/><inputtype="checkbox"data-testid="input-checkbox-unchecked"/><divrole="checkbox"aria-checked="true"data-testid="aria-checkbox-checked"/><divrole="checkbox"aria-checked="false"data-testid="aria-checkbox-unchecked"/><inputtype="radio"checkedvalue="foo"data-testid="input-radio-checked"/><inputtype="radio"value="foo"data-testid="input-radio-unchecked"/><divrole="radio"aria-checked="true"data-testid="aria-radio-checked"/><divrole="radio"aria-checked="false"data-testid="aria-radio-unchecked"/><divrole="switch"aria-checked="true"data-testid="aria-switch-checked"/><divrole="switch"aria-checked="false"data-testid="aria-switch-unchecked"/>
constinputCheckboxChecked=getByTestId('input-checkbox-checked')constinputCheckboxUnchecked=getByTestId('input-checkbox-unchecked')constariaCheckboxChecked=getByTestId('aria-checkbox-checked')constariaCheckboxUnchecked=getByTestId('aria-checkbox-unchecked')expect(inputCheckboxChecked).toBeChecked()expect(inputCheckboxUnchecked).not.toBeChecked()expect(ariaCheckboxChecked).toBeChecked()expect(ariaCheckboxUnchecked).not.toBeChecked()constinputRadioChecked=getByTestId('input-radio-checked')constinputRadioUnchecked=getByTestId('input-radio-unchecked')constariaRadioChecked=getByTestId('aria-radio-checked')constariaRadioUnchecked=getByTestId('aria-radio-unchecked')expect(inputRadioChecked).toBeChecked()expect(inputRadioUnchecked).not.toBeChecked()expect(ariaRadioChecked).toBeChecked()expect(ariaRadioUnchecked).not.toBeChecked()constariaSwitchChecked=getByTestId('aria-switch-checked')constariaSwitchUnchecked=getByTestId('aria-switch-unchecked')expect(ariaSwitchChecked).toBeChecked()expect(ariaSwitchUnchecked).not.toBeChecked()
toBePartiallyChecked()
This allows you to check whether the given element is partially checked. Itaccepts aninput of typecheckbox and elements with arole ofcheckboxwith aaria-checked="mixed", orinput of typecheckbox withindeterminate set totrue
<inputtype="checkbox"aria-checked="mixed"data-testid="aria-checkbox-mixed"/><inputtype="checkbox"checkeddata-testid="input-checkbox-checked"/><inputtype="checkbox"data-testid="input-checkbox-unchecked"/><divrole="checkbox"aria-checked="true"data-testid="aria-checkbox-checked"/><divrole="checkbox"aria-checked="false"data-testid="aria-checkbox-unchecked"/><inputtype="checkbox"data-testid="input-checkbox-indeterminate"/>
constariaCheckboxMixed=getByTestId('aria-checkbox-mixed')constinputCheckboxChecked=getByTestId('input-checkbox-checked')constinputCheckboxUnchecked=getByTestId('input-checkbox-unchecked')constariaCheckboxChecked=getByTestId('aria-checkbox-checked')constariaCheckboxUnchecked=getByTestId('aria-checkbox-unchecked')constinputCheckboxIndeterminate=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=trueexpect(inputCheckboxIndeterminate).toBePartiallyChecked()
This allows you to assert that an element has the expectedrole.
This is useful in cases where you already have access to an element via somequery other than the role itself, and want to make additional assertionsregarding its accessibility.
The role can match either an explicit role (via therole attribute), or animplicit one via theimplicit ARIA semantics.
Note: roles are matched literally by string equality, without inheriting fromthe ARIA role hierarchy. As a result, querying a superclass role like 'checkbox'will not include elements with a subclass role like 'switch'.
toHaveRole(expectedRole: string)
<buttondata-testid="button">Continue</button><divrole="button"data-testid="button-explicit">Continue</button><buttonrole="switch button"data-testid="button-explicit-multiple">Continue</button><ahref="/about"data-testid="link">About</a><adata-testid="link-invalid">Invalid link<a/>
expect(getByTestId('button')).toHaveRole('button')expect(getByTestId('button-explicit')).toHaveRole('button')expect(getByTestId('button-explicit-multiple')).toHaveRole('button')expect(getByTestId('button-explicit-multiple')).toHaveRole('switch')expect(getByTestId('link')).toHaveRole('link')expect(getByTestId('link-invalid')).not.toHaveRole('link')expect(getByTestId('link-invalid')).toHaveRole('generic')
This custom matcher is deprecated. Prefer
toHaveAccessibleErrorMessageinstead, whichis more comprehensive in implementing the official spec.
toHaveErrorMessage(text:string|RegExp)
This allows you to check whether the given element has anARIA error message or not.
Use thearia-errormessage attribute to reference another element that containscustom error message text. Multiple ids isNOT allowed. Authors MUST usearia-invalid in conjunction witharia-errormessage. Learn more fromaria-errormessage spec.
Whitespace is normalized.
When astring argument is passed through, it will perform a wholecase-sensitive match to the error message text.
To perform a case-insensitive match, you can use aRegExp with the/imodifier.
To perform a partial match, you can pass aRegExp or useexpect.stringContaining("partial string").
<labelfor="startTime"> Please enter a start time for the meeting:</label><inputid="startTime"type="text"aria-errormessage="msgID"aria-invalid="true"value="11:30 PM"/><spanid="msgID"aria-live="assertive"style="visibility:visible"> Invalid time: the time must be between 9:00 AM and 5:00 PM</span>
consttimeInput=getByLabel('startTime')expect(timeInput).toHaveErrorMessage('Invalid time: the time must be between 9:00 AM and 5:00 PM',)expect(timeInput).toHaveErrorMessage(/invalidtime/i)// to partially matchexpect(timeInput).toHaveErrorMessage(expect.stringContaining('Invalid time'))// to partially matchexpect(timeInput).not.toHaveErrorMessage('Pikachu!')
This allows to check whether given element ispressed.
It accepts elements with explicit or implicitbutton role and validaria-pressed attribute of"true" or"false".
toBePressed()
<buttonaria-pressed="true">Pressed</button><buttonaria-pressed="false">Released</button><inputtype="button"aria-pressed="true"value="Pressed input button"/><inputtype="button"aria-pressed="false"value="Released input button"/><spanrole="button"aria-pressed="true">Pressed span</span><spanrole="button"aria-pressed="false">Released span</span>
screen.getByRole('button',{name:'Pressed'}).toBePressed()screen.getByRole('button',{name:'Released'}).not.toBePressed()screen.getByRole('button',{name:'Pressed input button'}).toBePressed()screen.getByRole('button',{name:'Released input button'}).not.toBePressed()screen.getByRole('button',{name:'Pressed span'}).toBePressed()screen.getByRole('button',{name:'Released span'}).not.toBePressed()
This allows to check whether given element is partiallypressed.
It accepts elements with explicit or implicitbutton role and validaria-pressed attribute ofmixed.
toBePressed()
<buttonaria-pressed="mixed">Partially pressed</button><inputtype="button"aria-pressed="mixed"value="Partially pressed input button"/><spanrole="button"aria-pressed="mixed">Partially pressed span</span>
screen.getByRole('button',{name:'Partially pressed'}).toBePartiallyPressed()screen.getByRole('button',{name:'Partially pressed input button'}).toBePartiallyPressed()screen.getByRole('button',{name:'Partially pressed span'}).toBePartiallyPressed()
This checks if a given element appears before another element in the DOM tree,as percompareDocumentPosition().
toAppearBefore()
<div><spandata-testid="text-a">Text A</span><spandata-testid="text-b">Text B</span></div>
consttextA=queryByTestId('text-a')consttextB=queryByTestId('text-b')expect(textA).toAppearBefore(textB)expect(textB).not.toAppearBefore(textA)
Note: This matcher does not take into account CSS styles that may modify thedisplay order of elements, eg:
flex-direction: row-reverse,flex-direction: column-reverse,display: grid
This checks if a given element appears after another element in the DOM tree, aspercompareDocumentPosition().
toAppearAfter()
<div><spandata-testid="text-a">Text A</span><spandata-testid="text-b">Text B</span></div>
consttextA=queryByTestId('text-a')consttextB=queryByTestId('text-b')expect(textB).toAppearAfter(textA)expect(textA).not.toAppearAfter(textB)
Note: This matcher does not take into account CSS styles that may modify thedisplay order of elements, see
toAppearBefore()
Note: This matcher is being deprecated due to a name clash with
jest-extended. See more info in #216. In the future, please use onlytoBeEmptyDOMElement
toBeEmpty()
This allows you to assert whether an element has content or not.
<spandata-testid="not-empty"><spandata-testid="empty"></span></span>
expect(getByTestId('empty')).toBeEmpty()expect(getByTestId('not-empty')).not.toBeEmpty()
This custom matcher is deprecated. Prefer
toBeInTheDocumentinstead.
toBeInTheDOM()
This allows you to check whether a value is a DOM element, or not.
Contrary to what its name implies, this matcher only checks that you passed toit a valid DOM element. It does not have a clear definition of what "the DOM"is. Therefore, it does not check whether that element is contained anywhere.
This is the main reason why this matcher is deprecated, and will be removed inthe next major release. You can follow the discussion around this decision inmore detailhere.
As an alternative, you can usetoBeInTheDocument ortoContainElement. Or if you just want to check if a valueis indeed anHTMLElement you can always use some ofjest's built-in matchers:
expect(document.querySelector('.ok-button')).toBeInstanceOf(HTMLElement)expect(document.querySelector('.cancel-button')).toBeTruthy()
Note: The differences between
toBeInTheDOMandtoBeInTheDocumentaresignificant. Replacing all uses oftoBeInTheDOMwithtoBeInTheDocumentwill likely cause unintended consequences in your tests. Please make sure whenreplacingtoBeInTheDOMto read through the documentation of the proposedalternatives to see which use case works better for your needs.
This custom matcher is deprecated. Prefer
toHaveAccessibleDescriptioninstead, whichis more comprehensive in implementing the official spec.
toHaveDescription(text:string|RegExp)
This allows you to check whether the given element has a description or not.
An element gets its description via thearia-describedby attribute.Set this to theid of one or more other elements. These elements may be nestedinside, be outside, or a sibling of the passed in element.
Whitespace is normalized. Using multiple ids willjoin the referenced elements’ text content separated by a space.
When astring argument is passed through, it will perform a wholecase-sensitive match to the description text.
To perform a case-insensitive match, you can use aRegExp with the/imodifier.
To perform a partial match, you can pass aRegExp or useexpect.stringContaining("partial string").
<buttonaria-label="Close"aria-describedby="description-close">X</button><divid="description-close">Closing will discard any changes</div><button>Delete</button>
constcloseButton=getByRole('button',{name:'Close'})expect(closeButton).toHaveDescription('Closing will discard any changes')expect(closeButton).toHaveDescription(/willdiscard/)// to partially matchexpect(closeButton).toHaveDescription(expect.stringContaining('will discard'))// to partially matchexpect(closeButton).toHaveDescription(/^closing/i)// to use case-insensitive matchexpect(closeButton).not.toHaveDescription('Other description')constdeleteButton=getByRole('button',{name:'Delete'})expect(deleteButton).not.toHaveDescription()expect(deleteButton).toHaveDescription('')// Missing or empty description always becomes a blank string
This allows to assert that an element has atext selection.
This is useful to check if text or part of the text is selected within anelement. The element can be either an input of type text, a textarea, or anyother element that contains text, such as a paragraph, span, div etc.
NOTE: the expected selection is a string, it does not allow to check forselection range indeces.
toHaveSelection(expectedSelection?: string)
<div><inputtype="text"value="text selected text"data-testid="text"/><textareadata-testid="textarea">text selected text</textarea><pdata-testid="prev">prev</p><pdata-testid="parent"> text<spandata-testid="child">selected</span> text</p><pdata-testid="next">next</p></div>
getByTestId('text').setSelectionRange(5,13)expect(getByTestId('text')).toHaveSelection('selected')getByTestId('textarea').setSelectionRange(0,5)expect('textarea').toHaveSelection('text ')constselection=document.getSelection()constrange=document.createRange()selection.removeAllRanges()selection.empty()selection.addRange(range)// selection of child applies to the parent as wellrange.selectNodeContents(getByTestId('child'))expect(getByTestId('child')).toHaveSelection('selected')expect(getByTestId('parent')).toHaveSelection('selected')// selection that applies from prev all, parent text before child, and part child.range.setStart(getByTestId('prev'),0)range.setEnd(getByTestId('child').childNodes[0],3)expect(queryByTestId('prev')).toHaveSelection('prev')expect(queryByTestId('child')).toHaveSelection('sel')expect(queryByTestId('parent')).toHaveSelection('text sel')expect(queryByTestId('next')).not.toHaveSelection()// selection that applies from part child, parent text after child and part next.range.setStart(getByTestId('child').childNodes[0],3)range.setEnd(getByTestId('next').childNodes[0],2)expect(queryByTestId('child')).toHaveSelection('ected')expect(queryByTestId('parent')).toHaveSelection('ected text')expect(queryByTestId('prev')).not.toHaveSelection()expect(queryByTestId('next')).toHaveSelection('ne')
This whole library was extracted out of Kent C. Dodds'DOM TestingLibrary, which was in turn extracted out ofReact TestingLibrary.
The intention is to make this available to be used independently of these otherlibraries, and also to make it more clear that these other libraries areindependent from jest, and can be used with other tests runners as well.
I'm not aware of any, if you are pleasemake a pull request and add ithere!
If you would like to further test the accessibility and validity of the DOMconsiderjest-axe. It doesn'toverlap withjest-dom but can complement it for more in-depth accessibilitychecking (eg: validatingaria attributes or ensuring unique id attributes).
The more your tests resemble the way your software is used, the moreconfidence they can give you.
This library follows the same guiding principles as its mother libraryDOMTesting Library. Gocheck them outfor more details.
Additionally, with respect to custom DOM matchers, this library aims to maintaina minimal but useful set of them, while avoiding bloating itself with merelyconvenient ones that can be easily achieved with other APIs. In general, theoverall criteria for what is considered a useful custom matcher to add to thislibrary, is that doing the equivalent assertion on our own makes the test codemore verbose, less clear in its intent, and/or harder to read.
Thanks goes to these people (emoji key):
This project follows theall-contributors specification.Contributions of any kind welcome!
MIT
About
🦉 Custom jest matchers to test the state of the DOM
Topics
Resources
License
Code of conduct
Contributing
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Uh oh!
There was an error while loading.Please reload this page.
