A simple test example
1
2
3
4
5
6
7
8
9
10
11import React from 'react'
import {FavoriteNumber} from '../favorite-number'
import ReactDOM from 'react-dom'
test('renders a number input with a label "Favorite Number"', () => {
const div = document.createElement('div')
ReactDOM.render(<FavoriteNumber />, div)
console.log(div.innerHTML) //You can use console.log to see the results in the terminal.
expect(div.querySelector('input').type).toBe('number')
expect(div.querySelector('label').textContent).toBe('Favorite Number'))
})The result can be seen in the terminal.
expect(div.querySelector('label').textContent).toBe('Favorite Number'))
can be reversed to verify that the false output passes the test. If the result is fail, assertions run normally.
Using Jest DOM to boost assertions
In the previous method, the error message is not helpful. For example, if the input is wrong in
div.querySelector('input')
, an errorTypeError: Cannot read property 'type' of null
will be reported, and it will be marked indiv
on.We use testing-library/jest-dom to solve this problem.
It has many methods, such as
{toHaveAttribute, toHaveTextContent}
. To simplify this code, such asexpect.extend(jestDom)
, useimport '@testing-library/jest-dom/extend-expect'
to import the package. Or you can automatically import this package in jest.setup.js for all files.
The modified assertion is:
1
2
3
4
5
6
7
8import '@testing-library/jest-dom/extend-expect'
test('renders a number input with a label "Favorite Number"', () => {
const div = document.createElement('div')
ReactDOM.render(<FavoriteNumber />, div)
expect(div.querySelector('input')).toHaveAttribute('type','number')
expect(div.querySelector('label')).toHaveTextContent('Favorite Number')
})At this time, if the input is written incorrectly, the error will become:
1
2expect(received).toHaveAttribute()
received value must be an HTMLElement or an SVGElement. Received has value: nullAt this point it is easier to understand and fix.
Use assertions to ensure label and element match exactly
If there is no match, if the value of htmlFor in label is modified, the test can still pass. But there will be an error when the screen reader reads it. We can use an assertion to get the element corresponding to the label.
1
2
3
4
5
6
7
8
9import {queries} from '@testing-library/dom' // can be done in the configuration file
test('renders a number input with a label "Favorite Number"', () => {
const div = document.createElement('div')
ReactDOM.render(<FavoriteNumber />, div)
const input = queries.getByLabelText(div, 'Favorite Number')
expect(input).toHaveAttribute('type','number') //Simplified because of the previous line
//The next line is deleted because of duplication
})queries.getByLabelText(div, 'Favorite Number')
will cause the DOM testing library to search all children of this div for a label containing this text. At the same time, the previousdiv.querySelector('label')
can also be deleted, because its content is already contained inqueries.getByLabelText(div, 'Favorite Number')
.
This method is case sensitive. But users of screen reader don’t care about case, so it should be written as:
1
2
3
4
5
6test('renders a number input with a label "Favorite Number"', () => {
const div = document.createElement('div')
ReactDOM.render(<FavoriteNumber />, div)
const input = queries.getByLabelText(div, /Favorite Number/i)
expect(input).toHaveAttribute('type','number')
})This regex ignores case.
Use getQueriesForElement to simplify div fetching
From getQueriesForElement , we can access many other queries from the DOM testing library to find elements in the render DOM.
1
2
3
4
5
6
7
8
9import {queries, getQueriesForElement} from '@testing-library/dom'
test('renders a number input with a label "Favorite Number"', () => {
const div = document.createElement('div')
ReactDOM.render(<FavoriteNumber />, div)
const {getByLabelText} = getQueriesForElement(div)
const input = getByLabelText(/Favorite Number/i)
expect(input).toHaveAttribute('type','number')
})
What’s done here is that the testing library/DOM module is added, and we pull in getQueriesForElement. We get queries for div. Now, getByLabelText is pre-bound to that div, so we can take the text matching regex as a parameter and get the input. Then we can assert on that input that it has a numeric type.